Magento – Surcharge Fee not included in tax calculation

ce-1.7.0.2taxtotals

I am trying to add a product-specific Extra-Shipping-Fee via product attributes.
The customer can buy a product and has to pay Extra-Shipping-Fee if it is set in Backend for that product.
There is another attribute which determines if the Extra-Shipping-Fee should be calculated multiple times, if the product is bought multiple times.
Everything works fine: The fee is getting charged by a total-model.
But it is not considered in tax-calculation. The Extra-Shipping-Fee is meant to include tax. The Total is calculated correctly, but the Extra-Shipping-Fee is not included in tax-calculation..
What am I missing? How do I say "Magento! Please include this fee in tax-calculation!" I am on this for days now and can't figure it out..
Every help is appreciated!

Here is what I got so far in my Total-Model:

<?php
class ****_Versandaufpreis_Model_Quote_Address_Total_Shipping_Surcharge extends Mage_Sales_Model_Quote_Address_Total_Abstract
{

    public function collect(Mage_Sales_Model_Quote_Address $address)
    {
        parent::collect($address);
        $total = 0;
        foreach ($address->getAllItems() as $item)
        {   
            if ($item->getVersandaufschlagMf() == 1) {
                $total += $item->getExtraVersandkosten() * $item->getQty();
            } else {
                $total += $item->getExtraVersandkosten();
            }
        }

        /*
        * add to Grand Total
        */
        $baseTotal = $this->_getBaseAmount($total);

        $this->_addAmount($total);
        $this->_addBaseAmount($baseTotal);

        /*
        * Store in Address Model
        */
        $address->setExtraVersandkosten($total);
        $address->setBaseExtraVersandkosten($baseTotal);


        return $this;
    }

    /**
    * Convert to Base-Currency
    *
    * @param float $amount
    * @return float $amount converted Amount
    */
    public function _getBaseAmount($amount)
    {
        $currentCurrency = Mage::app()->getStore()->getCurrentCurrency();
        $baseCurrency = Mage::app()->getStore()->getBaseCurrency();

        if ($baseCurrency->getCode() == $currentCurrency->getCode())
        {
            $baseAmount = $amount;
        }
        else
        {
            $baseAmount = Mage::helper('directory')->currencyConvert($amount, $currentCurrency, $baseCurrency);
        }

        return $baseAmount;
    }

    /**
    *
    * @param   Mage_Sales_Model_Quote_Address $address
    * @return  ****_Versandaufpreis_Model_Quote_Address_Total_Shipping_Surcharge
    */
    public function fetch(Mage_Sales_Model_Quote_Address $address)
    {
        if ($address->getExtraVersandkosten() > 0)
        {
            $address->addTotal(array(
                'code'  => $this->getCode(),
                'title' => Mage::helper('versandaufpreis')->__('Versandaufpreis'),
                'value' => $address->getExtraVersandkosten()
            ));
        }
        return $this;
    }
}

And here is the extension's config.xml

