6

I have product with Price 6.50 € which includes 24% VAT in it. When I add it to cart, for 1 quantity the price shows correct.

Net value     5.24 €
VAT 24%       1.26 €
Total value   6,50 €

Now if I add 3 products to cart, the total becomes incorrect.

Net value     15.72 €
VAT 24%       3.77 €
Total value   19,49 €

Which is 0.01€ less than correct subtotal. It should be,

Net value     15.72 €
VAT 24%       3.78 €
Total value   19,50 €

Here you can see that VAT value is calculated wrong. It calculates 24% of 15.72 which is 3.77 and its correct, but it should be calculated on each product and then summed up to be 3.78

UPDATES

I have tried by setting Unit Price

System -> Configuration -> Tax -> Calculation Settings

But it gives me results like,

Net value     15.72 €
VAT 24%       3.06 €
Total value   18.78 €

It is because we are using a module Additional Fee extension on site, which adds 1 € to each product price. So I need to use Row Total to add Additional Fee data. SO I cannot use Unit Price, it gets Product Price which is 4.24 € to calculate Tax amount
Is there any other way?

  • actually in magento vat calculate on total(sub-total) of quote and yes 1.2576 is rounding off to 1.26 – Gopal Patel Mar 7 '17 at 12:52
  • Yes that's correct. My VAT on subtotal is 3.7728 which is rounded to 3.77. But That is incorrect. My cart total becomes 19.49 which actually should be 6.50 x 3 = 19.50 Is there any way to correct it? – John Mar 7 '17 at 12:58
  • you want to change tax implementation on single product level – Gopal Patel Mar 7 '17 at 13:02
  • Yes, something like that which can correct my cart details. – John Mar 7 '17 at 13:03
  • I think it needs high customization – Gopal Patel Mar 7 '17 at 13:05
3
+50

I have checked with Default Magento functionality and found that your issue can be resolved by overriding two functions:
Mage_Tax_Model_Sales_Total_Quote_Tax::_calcRowTaxAmount()
Mage_Tax_Model_Sales_Total_Quote_Subtotal::_rowBaseCalculation()
Create a module Mymodule_Updatetax which will override these functions.

