Magento VAT calculation issue with Price Inclusive TAX
Go To
System -> Configuration -> Tax -> Calculation Settings
Select Unit Price
in Tax Calculation Method Based On
Reference
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 €
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 ;)