<?xml version="1.0"?>
<config>

    <modules>
        <****_Versandaufpreis>
            <version>0.1.0</version>
        </****_Versandaufpreis>
    </modules>

    <global>
        <models>
            <versandaufpreis>
                <class>****_Versandaufpreis_Model</class>
            </versandaufpreis>
        </models>
        <blocks>
            <versandaufpreis>
                <class>****_Versandaufpreis_Block</class>
            </versandaufpreis>
        </blocks>
        <helpers>
            <versandaufpreis>
                <class>****_Versandaufpreis_Helper</class>
            </versandaufpreis>
        </helpers>
        <resources>
            <versandaufpreis_catalog_setup>
                <setup>
                    <module>****_Versandaufpreis</module>
                    <class>Mage_Catalog_Model_Resource_Eav_Mysql4_Setup</class>
                </setup>
            </versandaufpreis_catalog_setup>
            <versandaufpreis_sales_setup>
                <setup>
                    <module>****_Versandaufpreis</module>
                    <class>Mage_Sales_Model_Mysql4_Setup</class>
                </setup>
            </versandaufpreis_sales_setup>
        </resources>
        <fieldsets>
            <sales_convert_quote_item>
                <extra_versandkosten><to_order_item>*</to_order_item></extra_versandkosten>
                <versandaufschlag_mf><to_order_item>*</to_order_item></versandaufschlag_mf>
            </sales_convert_quote_item>
            <sales_convert_order_item>
                <extra_versandkosten><to_quote_item>*</to_quote_item><to_shipment_item>*</to_shipment_item></extra_versandkosten>
                <versandaufschlag_mf><to_quote_item>*</to_quote_item><to_shipment_item>*</to_shipment_item></versandaufschlag_mf>
            </sales_convert_order_item>
            <sales_convert_quote_address>
                <extra_versandkosten><to_order>*</to_order></extra_versandkosten>
                <versandaufschlag_mf><to_order>*</to_order></versandaufschlag_mf>
                <base_extra_versandkosten><to_order>*</to_order></base_extra_versandkosten>
            </sales_convert_quote_address>
            <sales_convert_order>
                <extra_versandkosten><to_invoice>*</to_invoice><to_cm>*</to_cm></extra_versandkosten>
                <versandaufschlag_mf><to_invoice>*</to_invoice><to_cm>*</to_cm></versandaufschlag_mf>
            </sales_convert_order>
        </fieldsets>
        <sales>
            <quote>
                <totals>
                    <extra_versandkosten>
                        <class>versandaufpreis/quote_address_total_shipping_surcharge</class>
                        <after>nominal,subtotal,freeshipping</after>
                        <before>shipping,tax_subtotal,tax_shipping,weee,phoenix_cashondelivery,discount,phoenix_cashondelivery_tax,grand_total,msrp,tax</before>
                    </extra_versandkosten>
                </totals>
        <item>
          <product_attributes>
            <versandaufschlag_mf/>
          </product_attributes>
        </item>
            </quote>
            <order_invoice>
                <totals>
                    <extra_versandkosten>
                        <class>versandaufpreis/order_invoice_total_shipping_surcharge</class>
                        <after>nominal,subtotal,freeshipping</after>
                        <before>shipping,tax_subtotal,tax_shipping,weee,phoenix_cashondelivery,discount,phoenix_cashondelivery_tax,grand_total,msrp,tax</before>
                    </extra_versandkosten>
                </totals>
            </order_invoice>
            <order_creditmemo>
                <totals>
                    <extra_versandkosten>
                        <class>versandaufpreis/order_creditmemo_total_shipping_surcharge</class>
                        <after>nominal,subtotal,freeshipping</after>
                        <before>shipping,tax_subtotal,tax_shipping,weee,phoenix_cashondelivery,discount,phoenix_cashondelivery_tax,grand_total,msrp,tax</before>
                    </extra_versandkosten>
                </totals>
            </order_creditmemo>
        </sales>
        <pdf>
            <totals>
                <extra_versandkosten translate="title">
                    <title>Versandaufpreis</title>
                    <source_field>extra_versandkosten</source_field>
                    <font_size>7</font_size>
                    <display_zero>0</display_zero>
                    <sort_order>450</sort_order>
                </extra_versandkosten>
            </totals>
        </pdf>
    </global>

    <frontend>
        <events>
            <sales_quote_product_add_after>
                <observers>
                    <versandaufpreis>
                        <type>singleton</type>
                        <class>versandaufpreis/observer</class>
                        <method>salesQuoteProductAddAfter</method>
                    </versandaufpreis>
                </observers>
            </sales_quote_product_add_after>
            <sales_convert_quote_to_order>
                <observers>
                    <versandaufpreis>
                        <type>singleton</type>
                        <class>versandaufpreis/observer</class>
                        <method>salesConvertQuoteToOrder</method>
                    </versandaufpreis>
                </observers>
            </sales_convert_quote_to_order>
        </events>
        <layout>
            <updates>
                <versandaufpreis>
                    <file>versandaufpreis.xml</file>
                </versandaufpreis>
            </updates>
        </layout>
    </frontend>

    <adminhtml>
        <layout>
            <updates>
                <versandaufpreis>
                    <file>versandaufpreis.xml</file>
                </versandaufpreis>
            </updates>
        </layout>
    </adminhtml>

</config>

The order of $sortedOrderCollectors in Mage_Sales_Model_Config_Ordered is the following

Array
(
    [0] => nominal
    [1] => subtotal
    [2] => freeshipping
    [3] => extra_versandkosten
    [4] => tax_subtotal
    [5] => shipping
    [6] => tax_shipping
    [7] => weee
    [8] => discount
    [9] => phoenix_cashondelivery
    [10] => tax
    [11] => phoenix_cashondelivery_tax
    [12] => grand_total
    [13] => msrp
)

Best Answer

You have to check, whether the totals are in the correct order, because magento is sill buggy here.

Hook here in: \Mage_Sales_Model_Config_Ordered::_getSortedCollectorCodes and check wether the returned $sortedCollectors is in the correct order.

The problem is, magento doesn't sort correctly. If the order is wrong, add more totals to <before> and <after> node, until it works. You can just add more totals comma seperated like <before>tax,grand_total,subtotal</before>

Good luck!