In most countries there is one man you don’t want to stuff around – the Taxman. Unfortunately Magento has had a long string of issues around taxation. Admittedly it is not easy to write a system that works with all ideas every Taxman has ever come up with around the world. So my first advice is to not trust the numbers or if you have to, really stress test those numbers.
Pitfalls
Once an order is placed, Magento saves a tax “summary” of the order and the tax amounts and percentages on the order items – that’s all. Some pitfalls I have discovered fell into:
“summary” is incomplete
The tax summary only contains the tax amounts and the tax percentages. Since you don’t know if the tax amount was rounded and if so which way you can’t work backwards to get the amount the tax was charged on. You also can’t use this info to verify if Magento made a mistake or not. Collecting the tax amounts yourself by looping over the order items did the trick for me.
Shipping Tax Rate / Shipping Tax Percentage
If you are tasked to display the tax rate for the shipping costs after the order has been placed either a) run for the hills or b) quote high. The problem is that this information is simply not saved. The only information available once the order is placed is the shipping amount and shipping tax amount. Again trying to work backwards with the amounts you will be off by a few cents depending on how the amount was (in/correctly) rounded in the first place. Trying to look up the settings in your current settings has the downside that his information might have changed over time. The best solution I could come up with so far was to sum up all tax amounts of the order items and then compare this to the tax summary. Let me know if you know a better a way.
Item Tax Rates
Magento saves the tax percentage with each order item. In most scenarios this is sufficient to work out what tax rate applies. However in some scenarios you might be using multiple tax rates with the same percentage but you need to keep them separate (for example selling into Netherlands and Germany – both have a sales tax of 19%). This can only be solved retrospectively if you had no setting changes on your system. The way to do is to reload the initial quote that got converted to the order:
$quote = Mage::getModel('sales/quote')->load($order->getQuoteId());
and then reconstruct the tax calculation process (subject for a different post). Going forward you could create a new order item column and save the rate information when the order is being converted.
Math 101 gone wrong?
In a more recent example (1.4.1.1) I came across this order:

Looking at the numbers they don’t make sense any way you look at them. I hear you say but what about the hidden_tax_amount, Kristof. Of course the hidden tax amount! and it all makes sense now – well at least you can work out how the row total is made up RowTotal = Subtotal – Discount Amount – Hidden Tax Amount; My understanding of the hidden_tax_amount is that it is the amount of tax that would have been applied on the discount. (on a sidenote – in previous versions this information was stored slightly differently in tax_before_discount)
If you look closely all items have the same tax inclusive price. However one row is discounted and taxed differently to the others. This is some tax-foo introduced by the setting System > Calculation > Tax > Tax Calculation Based On > Total.
More hidden taxes or wysiNwyg
One other example I have come across only showed itself on the db level. A particular order had a shipping tax amount but no shipping amount.
In general if you have a spare moment I suggest to have a look at the inner workings of Magento at the db level. The table sales_flat_order_item is full of info what Magento does behind the back and saves for each item.
What to do
While your mileage may vary I suggest creating a set of sample orders which you test for each Magento version you deploy. A lot of rounding errors only show when using cents. In my view a good test order includes:
- Multiple items with various cent amounts (ie. $9.75, $4.99)
- Items with high quantities
- Shipping
- Discount
- Tax
The more test orders you have the more confident you’ll be that you have covered all the corner cases. One further item to verify is that what your customer sees in the basket matches up with what ends up being the final order. You may also want to invest some initial time into setting up some form of automation for this (for example Selenium for Firefox)
In general I’ve had more predictable outcomes with using tax exclusive amounts in the back-end and using the tax calculation method row total. What has your experience been so far?
And lastly: petition Magento to finally include unit and functional tests in their development process.
Links:
Lengthy thread on the forum with tax fixes for various versions
Originally published on magebase.com. Copyright © 2010 Magebase - All Rights Reserved.




Proud members of the
Good Article Kristof, we have some Sites where System Generates the TAX, while we want to reach a RRP of example 70.00 we must Input a Price of 59.574 but we find the system rounds up to 70.01 or 69.99 depending what we play with. Is there any guidlines on how to fix this?
Kevin
Hi Citrus Orange, thanks for stopping by. I think in the case where you want the RRP to be exact I would change to entering the amounts as tax inclusive in the back-end. Start testing with these settings:
System > Calculation > Tax > Catalog prices include tax > Yes
System > Calculation > Tax > Tax Calculation Based On > Row Total
Hey Kristof, won’t that increase rounding errors?
That kind of setup would mean total tax is the sum total of all the rounded taxes. But rounding shouldn’t really happen per item, correct?
Hi Vincent, just to clarify Magento has these calculation models:
1.) per unit
2.) per row total (qty x units)
3.) total (row totals combined)
And yes if you choose per unit or row total your tax total will include the rounded amounts.
What to do depends on your applicable tax laws. Here in NZ it is fine to round on the row total.
In general I find that the mode to calculate tax on the total has had the most bugs so far. Especially when the shipping amount needs to be taxed as well, items are taxed at different rates or items are discounted.
Thanks Kristof for your swift Reply. I did manage to get it displaying correctly by changing the store.php roundprice() to use 3 decimal places. I must test now like you mentioned above.
-13.5 C (Coldest Winter for decades)
Good to make contact with you, were here in Ireland
Happy Christmas and wishing you a successful 2011
After hours of research I tried to extract the shipping tax rate directly from the database via sql and it seems to work:
private function getShippingTaxRate($store) { $tax_class_id = Mage::helper('tax')->getShippingTaxClass($store); $resource = Mage::getSingleton('core/resource'); $readConnection = $resource->getConnection('core_read'); $tableName = $resource->getTableName('tax_calculation_rate'); //because of prefix ! $tableName2 = $resource->getTableName('tax_calculation'); $query = 'SELECT rate FROM ' . $tableName . ' WHERE tax_calculation_rate_id=(SELECT tax_calculation_rate_id FROM ' . $tableName2 . ' WHERE product_tax_class_id='.$tax_class_id.')'; $shipping_rate = $readConnection->fetchOne($query); return $shipping_rate; }I am a Magento beginner, so I am not sure if this is good practice or not. I will be greatful for any comments.
@Rushman thanks for posting your solution. Your approach looks like it could work but only as long as there is never a change of the shipping tax rate. Also your code does not relate to a specific order.