class Mymodule_Updatetax_Model_Tax_Sales_Total_Quote_Subtotal extends Mage_Tax_Model_Sales_Total_Quote_Subtotal
{
    protected function _rowBaseCalculation($item, $request)
    {
        $request->setProductClassId($item->getProduct()->getTaxClassId());
        $rate = $this->_calculator->getRate($request);
        $qty = $item->getTotalQty();
        $additionalCharges = 1; // Get your additional fee from module
        $price = $taxPrice = $this->_calculator->round($item->getCalculationPriceOriginal());
        $basePrice = $baseTaxPrice = $this->_calculator->round($item->getBaseCalculationPriceOriginal());
        $subtotal = $taxSubtotal = $this->_calculator->round($item->getRowTotal());
        $baseSubtotal = $baseTaxSubtotal = $this->_calculator->round($item->getBaseRowTotal());

        // if we have a custom price, determine if tax should be based on the original price
        $taxOnOrigPrice = !$this->_helper->applyTaxOnCustomPrice($this->_store) && $item->hasCustomPrice();
        if ($taxOnOrigPrice) {
            $origSubtotal = $item->getOriginalPrice() * $qty;
            $baseOrigSubtotal = $item->getBaseOriginalPrice() * $qty;
        }

        $item->setTaxPercent($rate);
        if ($this->_config->priceIncludesTax($this->_store)) {
            if ($this->_sameRateAsStore($request)) {
                // determine which price to use when we calculate the tax
                if ($taxOnOrigPrice) {
                    $taxable        = $origSubtotal;
                    $baseTaxable    = $baseOrigSubtotal;
                } else {
                    $taxable        = $taxSubtotal;
                    $baseTaxable    = $baseTaxSubtotal;
                }
                $taxable        = $item->getOriginalPrice();
                $baseTaxable    = $item->getBaseOriginalPrice();
                $rowTax          = $this->_calculator->calcTaxAmount($taxable, $rate, true, true) * $qty;
                $baseRowTax      = $this->_calculator->calcTaxAmount($baseTaxable, $rate, true, true) * $qty;
                $taxPrice        = $price;
                $baseTaxPrice    = $basePrice;
                $taxSubtotal     = $subtotal;
                $baseTaxSubtotal = $baseSubtotal;
                $subtotal = $this->_calculator->round($subtotal - $rowTax);
                $baseSubtotal = $this->_calculator->round($baseSubtotal - $baseRowTax);
                $price = $this->_calculator->round($subtotal / $qty);
                $basePrice = $this->_calculator->round($baseSubtotal / $qty);
                $isPriceInclTax  = true;

                $item->setRowTax($rowTax);
                $item->setBaseRowTax($baseRowTax);
            } else {
                $storeRate       = $this->_calculator->getStoreRate($request, $this->_store);
                if ($taxOnOrigPrice) {
                    // the merchant already provided a customer's price that includes tax
                    $taxPrice     = $price;
                    $baseTaxPrice = $basePrice;
                    // determine which price to use when we calculate the tax
                    $taxable      = $this->_calculatePriceInclTax($item->getOriginalPrice(), $storeRate, $rate);
                    $baseTaxable  = $this->_calculatePriceInclTax($item->getBaseOriginalPrice(), $storeRate, $rate);
                } else {
                    // determine the customer's price that includes tax
                    $taxPrice     = $this->_calculatePriceInclTax($price, $storeRate, $rate);
                    $baseTaxPrice = $this->_calculatePriceInclTax($basePrice, $storeRate, $rate);
                    // determine which price to use when we calculate the tax
                    $taxable      = $taxPrice;
                    $baseTaxable  = $baseTaxPrice;
                }
                $taxable        = $item->getOriginalPrice() + $additionalCharges;
                $baseTaxable    = $item->getBaseOriginalPrice() + $additionalCharges;

                // determine the customer's tax amount
                $tax             = $this->_calculator->calcTaxAmount($taxable, $rate, true, true) * $qty;
                $baseTax         = $this->_calculator->calcTaxAmount($baseTaxable, $rate, true, true) * $qty;
                // determine the customer's price without taxes
                $price = $taxPrice - $tax;
                $basePrice = $baseTaxPrice - $baseTax;
                // determine subtotal amounts
                $taxable        *= $qty;
                $baseTaxable    *= $qty;
                $taxSubtotal     = $taxPrice * $qty;
                $baseTaxSubtotal = $baseTaxPrice * $qty;
                $rowTax          = $this->_calculator->calcTaxAmount($taxable, $rate, true, true);
                $baseRowTax      = $this->_calculator->calcTaxAmount($baseTaxable, $rate, true, true);
                $subtotal        = $taxSubtotal - $rowTax;
                $baseSubtotal    = $baseTaxSubtotal - $baseRowTax;
                $isPriceInclTax  = true;

                $item->setRowTax($rowTax);
                $item->setBaseRowTax($baseRowTax);
            }
        } else {
            // determine which price to use when we calculate the tax
            if ($taxOnOrigPrice) {
                $taxable = $origSubtotal;
                $baseTaxable = $baseOrigSubtotal;
            } else {
                $taxable = $subtotal;
                $baseTaxable = $baseSubtotal;
            }
            $taxable        = $item->getOriginalPrice() + $additionalCharges;
            $baseTaxable    = $item->getBaseOriginalPrice() + $additionalCharges;
            $appliedRates = $this->_calculator->getAppliedRates($request);
            $rowTaxes = array();
            $baseRowTaxes = array();
            foreach ($appliedRates as $appliedRate) {
                $taxRate = $appliedRate['percent'];
                $rowTaxes[] = $this->_calculator->calcTaxAmount($taxable, $taxRate, false, true) * $qty;
                $baseRowTaxes[] = $this->_calculator->calcTaxAmount($baseTaxable, $taxRate, false, true) * $qty;
            }
            $rowTax          = array_sum($rowTaxes);
            $baseRowTax      = array_sum($baseRowTaxes);
            $taxSubtotal     = $subtotal + $rowTax;
            $baseTaxSubtotal = $baseSubtotal + $baseRowTax;
            $taxPrice        = $this->_calculator->round($taxSubtotal/$qty);
            $baseTaxPrice    = $this->_calculator->round($baseTaxSubtotal/$qty);
            $isPriceInclTax  = false;
        }

        if ($item->hasCustomPrice()) {
            /**
             * Initialize item original price before declaring custom price
             */
            $item->getOriginalPrice();
            $item->setCustomPrice($price);
            $item->setBaseCustomPrice($basePrice);
        }
        $item->setPrice($basePrice);
        $item->setBasePrice($basePrice);
        $item->setRowTotal($subtotal);
        $item->setBaseRowTotal($baseSubtotal);
        $item->setPriceInclTax($taxPrice);
        $item->setBasePriceInclTax($baseTaxPrice);
        $item->setRowTotalInclTax($taxSubtotal);
        $item->setBaseRowTotalInclTax($baseTaxSubtotal);
        $item->setTaxableAmount($taxable);
        $item->setBaseTaxableAmount($baseTaxable);
        $item->setIsPriceInclTax($isPriceInclTax);
        if ($this->_config->discountTax($this->_store)) {
            $item->setDiscountCalculationPrice($taxSubtotal / $qty);
            $item->setBaseDiscountCalculationPrice($baseTaxSubtotal / $qty);
        } elseif ($isPriceInclTax) {
            $item->setDiscountCalculationPrice($subtotal / $qty);
            $item->setBaseDiscountCalculationPrice($baseSubtotal / $qty);
        }

        return $this;
    }
}

