Magento – Changing and of totals in config.xml doesn’t alter the order they are processed

cartcheckoutmoduletotals

TL:DR – trying to change the order that totals are collected doesn't work as expected. How do I adjust the order they are processed properly?


I previously had a problem with a custom total breaking the tax total, and found the problem was the order that totals are added in sales/quote/address/total/collector.php getCollectors().

on my working modules config.xml I use:

    <quote>
        <totals>
            <fee>
                <class>fee/sales_quote_address_total_fee</class>
                <before>subtotal</before>
            </fee>
        </totals>
    </quote>

on another install the module, using the same config.xml doesn't work.

after some debugging and testing I confirmed that the problem is this bit of code (when it's used the taxes don't calculate correctly, when it's commented out it does), and it seems the problem is that on the working install changing the "before" node changes the order, but on the non-working it doesn't behave as expected.

I need my total to be added before the subtotal, but below you can see some examples of what it is doing on both the working install and the non-working install.

So my questions are:
On the non-working install, why is my fee being added to the totals so late, even though it's set to before subtotal?

Is there another way to adjust the order they are collected?

Is there anything that might over-ride or alter the order they should be collected?

how can I get my total to collect before the subtotal, like I want it to?


What I did so far –

I made a simple controller with the following:

$collectors = Mage::getModel('sales/quote_address_total_collector')->getCollectors();
Zend_Debug::dump(array_keys($collectors));

and have run it in the following situations with the following results(please take not of the total "fee" which is mine):

working install with fee set to <after>subtotal</after> (breaks the install, but here to show that I can adjust the order and it shows up where it should)

array (size=12)
  0 => string 'nominal' (length=7)
  1 => string 'subtotal' (length=8)
  2 => string 'msrp' (length=4)
  3 => string 'fee' (length=3)
  4 => string 'freeshipping' (length=12)
  5 => string 'tax_subtotal' (length=12)
  6 => string 'weee' (length=4)
  7 => string 'shipping' (length=8)
  8 => string 'tax_shipping' (length=12)
  9 => string 'discount' (length=8)
  10 => string 'tax' (length=3)
  11 => string 'grand_total' (length=11)

working install with fee set to <before>subtotal</before>

array (size=12)
  0 => string 'nominal' (length=7)
  1 => string 'fee' (length=3)
  2 => string 'subtotal' (length=8)
  3 => string 'msrp' (length=4)
  4 => string 'freeshipping' (length=12)
  5 => string 'tax_subtotal' (length=12)
  6 => string 'weee' (length=4)
  7 => string 'shipping' (length=8)
  8 => string 'tax_shipping' (length=12)
  9 => string 'discount' (length=8)
  10 => string 'tax' (length=3)
  11 => string 'grand_total' (length=11)

nonworking install with fee set to <before>subtotal</before> (should work)

array(13) {
  [0] => string(7) "nominal"
  [1] => string(8) "subtotal"
  [2] => string(12) "tax_subtotal"
  [3] => string(12) "tax_shipping"
  [4] => string(3) "fee"
  [5] => string(11) "aw_giftwrap"
  [6] => string(12) "freeshipping"
  [7] => string(8) "shipping"
  [8] => string(4) "weee"
  [9] => string(8) "discount"
  [10] => string(11) "grand_total"
  [11] => string(4) "msrp"
  [12] => string(3) "tax"

nonworking install with fee set to <after>subtotal</after>

array(13) {
  [0] => string(7) "nominal"
  [1] => string(8) "subtotal"
  [2] => string(12) "freeshipping"
  [3] => string(12) "tax_subtotal"
  [4] => string(12) "tax_shipping"
  [5] => string(11) "aw_giftwrap"
  [6] => string(8) "shipping"
  [7] => string(3) "fee"
  [8] => string(4) "weee"
  [9] => string(8) "discount"
  [10] => string(11) "grand_total"
  [11] => string(4) "msrp"
  [12] => string(3) "tax"

Best Answer

I've come across the same problem before. I know its an old question but in case somebody sees this, here is what helped me in the cases when I encountered this:

Sometimes it might work just by adding more totals into the before/after nodes. However even if your totals are then ordered correctly, some other existing one might get ordered wrongly.

The code responsible for sorting is in class: Mage_Sales_Model_Config_Ordered

I couldn't get my totals to order correctly without breaking some existing total, so what I did was to hardcode the correct order. If you check the method _getSortedCollectorCodes() that is responsible for sorting, it actually checks for a presence of a node in the first total and then sorts by it if present:

// invoke simple sorting if the first element contains the "sort_order" key
    reset($configArray);
    $element = current($configArray);
    if (isset($element['sort_order'])) {
        uasort($configArray, array($this, '_compareSortOrder'));
    } else {

So we just need to add a sort order to each existing total which can be done easily within config.xml like so:

<global>
    <sales>
        <quote>
            <totals>
                <nominal>
                    <sort_order>10</sort_order>
                </nominal>
                <subtotal>
                    <sort_order>20</sort_order>
                </subtotal>
                <freeshipping>
                    <sort_order>30</sort_order>
                </freeshipping>
                ...
                <payment_fee>
                    <sort_order>120</sort_order>
                </payment_fee>
                <payment_fee_tax>
                    <sort_order>130</sort_order>
                </payment_fee_tax>
                ...
                <grand_total>
                    <sort_order>200</sort_order>
                </grand_total>
            </totals>
        </quote>
    </sales>
</global>
Related Topic