1

Magento 2 version 2.2.2

Steps to set tax rules: Create a configurable product, which has two simple (child) products. Configurable product is set as taxable with 20% tax setup. First simple product is set as taxable with 20% tax setup. Second simple product is set as no tax i.e. 0% tax. Add second product through configurable options to cart.

Actual result: Tax of 20% is being applied in cart for the second simple product.

Expected result: 0% tax should be applied for the second simple product.

How can I modify this to achieve my requirement?

4 Answers 4

1

I was having the same issue due to UK VAT rules and found several magento bug created on github but no actual fix.

So then while looking for a workaround I have built a module to change the Magento behaviour according to our requirement.

Basically we need to update the definition of mapItem method of class Magento\Tax\Model\Sales\Total\Quote\CommonTaxCollector

For that we need to override 2 magento classes i.e. write preference in di.xml

<preference for="Magento\Tax\Model\Sales\Total\Quote\CommonTaxCollector" type="VendorName\MagentoChildProductTaxExtend\Preference\Tax\Model\Sales\Total\Quote\CommonTaxCollector"/>
<preference for="Magento\Tax\Model\Sales\Total\Quote\Tax" type="VendorName\MagentoChildProductTaxExtend\Preference\Tax\Model\Sales\Total\Quote\Tax"/>

Now in mapItem method of class VendorName\MagentoChildProductTaxExtend\Preference\Tax\Model\Sales\Total\Quote\CommonTaxCollector in line 211, we need to replace the $item->getProduct()->getTaxClassId() with the child product tax class id.

For that, we can change to these lines of code in our own class -

    $taxClassId = $item->getProduct()->getTaxClassId();
    if($item->getHasChildren()) {
        foreach ($item->getChildren() as $child) {
            $taxClassId = $child->getProduct()->getTaxClassId();
        }
    }
    /** @var \Magento\Tax\Api\Data\QuoteDetailsItemInterface $itemDataObject */
    $itemDataObject = $itemDataObjectFactory->create();
    $itemDataObject->setCode($item->getTaxCalculationItemId())
        ->setQuantity($item->getQty())
        ->setTaxClassKey(
            $this->taxClassKeyDataObjectFactory->create()
                ->setType(TaxClassKeyInterface::TYPE_ID)
                //->setValue($item->getProduct()->getTaxClassId())
                ->setValue($taxClassId)
        )
        ->setIsTaxIncluded($priceIncludesTax)
        ->setType(self::ITEM_TYPE_PRODUCT);

Create your own module and add those codes, this works in every tax related section in magento, Tested on Ver 2.2.2

Cheers!!

3
  • Why are you extending Magento\Tax\Model\Sales\Total\Quote\Tax? you're changing only the code in CommonTaxCollector.
    – SimoneB
    Commented Jul 3, 2018 at 9:27
  • Hi @SimoneB, due to backward compatibility. My modified method wont be called if we dont extend that class as well
    – Sandipan S
    Commented Jul 4, 2018 at 4:59
  • Not working on 2.2.7, had no chance to test on other versions. I've overridden only the method (not the all class that is simply extended). Is it supposed to be done that way?
    – SimoneB
    Commented Jan 15, 2019 at 17:04
2

You can also create a plugin for that

di.xml

<type name="Magento\Tax\Model\Sales\Total\Quote\CommonTaxCollector">
    <plugin name="child_tax" type="Vendor\ModuleName\Plugin\ChildTaxClass" sortOrder="1" />
</type>

ChildTaxClass.php

namespace Vendor\ModuleName\Plugin;
class ChildTaxClass
{
/**
 * @var \Magento\Tax\Api\Data\TaxClassKeyInterfaceFactory
 */
private $taxClassKeyDataObjectFactory;

/**
 * ChildTaxClass constructor.
 * @param \Magento\Tax\Api\Data\TaxClassKeyInterfaceFactory $taxClassKeyDataObjectFactory
 */
public function __construct(
    \Magento\Tax\Api\Data\TaxClassKeyInterfaceFactory $taxClassKeyDataObjectFactory
) {
    $this->taxClassKeyDataObjectFactory = $taxClassKeyDataObjectFactory;
}

/**
 * @param \Magento\Tax\Model\Sales\Total\Quote\CommonTaxCollector $subject
 * @param callable $proceed
 * @param \Magento\Tax\Api\Data\QuoteDetailsItemInterfaceFactory $itemDataObjectFactory
 * @param \Magento\Quote\Model\Quote\Item\AbstractItem $item
 * @param $priceIncludesTax
 * @param $useBaseCurrency
 * @param null $parentCode
 * @return \Magento\Quote\Model\Quote\Item\AbstractItem|\Magento\Tax\Api\Data\QuoteDetailsItemInterface
 */
public function aroundMapItem(
    \Magento\Tax\Model\Sales\Total\Quote\CommonTaxCollector $subject,
    callable $proceed,
    \Magento\Tax\Api\Data\QuoteDetailsItemInterfaceFactory $itemDataObjectFactory,
    \Magento\Quote\Model\Quote\Item\AbstractItem $item,
    $priceIncludesTax,
    $useBaseCurrency,
    $parentCode = null
) {

    $taxClassId = $item->getProduct()->getTaxClassId();
    if ($item->getHasChildren()) {
        foreach ($item->getChildren() as $child) {
            $taxClassId = $child->getProduct()->getTaxClassId();
        }
    }

    // call method
    /** @var \Magento\Tax\Api\Data\QuoteDetailsItemInterface $item */
    $item = $proceed(
        $itemDataObjectFactory,
        $item,
        $priceIncludesTax,
        $useBaseCurrency,
        $parentCode
    );

    // Set tax class from child (if available)
    $item->setTaxClassId($taxClassId);
    $item->setTaxClassKey(
        $this->taxClassKeyDataObjectFactory->create()
            ->setType(\Magento\Tax\Api\Data\TaxClassKeyInterface::TYPE_ID)
            ->setValue($taxClassId)
    );
    return $item;
}

}

1
  • this one worked for me thanks"
    – SimoneB
    Commented Jan 21, 2019 at 17:41
0

i have the same problem on Magento 1 with UK product, different size have different tax rate.

exemple : Configurable (global 20% tax) - Simple 1 (global 20% tax, but on UK 0% tax) - Simple 2 (global 20% tax, but on UK 20% tax)

in method Mage_Tax_Model_Sales_Total_Quote_Tax::_totalBaseProcessItemTax, dont forget to add a config to disable this functionality

///// BEGIN OLD
//$taxRateRequest->setProductClassId($item->getProduct()->getTaxClassId());
///// BEGIN OLD
///// BEGIN AKOA
$configEnable = Mage::getStoreConfigFlag('tax/calculation/tax_rate_on_simple_enable', $item->getStoreId());
if ($configEnable && $item->getHasChildren()) {
    $children = $item->getChildren();
    foreach ($children as $childItem) {
        $taxRateRequest->setProductClassId($childItem->getProduct()->getTaxClassId());
        break;
    }
} else {
    $taxRateRequest->setProductClassId($item->getProduct()->getTaxClassId());
}
///// BEGIN AKOA
0

From Magento 2.3.2 the tax that is applied to a simple child product is now based on the tax class of that product. Previously, Magento based the tax for a child product on the tax class of its parent product.

So better way to fix this is to upgrade the version to match 2.3.2.

Best of LUCK!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.