And,

class Mymodule_Updatetax_Model_Tax_Sales_Total_Quote_Tax extends Mage_Tax_Model_Sales_Total_Quote_Tax
{
    protected function _calcRowTaxAmount(
        $item, $rate, &$taxGroups = null, $taxId = null, $recalculateRowTotalInclTax = false
    )
    {
        $qty = $item->getTotalQty();
        $inclTax = $item->getIsPriceInclTax();
        $subtotal = $taxSubtotal = $item->getTaxableAmount();
        $baseSubtotal = $baseTaxSubtotal = $item->getBaseTaxableAmount();
        $rateKey = ($taxId == null) ? (string)$rate : $taxId;
        $additionalCharges = 1; // Get your additional fee from module
        $isWeeeEnabled = $this->_weeeHelper->isEnabled();
        $isWeeeTaxable = $this->_weeeHelper->isTaxable();

        $hiddenTax = null;
        $baseHiddenTax = null;
        $weeeTax = null;
        $baseWeeeTax = null;
        $rowTaxBeforeDiscount = null;
        $baseRowTaxBeforeDiscount = null;
        $weeeRowTaxBeforeDiscount = null;
        $baseWeeeRowTaxBeforeDiscount = null;

        switch ($this->_helper->getCalculationSequence($this->_store)) {
            case Mage_Tax_Model_Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_EXCL:
            case Mage_Tax_Model_Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_INCL:
                $rowTaxBeforeDiscount = $this->_calculator->calcTaxAmount($subtotal, $rate, $inclTax, false);
                $baseRowTaxBeforeDiscount = $this->_calculator->calcTaxAmount($baseSubtotal, $rate, $inclTax, false);

                if ($isWeeeEnabled && $isWeeeTaxable) {
                    $weeeRowTaxBeforeDiscount = $this->_calculateRowWeeeTax(0, $item, $rate, false);
                    $rowTaxBeforeDiscount += $weeeRowTaxBeforeDiscount;
                    $baseWeeeRowTaxBeforeDiscount = $this->_calculateRowWeeeTax(0, $item, $rate);
                    $baseRowTaxBeforeDiscount += $baseWeeeRowTaxBeforeDiscount;
                }
                $rowTaxBeforeDiscount = $rowTax = $this->_calculator->round($rowTaxBeforeDiscount);
                $baseRowTaxBeforeDiscount = $baseRowTax = $this->_calculator->round($baseRowTaxBeforeDiscount);
                break;
            case Mage_Tax_Model_Calculation::CALC_TAX_AFTER_DISCOUNT_ON_EXCL:
            case Mage_Tax_Model_Calculation::CALC_TAX_AFTER_DISCOUNT_ON_INCL:
                $discountAmount = $item->getDiscountAmount();
                $baseDiscountAmount = $item->getBaseDiscountAmount();

                if ($isWeeeEnabled && $this->_weeeHelper->includeInSubtotal()) {
                    $discountAmount = $discountAmount - $item->getWeeeDiscount();
                    $baseDiscountAmount = $baseDiscountAmount - $item->getBaseWeeeDiscount();
                }

                $rowTax = $this->_calculator->calcTaxAmount(
                    $item->getOriginalPrice() + $additionalCharges,
                    $rate,
                    $inclTax
                ) * $qty;
                $baseRowTax = $this->_calculator->calcTaxAmount(
                    $item->getBaseOriginalPrice() + $additionalCharges,
                    $rate,
                    $inclTax
                ) * $qty;

                if ($isWeeeEnabled && $this->_weeeHelper->isTaxable()) {
                    $weeeTax = $this->_calculateRowWeeeTax($item->getWeeeDiscount(), $item, $rate, false);
                    $rowTax += $weeeTax;
                    $baseWeeeTax = $this->_calculateRowWeeeTax($item->getBaseWeeeDiscount(), $item, $rate);
                    $baseRowTax += $baseWeeeTax;
                }

                $rowTax = $this->_calculator->round($rowTax);
                $baseRowTax = $this->_calculator->round($baseRowTax);

                //Calculate the Row Tax before discount
                $rowTaxBeforeDiscount = $this->_calculator->calcTaxAmount(
                    $item->getOriginalPrice() + $additionalCharges,
                    $rate,
                    $inclTax,
                    false
                ) * $qty;
                $baseRowTaxBeforeDiscount = $this->_calculator->calcTaxAmount(
                    $item->getBaseOriginalPrice() + $additionalCharges,
                    $rate,
                    $inclTax,
                    false
                ) * $qty;
                $rowTax = $rowTax - $discountAmount; // Deduct discount
                $baseRowTax = $baseRowTax - $baseDiscountAmount; // Deduct discount
                //Calculate the Weee taxes before discount
                $weeeRowTaxBeforeDiscount = 0;
                $baseWeeeRowTaxBeforeDiscount = 0;
                if ($isWeeeTaxable) {
                    $weeeRowTaxBeforeDiscount = $this->_calculateRowWeeeTax(0, $item, $rate, false);
                    $rowTaxBeforeDiscount += $weeeRowTaxBeforeDiscount;
                    $baseWeeeRowTaxBeforeDiscount = $this->_calculateRowWeeeTax(0, $item, $rate);
                    $baseRowTaxBeforeDiscount += $baseWeeeRowTaxBeforeDiscount;
                }

                $rowTaxBeforeDiscount = max(0, $this->_calculator->round($rowTaxBeforeDiscount));
                $baseRowTaxBeforeDiscount = max(0, $this->_calculator->round($baseRowTaxBeforeDiscount));

                if ($inclTax && $discountAmount > 0) {
                    $hiddenTax = $rowTaxBeforeDiscount - $rowTax;
                    $baseHiddenTax = $baseRowTaxBeforeDiscount - $baseRowTax;
                    $this->_hiddenTaxes[] = array(
                        'rate_key' => $rateKey,
                        'qty' => 1,
                        'item' => $item,
                        'value' => $hiddenTax,
                        'base_value' => $baseHiddenTax,
                        'incl_tax' => $inclTax,
                    );
                } elseif ($discountAmount > $subtotal) { // case with 100% discount on price incl. tax
                    $hiddenTax = $discountAmount - $subtotal;
                    $baseHiddenTax = $baseDiscountAmount - $baseSubtotal;
                    $this->_hiddenTaxes[] = array(
                        'rate_key' => $rateKey,
                        'qty' => 1,
                        'item' => $item,
                        'value' => $hiddenTax,
                        'base_value' => $baseHiddenTax,
                        'incl_tax' => $inclTax,
                    );
                }
                // calculate discount compensation
                if (!$item->getNoDiscount() && $item->getWeeeTaxApplied()) {
                    $item->setDiscountTaxCompensation($item->getDiscountTaxCompensation() +
                    $rowTaxBeforeDiscount - max(0, $rowTax));
                }
                break;
        }
        $item->setTaxAmount($item->getTaxAmount() + max(0, $rowTax));
        $item->setBaseTaxAmount($item->getBaseTaxAmount() + max(0, $baseRowTax));
        if (is_array($taxGroups)) {
            $taxGroups[$rateKey]['tax'] = max(0, $rowTax);
            $taxGroups[$rateKey]['base_tax'] = max(0, $baseRowTax);
        }

        $rowTotalInclTax = $item->getRowTotalInclTax();
        if (!isset($rowTotalInclTax) || $recalculateRowTotalInclTax) {
            if ($this->_config->priceIncludesTax($this->_store)) {
                $item->setRowTotalInclTax($subtotal);
                $item->setBaseRowTotalInclTax($baseSubtotal);
            } else {
                $item->setRowTotalInclTax(
                    $item->getRowTotalInclTax() + $rowTaxBeforeDiscount - $weeeRowTaxBeforeDiscount);
                $item->setBaseRowTotalInclTax($item->getBaseRowTotalInclTax() +
                $baseRowTaxBeforeDiscount - $baseWeeeRowTaxBeforeDiscount);
            }
        }
        return $this;
    }
}

