Mage_Weee and why it is important for tax calculation
TL;DR
Install Topological Sort to fix the sorting algorithm.
Problem
Mage_Weee
is a module which is needed in Magento to calculate the so called Waste Electrical and Electronic Equipment Directive. It is a tax in Europe for electronic stuff, so that it is already paid, when you throws it away. Don't ask me. We don't sell any kind of electric stuff, so it is a good decision to remove the module.
<!-- app/etc/modules/zzzzzz_DeactivatedModules.xml-->
<?xml version="1.0"?>
<config>
<modules>
<Mage_Weee>
<active>false</active>
</Mage_Weee>
</modules>
</config>
Missing Mage_Weee adds tax on product instead of including it
What happens then was very irritating for me.
Before:
After:
You might sense the miscalculation of the tax. Our tax settings are still correct and everything is fine, but the tax is added to the price, instead of being included.
Easiest fix here is to just NOT deactivate Mage_Weee
, but this is unsatisfying. So I dig deeper (and have already an idea, what happens):
Magento total models
Magento is calculating all the stuff in quote and order with total models. You can check what total models are called in
\Mage_Sales_Model_Quote_Address::collectTotals
foreach ($this->getTotalCollector()->getCollectors() as $model) {
echo get_class($model) . "\n";
$model->collect($this);
}
Billing address with Mage_Weee
Mage_Sales_Model_Quote_Address_Total_Nominal
Mage_Sales_Model_Quote_Address_Total_Subtotal
Mage_Sales_Model_Quote_Address_Total_Msrp
Mage_SalesRule_Model_Quote_Freeshipping
Mage_Tax_Model_Sales_Total_Quote_Subtotal
Mage_Weee_Model_Total_Quote_Weee
Mage_Sales_Model_Quote_Address_Total_Shipping
Mage_Tax_Model_Sales_Total_Quote_Shipping
Mage_SalesRule_Model_Quote_Discount
Mage_Tax_Model_Sales_Total_Quote_Tax
Mage_Sales_Model_Quote_Address_Total_Grand
Billing address without Mage_Weee
Mage_SalesRule_Model_Quote_Freeshipping
Mage_Tax_Model_Sales_Total_Quote_Subtotal
Mage_Tax_Model_Sales_Total_Quote_Shipping
Mage_SalesRule_Model_Quote_Discount
Mage_Tax_Model_Sales_Total_Quote_Tax
Mage_Sales_Model_Quote_Address_Total_Msrp
Mage_Sales_Model_Quote_Address_Total_Nominal
Mage_Sales_Model_Quote_Address_Total_Subtotal
Mage_Sales_Model_Quote_Address_Total_Shipping
Mage_Sales_Model_Quote_Address_Total_Grand
As you can see, the order is totally different. I'm cleaning up the list a little bit:
WITH Weee | WithOUT Weee |
---|---|
Mage_Sales_Model_Quote_Address_Total_Subtotal | Mage_Tax_Model_Sales_Total_Quote_Subtotal |
Mage_Tax_Model_Sales_Total_Quote_Subtotal | Mage_Tax_Model_Sales_Total_Quote_Shipping |
Mage_Sales_Model_Quote_Address_Total_Shipping | Mage_Tax_Model_Sales_Total_Quote_Tax |
Mage_Tax_Model_Sales_Total_Quote_Shipping | Mage_Sales_Model_Quote_Address_Total_Subtotal |
Mage_Tax_Model_Sales_Total_Quote_Tax | Mage_Sales_Model_Quote_Address_Total_Shipping |
Mage_Sales_Model_Quote_Address_Total_Grand | Mage_Sales_Model_Quote_Address_Total_Grand |
I think (I didn't check it yet), that the Mage_Tax
totals expect, that the Mage_Sales
already ran and collected all the sums, etc. So when you are changing the order from first Mage_Sales
, then Mage_Tax
, you get wrong results.
Ordering multiple dependend nodes in a graph is a hard problem
The problem lays in the ordering algorithm. All the totals have a before
and after
in their definition.
<!-- app/code/core/Mage/Tax/etc/config.xml:160 -->
<sales>
<quote>
<totals>
<tax_subtotal>
<class>tax/sales_total_quote_subtotal</class>
<after>freeshipping</after>
<before>tax,discount</before>
</tax_subtotal>
<tax_shipping>
<class>tax/sales_total_quote_shipping</class>
<after>shipping,tax_subtotal</after>
<before>tax,discount</before>
</tax_shipping>
[...]
All the ordering is done here:
\Mage_Sales_Model_Config_Ordered
and this is buggy.
How to solve it the great way
The hard solution for this is:
- Implement a real graph algorithm which solves all the dependencies and orders the total models correct
- Play with all the
before
andafter
nodes until the order is correct.
I neither implemented a cool algorithm yet (or looked it up) to solve the problem, nor did I play with the values until everything is fine. I'm staying with the solution: Not deactivating Mage_Weee
for the moment.
Update: Thanks to @Daniel_Sloof, more informations from @VinaiKopp
Update 2: I found even more on this topic on Stackoverflow from @s3lf