/**
  * @param array $quoteDetailsData
  * @param array $taxDetailsData
  * @param string $calculateCallback Name of a function within this test class which will be executed to create
  *      a tax details item.
  * @return void
  * @dataProvider calculateTaxProvider
  */
 public function testCalculateTax($quoteDetailsData, $taxDetailsData, $calculateCallback = 'createTaxDetailsItem')
 {
     $storeMock = $this->getMockBuilder('Magento\\Store\\Model\\Store')->disableOriginalConstructor()->getMock();
     $this->storeManager->expects($this->any())->method('getStore')->will($this->returnValue($storeMock));
     $calculatorMock = $this->getMockBuilder('\\Magento\\Tax\\Model\\Calculation\\AbstractCalculator')->disableOriginalConstructor()->setMethods(['calculate'])->getMockForAbstractClass();
     $this->calculatorFactory->expects($this->any())->method('create')->will($this->returnValue($calculatorMock));
     $calculatorMock->expects($this->any())->method('calculate')->will($this->returnCallback([$this, $calculateCallback]));
     $quoteDetails = $this->quoteDetailsBuilder->populateWithArray($quoteDetailsData)->create();
     $taxDetails = $this->taxCalculationService->calculateTax($quoteDetails);
     $this->assertEquals($taxDetailsData, $taxDetails->__toArray());
 }
 /**
  * {@inheritdoc}
  */
 public function calculateTax(\Magento\Tax\Api\Data\QuoteDetailsInterface $quoteDetails, $storeId = null, $round = true)
 {
     if ($storeId === null) {
         $storeId = $this->storeManager->getStore()->getStoreId();
     }
     // initial TaxDetails data
     $taxDetailsData = [TaxDetailsInterface::KEY_SUBTOTAL => 0.0, TaxDetailsInterface::KEY_TAX_AMOUNT => 0.0, TaxDetailsInterface::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT => 0.0, TaxDetailsInterface::KEY_APPLIED_TAXES => [], TaxDetailsInterface::KEY_ITEMS => []];
     $items = $quoteDetails->getItems();
     if (empty($items)) {
         return $this->taxDetailsDataObjectFactory->create()->setSubtotal(0.0)->setTaxAmount(0.0)->setDiscountTaxCompensationAmount(0.0)->setAppliedTaxes([])->setItems([]);
     }
     $this->computeRelationships($items);
     $calculator = $this->calculatorFactory->create($this->config->getAlgorithm($storeId), $storeId, $quoteDetails->getBillingAddress(), $quoteDetails->getShippingAddress(), $this->taxClassManagement->getTaxClassId($quoteDetails->getCustomerTaxClassKey(), 'customer'), $quoteDetails->getCustomerId());
     $processedItems = [];
     /** @var QuoteDetailsItemInterface $item */
     foreach ($this->keyedItems as $item) {
         if (isset($this->parentToChildren[$item->getCode()])) {
             $processedChildren = [];
             foreach ($this->parentToChildren[$item->getCode()] as $child) {
                 $processedItem = $this->processItem($child, $calculator, $round);
                 $taxDetailsData = $this->aggregateItemData($taxDetailsData, $processedItem);
                 $processedItems[$processedItem->getCode()] = $processedItem;
                 $processedChildren[] = $processedItem;
             }
             $processedItem = $this->calculateParent($processedChildren, $item->getQuantity());
             $processedItem->setCode($item->getCode());
             $processedItem->setType($item->getType());
         } else {
             $processedItem = $this->processItem($item, $calculator, $round);
             $taxDetailsData = $this->aggregateItemData($taxDetailsData, $processedItem);
         }
         $processedItems[$processedItem->getCode()] = $processedItem;
     }
     $taxDetailsDataObject = $this->taxDetailsDataObjectFactory->create();
     $this->dataObjectHelper->populateWithArray($taxDetailsDataObject, $taxDetailsData, '\\Magento\\Tax\\Api\\Data\\TaxDetailsInterface');
     $taxDetailsDataObject->setItems($processedItems);
     return $taxDetailsDataObject;
 }
 /**
  * {@inheritdoc}
  */
 public function calculateTax(QuoteDetails $quoteDetails, $storeId = null)
 {
     if (is_null($storeId)) {
         $storeId = $this->storeManager->getStore()->getStoreId();
     }
     // initial TaxDetails data
     $taxDetailsData = [TaxDetails::KEY_SUBTOTAL => 0.0, TaxDetails::KEY_TAX_AMOUNT => 0.0, TaxDetails::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT => 0.0, TaxDetails::KEY_APPLIED_TAXES => [], TaxDetails::KEY_ITEMS => []];
     $items = $quoteDetails->getItems();
     if (empty($items)) {
         return $this->taxDetailsBuilder->populateWithArray($taxDetailsData)->create();
     }
     $this->computeRelationships($items);
     $calculator = $this->calculatorFactory->create($this->config->getAlgorithm($storeId), $storeId, $quoteDetails->getBillingAddress(), $quoteDetails->getShippingAddress(), $this->taxClassService->getTaxClassId($quoteDetails->getCustomerTaxClassKey(), 'customer'), $quoteDetails->getCustomerId());
     $processedItems = [];
     /** @var QuoteDetailsItem $item */
     foreach ($this->keyedItems as $item) {
         if (isset($this->parentToChildren[$item->getCode()])) {
             $processedChildren = [];
             foreach ($this->parentToChildren[$item->getCode()] as $child) {
                 $processedItem = $this->processItem($child, $calculator);
                 $taxDetailsData = $this->aggregateItemData($taxDetailsData, $processedItem);
                 $processedItems[$processedItem->getCode()] = $processedItem;
                 $processedChildren[] = $processedItem;
             }
             $processedItemBuilder = $this->calculateParent($processedChildren, $item->getQuantity());
             $processedItemBuilder->setCode($item->getCode());
             $processedItemBuilder->setType($item->getType());
             $processedItem = $processedItemBuilder->create();
         } else {
             $processedItem = $this->processItem($item, $calculator);
             $taxDetailsData = $this->aggregateItemData($taxDetailsData, $processedItem);
         }
         $processedItems[$processedItem->getCode()] = $processedItem;
     }
     return $this->taxDetailsBuilder->populateWithArray($taxDetailsData)->setItems($processedItems)->create();
 }