The trick here is that we are calculating the Tax amount based on product price and then make a sum of it. So if your product price is 6.50 €, and Your Tax percent is 24%, it will first calculate tax for each of your product price + your Additional fee amount and then make a sum of all values.

24% Tax for 6.50 = 1.26
1.26 * 3 = 3.78

So total will be,

Net value     15.72 €
VAT 24%       3.78 €
Total value   19,50 €
  • I have tried this and its working but there is one issue. When I apply discount, it is not working. – John Mar 14 '17 at 8:33
  • Okay, let me check with discount amount, I'll update the answer once its resolved. – Jaimin Sutariya Mar 14 '17 at 8:44
  • Please check updated answer as I have added discount calculation to Tax amount. – Jaimin Sutariya Mar 14 '17 at 10:08
3

Go To

System -> Configuration -> Tax -> Calculation Settings

Select Unit Price in Tax Calculation Method Based On

Reference

  • Hello, I have tried this solution but its not working for my case. Please check my updated question. – John Mar 9 '17 at 14:25
  • For the benefit of Magento 2 developers, the setting is now at: Stores -> Sales -> Tax -> Tax Calculation Method Based On – jschrab Mar 20 '18 at 16:09
2

This is similar issue https://stackoverflow.com/questions/13529580/magento-tax-rounding-issue

