/** * Tests the specific method * * @param array $itemData * @param array $appliedRatesData * @param array $taxDetailsData * @param array $quoteDetailsData * @param array $addressData * @param array $verifyData * * @dataProvider dataProviderCollectArray * @SuppressWarnings(PHPMD.ExcessiveMethodLength) * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function testCollect($itemData, $appliedRatesData, $taxDetailsData, $quoteDetailsData, $addressData, $verifyData) { $this->markTestIncomplete('Source code is not testable. Need to be refactored before unit testing'); $shippingAssignmentMock = $this->getMock('Magento\\Quote\\Api\\Data\\ShippingAssignmentInterface'); $totalsMock = $this->getMock('Magento\\Quote\\Model\\Quote\\Address\\Total', [], [], '', false); $objectManager = new ObjectManager($this); $taxData = $this->getMock('Magento\\Tax\\Helper\\Data', [], [], '', false); $taxConfig = $this->getMockBuilder('\\Magento\\Tax\\Model\\Config')->disableOriginalConstructor()->setMethods(['priceIncludesTax', 'getShippingTaxClass', 'shippingPriceIncludesTax', 'discountTax'])->getMock(); $taxConfig->expects($this->any())->method('priceIncludesTax')->will($this->returnValue(false)); $taxConfig->expects($this->any())->method('getShippingTaxClass')->will($this->returnValue(1)); $taxConfig->expects($this->any())->method('shippingPriceIncludesTax')->will($this->returnValue(false)); $taxConfig->expects($this->any())->method('discountTax')->will($this->returnValue(false)); $product = $this->getMock('\\Magento\\Catalog\\Model\\Product', [], [], '', false); $item = $this->getMockBuilder('Magento\\Quote\\Model\\Quote\\Item')->disableOriginalConstructor()->setMethods(['getParentItem', 'getHasChildren', 'getProduct', 'getQuote', 'getCode', '__wakeup'])->getMock(); $item->expects($this->any())->method('getParentItem')->will($this->returnValue(null)); $item->expects($this->any())->method('getHasChildren')->will($this->returnValue(false)); $item->expects($this->any())->method('getCode')->will($this->returnValue("1")); $item->expects($this->any())->method('getProduct')->will($this->returnValue($product)); foreach ($itemData as $key => $value) { $item->setData($key, $value); } $items = [$item]; $taxDetails = $this->getMock('Magento\\Tax\\Api\\Data\\TaxDetailsInterface'); $taxDetails->expects($this->any())->method('getItems')->will($this->returnValue($items)); $storeManager = $this->getMockBuilder('\\Magento\\Store\\Model\\StoreManagerInterface')->disableOriginalConstructor()->setMethods(['getStore', 'hasSingleStore', 'isSingleStoreMode', 'getStores', 'getWebsite', 'getWebsites', 'reinitStores', 'getDefaultStoreView', 'setIsSingleStoreModeAllowed', 'getGroup', 'getGroups', 'clearWebsiteCache', 'setCurrentStore'])->getMock(); $storeMock = $this->getMockBuilder('Magento\\Store\\Model\\Store')->disableOriginalConstructor()->getMock(); $storeManager->expects($this->any())->method('getStore')->will($this->returnValue($storeMock)); $calculatorFactory = $this->getMockBuilder('Magento\\Tax\\Model\\Calculation\\CalculatorFactory')->disableOriginalConstructor()->setMethods(['create'])->getMock(); $calculationTool = $this->getMockBuilder('Magento\\Tax\\Model\\Calculation')->disableOriginalConstructor()->setMethods(['getRate', 'getAppliedRates', 'round', 'calcTaxAmount', '__wakeup'])->getMock(); $calculationTool->expects($this->any())->method('round')->will($this->returnArgument(0)); $calculationTool->expects($this->any())->method('getRate')->will($this->returnValue(20)); $calculationTool->expects($this->any())->method('calcTaxAmount')->will($this->returnValue(20)); $calculationTool->expects($this->any())->method('getAppliedRates')->will($this->returnValue($appliedRatesData)); $calculator = $objectManager->getObject('Magento\\Tax\\Model\\Calculation\\TotalBaseCalculator', ['calculationTool' => $calculationTool]); $calculatorFactory->expects($this->any())->method('create')->will($this->returnValue($calculator)); $taxCalculationService = $this->getMock('\\Magento\\Tax\\Api\\TaxCalculationInterface'); $taxClassKeyDataObjectMock = $this->getMock('\\Magento\\Tax\\Api\\Data\\TaxClassKeyInterface'); $taxClassKeyDataObjectFactoryMock = $this->getMockBuilder('\\Magento\\Tax\\Api\\Data\\TaxClassKeyInterfaceFactory')->disableOriginalConstructor()->getMock(); $taxClassKeyDataObjectFactoryMock->expects($this->any())->method('create')->will($this->returnValue($taxClassKeyDataObjectMock)); $taxClassKeyDataObjectMock->expects($this->any())->method('setType')->willReturnSelf(); $taxClassKeyDataObjectMock->expects($this->any())->method('setValue')->willReturnSelf(); $itemDataObjectMock = $this->getMock('\\Magento\\Tax\\Api\\Data\\QuoteDetailsItemInterface'); $itemDataObjectFactoryMock = $this->getMockBuilder('\\Magento\\Tax\\Api\\Data\\QuoteDetailsItemInterfaceFactory')->disableOriginalConstructor()->getMock(); $itemDataObjectFactoryMock->expects($this->any())->method('create')->will($this->returnValue($itemDataObjectMock)); $itemDataObjectMock->expects($this->any())->method('setTaxClassKey')->willReturnSelf(); $itemDataObjectMock->expects($this->any())->method('getAssociatedTaxables')->willReturnSelf(); $regionFactory = $this->getMockBuilder('Magento\\Customer\\Api\\Data\\RegionInterfaceFactory')->disableOriginalConstructor()->setMethods(['setRegionId', 'create'])->getMock(); $addressFactory = $this->getMockBuilder('Magento\\Customer\\Api\\Data\\AddressInterfaceFactory')->disableOriginalConstructor()->setMethods(['getRegionBuilder', 'create'])->getMock(); $region = $this->getMockForAbstractClass('Magento\\Customer\\Api\\Data\\RegionInterface', [], '', false); $regionFactory->expects($this->any())->method('setRegionId')->will($this->returnValue($regionFactory)); $regionFactory->expects($this->any())->method('create')->will($this->returnValue($region)); $addressFactory->expects($this->any())->method('getRegionBuilder')->will($this->returnValue($regionFactory)); $quoteDetails = $this->getMock('Magento\\Tax\\Api\\Data\\QuoteDetailsInterface'); $quoteDetailsDataObjectFactoryMock = $this->getMock('\\Magento\\Tax\\Api\\Data\\QuoteDetailsInterfaceFactory', ['create'], [], '', false); $quoteDetailsDataObjectFactoryMock->expects($this->any())->method('create')->will($this->returnValue($quoteDetails)); $quoteDetailsItemDataObjectFactoryMock = $this->getMock('Magento\\Tax\\Api\\Data\\QuoteDetailsItemInterfaceFactory', ['create'], [], '', false); $taxTotalsCalcModel = new Tax($taxConfig, $taxCalculationService, $quoteDetailsDataObjectFactoryMock, $quoteDetailsItemDataObjectFactoryMock, $taxClassKeyDataObjectFactoryMock, $addressFactory, $regionFactory, $taxData); $store = $this->getMockBuilder('Magento\\Store\\Model\\Store')->disableOriginalConstructor()->setMethods(['convertPrice', '__wakeup', 'getStoreId'])->getMock(); $store->expects($this->any())->method('getStoreId')->will($this->returnValue(1)); $quote = $this->getMock('Magento\\Quote\\Model\\Quote', [], [], '', false); $quote->expects($this->any())->method('getStore')->will($this->returnValue($store)); $address = $this->getMockBuilder('Magento\\Quote\\Model\\Quote\\Address')->disableOriginalConstructor()->setMethods(['getAssociatedTaxables', 'getQuote', 'getBillingAddress', 'getRegionId', '__wakeup', 'getCustomAttributesCodes'])->getMock(); $item->expects($this->any())->method('getQuote')->will($this->returnValue($quote)); $address->expects($this->any())->method('getQuote')->will($this->returnValue($quote)); $address->expects($this->any())->method('getAssociatedTaxables')->will($this->returnValue([])); $address->expects($this->any())->method('getRegionId')->will($this->returnValue($region)); $address->expects($this->any())->method('getCustomAttributesCodes')->willReturn([]); $quote->expects($this->any())->method('getBillingAddress')->will($this->returnValue($address)); $addressFactory->expects($this->any())->method('create')->will($this->returnValue($address)); $addressData["cached_items_all"] = $items; foreach ($addressData as $key => $value) { $address->setData($key, $value); } $taxTotalsCalcModel->collect($quote, $shippingAssignmentMock, $totalsMock); foreach ($verifyData as $key => $value) { $this->assertSame($verifyData[$key], $address->getData($key)); } }
/** * Collect tax totals for quote address * * @param Quote $quote * @param ShippingAssignmentInterface $shippingAssignment * @param Address\Total $total * @return $this * @throws RemoteServiceUnavailableException */ public function collect(Quote $quote, ShippingAssignmentInterface $shippingAssignment, Address\Total $total) { // If quote is virtual, getShipping will return billing address, so no need to check if quote is virtual $address = $shippingAssignment->getShipping()->getAddress(); $storeId = $quote->getStoreId(); // This will allow a merchant to configure default tax settings for their site using Magento's core tax // calculation and AvaTax's calculation will only kick in during cart/checkout. This is useful for countries // where merchants are required to display prices including tax (such as some countries that charge VAT tax). if (!$this->config->isModuleEnabled($storeId) || $this->config->getTaxMode($storeId) == Config::TAX_MODE_NO_ESTIMATE_OR_SUBMIT || !$this->config->isAddressTaxable($address, $storeId)) { return parent::collect($quote, $shippingAssignment, $total); } $postcode = $address->getPostcode(); // If postcode is not present, then collect totals is being run from a context where customer has not submitted // their address, such as on the product listing, product detail, or cart page. Once the user enters their // postcode in the "Estimate Shipping & Tax" form on the cart page, or submits their shipping address in the // checkout, then a postcode will be present. if (!$postcode) { return parent::collect($quote, $shippingAssignment, $total); } $this->clearValues($total); if (!$shippingAssignment->getItems()) { return $this; } $taxQuoteDetails = $this->getTaxQuoteDetails($shippingAssignment, $total, $storeId, false); $baseTaxQuoteDetails = $this->getTaxQuoteDetails($shippingAssignment, $total, $storeId, true); // Get array of tax details try { $taxDetailsList = $this->interactionGetTax->getTaxDetailsForQuote($quote, $taxQuoteDetails, $baseTaxQuoteDetails, $shippingAssignment); } catch (\Exception $e) { switch ($this->config->getErrorAction($quote->getStoreId())) { case Config::ERROR_ACTION_DISABLE_CHECKOUT: $this->coreRegistry->register(self::AVATAX_GET_TAX_REQUEST_ERROR, true, true); return parent::collect($quote, $shippingAssignment, $total); break; case Config::ERROR_ACTION_ALLOW_CHECKOUT_NATIVE_TAX: default: /** * Note: while this should return Magento's tax calculation, the tax calculation may be slightly * off, as these two collect methods will not have run: * @see \Magento\Tax\Model\Sales\Total\Quote\Shipping::collect() * @see \Magento\Tax\Model\Sales\Total\Quote\Subtotal::collect() */ return parent::collect($quote, $shippingAssignment, $total); break; } } $taxDetails = $taxDetailsList[InteractionGet::KEY_TAX_DETAILS]; $baseTaxDetails = $taxDetailsList[InteractionGet::KEY_BASE_TAX_DETAILS]; $itemsByType = $this->organizeItemTaxDetailsByType($taxDetails, $baseTaxDetails); if (isset($itemsByType[self::ITEM_TYPE_PRODUCT])) { $this->processProductItems($shippingAssignment, $itemsByType[self::ITEM_TYPE_PRODUCT], $total); } if (isset($itemsByType[self::ITEM_TYPE_SHIPPING])) { $shippingTaxDetails = $itemsByType[self::ITEM_TYPE_SHIPPING][self::ITEM_CODE_SHIPPING][self::KEY_ITEM]; $baseShippingTaxDetails = $itemsByType[self::ITEM_TYPE_SHIPPING][self::ITEM_CODE_SHIPPING][self::KEY_BASE_ITEM]; $this->processShippingTaxInfo($shippingAssignment, $total, $shippingTaxDetails, $baseShippingTaxDetails); } //Process taxable items that are not product or shipping $this->processExtraTaxables($total, $itemsByType); //Save applied taxes for each item and the quote in aggregation $this->processAppliedTaxes($total, $shippingAssignment, $itemsByType); if ($this->includeExtraTax()) { $total->addTotalAmount('extra_tax', $total->getExtraTaxAmount()); $total->addBaseTotalAmount('extra_tax', $total->getBaseExtraTaxAmount()); } return $this; }