There are some bugs with rounding prices in core Magento.
Read links and comments.
It should help ;)

  • I don't think its rounding issue as the 24% tax on 15.72 is 3.7728 and which is correct to be display as 3.77 – John Mar 9 '17 at 14:35
  • I don't know what else it could be if You don't have custom module for price. I got one same issue with tax and similar with price sending to payment gateway. It was round issue no matter how strange it looks. – Konrad Siamro Mar 9 '17 at 14:42
1

You have to rewrite this:

In app/code/core/Mage/Core/Model/Store.php, function roundPrice($price) change:

return round($price, 2);

to

return round($price, 4);

This works all and well until later when Magento detects that the Paypal payment amount (which is the correct amount without rounding issues) does not match the Magento calculated amount (the amound that does have rounding issues) … hence a “fraud suspected” message will be assigned to the product.

The method around this is to then do the following:

/app/code/core/Mage/Sales/Model/Order/Payment.php

protected function _isCaptureFinal($amountToCapture)
{
    $amountToCapture = round($this->_formatAmount($amountToCapture, true), 2);
    $orderGrandTotal = round($this->_formatAmount($this->getOrder()->getBaseGrandTotal(), true), 2);
    $baseAmountPaid = round($this->_formatAmount($this->getBaseAmountPaid(), true), 2);

    if (abs($orderGrandTotal - $baseAmountPaid - $amountToCapture) getShouldCloseParentTransaction()) {
            $this->setShouldCloseParentTransaction(true);
        }
        return true;
    }
    return false;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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