In this article I will show how to add a new Total row e.g. "Insurance" to Magento Shopping cart / Checkout.
Example:
If you need to add an additional fee to your total price, you need to add your own total item to the collection of totals.
To do this you need to add the following code to your main config.xml file:
<global> <sales> <quote> <totals> <turnkeye_insurance> <class>turnkeye_insurance/total_screen_quote</class> <after>subtotal</after> <before>tax</before> </turnkeye_insurance> </totals> </quote> <order_invoice> <totals> <turnkeye_insurance> <class>turnkeye_insurance/total_screen_invoice</class> <after>subtotal</after> <before>tax</before> </turnkeye_insurance> </totals> </order_invoice> <order_creditmemo> <totals> <turnkeye_insurance> <class>turnkeye_insurance/total_screen_creditmemo</class> <after>subtotal</after> <before>tax</before> </turnkeye_insurance> </totals> </order_creditmemo> </sales> </global>
Here we declare "total items" in 3 collections in Magento system: 1 - quote, 2 - invoice and 3 - creditmemo.
So the total price of the quote, invoice and creditmemo will have additional fee (which you will add in the corresponded classes).
In this config we can inform Magento in which order our total will be calculated, so you can calculate something after shipping or tax calculation stage. E.g. if you will need shipping or tax cost in your further calculations. However, it does not affect the order of totals in customer front-end. To change the position of the total in the totals table, you need to insert this code:
<default> <sales> <totals_sort> <turnkeye_insurance>15</turnkeye_insurance> </totals_sort> </sales> </default>
First class is 'turnkeye_insurance/total_insurance_quote':
class Turnkeye_Insurance_Model_Total_Insurance_Quote extends Mage_Sales_Model_Quote_Address_Total_Abstract { public function __construct() { $this->setCode('turnkeye_insurance'); } /** * Get label * * @return string */ public function getLabel() { return Mage::helper('turnkeye_insurance')->__('Insurance'); } /** * Collect totals information about insurance * * @param Mage_Sales_Model_Quote_Address $address */ public function collect(Mage_Sales_Model_Quote_Address $address) { parent::collect($address); if (($address->getAddressType() == 'billing')) { return $this; } $amount = INSURANCE_FEE; if ($amount) { $this->_addAmount($amount); $this->_addBaseAmount($amount); } return $this; } /** * Add giftcard totals information to address object * * @param Mage_Sales_Model_Quote_Address $address */ public function fetch(Mage_Sales_Model_Quote_Address $address) { if (($address->getAddressType() == 'billing')) { $amount = INSURANCE_FEE; if ($amount != 0) { $address->addTotal(array( 'code' => $this->getCode(), 'title' => $this->getLabel(), 'value' => $amount )); } } return $this; } }
Total collection is calculated for each address in the quote, that is why we need to add our fee only if we calculate total for billing address, in other case the fee will be added twice. Also if you have multi-currency store you will need to calculate base amount with rate and after that add this amount to base total.
Invoice and creditmemo total classes are very similar:
class Turnkeye_Insurance_Model_Total_Insurance_Creditmemo extends Mage_Sales_Model_Order_Creditmemo_Total_Abstract { public function collect(Mage_Sales_Model_Order_Creditmemo $creditmemo) { $order = $creditmemo->getOrder(); $amount = INSURANCE_FEE; if ($amount) { $creditmemo->setGrandTotal($creditmemo->getGrandTotal() + $amount); $creditmemo->setBaseGrandTotal($creditmemo->getBaseGrandTotal() + $amount); } return $this; } }
class Turnkeye_Insurance_Model_Total_Screen_Invoice extends Mage_Sales_Model_Order_Invoice_Total_Abstract { public function collect(Mage_Sales_Model_Order_Invoice $invoice) { $order = $invoice->getOrder(); $amount = INSURANCE_FEE; if ($amount) { $invoice->setGrandTotal($invoice->getGrandTotal() + $amount); $invoice->setBaseGrandTotal($invoice->getBaseGrandTotal() + $amount); } return $this; } }
Here we need to add a fee, so the total value will be the same as in the order. There is one thing which you should keep in mind: invoice and creditmemo can be partial, in this case if your total fee linked with items price you will need to calculate you fee based on invoiced/refunded items.
After that the total price will be calculated with your fee, but you will not see your total row anywhere except cart/checkout page. So there are 3 blocks (order, invoice, creditmemo) where you need to add your total, we need to rewrite it:
<blocks> <adminhtml> <rewrite> <sales_order_totals>Turnkeye_Insurance_RW_Adminhtml_Block_Sales_Order_Totals</sales_order_totals> <sales_order_invoice_totals>Turnkeye_Insurance_RW_Adminhtml_Block_Sales_Order_Invoice_Totals</sales_order_invoice_totals> <sales_order_creditmemo_totals>Turnkeye_Insurance_RW_Adminhtml_Block_Sales_Order_Creditmemo_Totals</sales_order_creditmemo_totals> </rewrite> </adminhtml> </blocks>
These classes are very similar:
class Turnkeye_Insurance_RW_Adminhtml_Block_Sales_Order_Totals extends Mage_Adminhtml_Block_Sales_Order_Totals { /** * Initialize order totals array * * @return Mage_Sales_Block_Order_Totals */ protected function _initTotals() { parent::_initTotals(); $amount = INSURANCE_FEE; if ($amount) { $this->addTotalBefore(new Varien_Object(array( 'code' => 'turnkeye_insurance', 'value' => $amount, 'base_value'=> $amount, 'label' => $this->helper('turnkeye_insurance')->__('Insurance'), ), array('shipping', 'tax'))); } return $this; } }
class Turnkeye_Insurance_RW_Adminhtml_Block_Sales_Order_Creditmemo_Totals extends Mage_Adminhtml_Block_Sales_Order_Creditmemo_Totals { /** * Initialize order totals array * * @return Mage_Sales_Block_Order_Totals */ protected function _initTotals() { parent::_initTotals(); $amount = INSURANCE_FEE; if ($amount) { $this->addTotalBefore(new Varien_Object(array( 'code' => 'turnkeye_insurance', 'value' => $amount, 'base_value'=> $amount, 'label' => $this->helper('turnkeye_insurance')->__('Insurance'), ), array('shipping', 'tax'))); } return $this; } }
class Turnkeye_Insurance_RW_Adminhtml_Block_Sales_Order_Invoice_Totals extends Mage_Adminhtml_Block_Sales_Order_Invoice_Totals { /** * Initialize order totals array * * @return Mage_Sales_Block_Order_Totals */ protected function _initTotals() { parent::_initTotals(); $amount = INSURANCE_FEE; if ($amount) { $this->addTotalBefore(new Varien_Object(array( 'code' => 'turnkeye_insurance', 'value' => $amount, 'base_value'=> $amount, 'label' => $this->helper('turnkeye_insurance')->__('Insurance'), ), array('shipping', 'tax'))); } return $this; } }
After that you will see new row in totals with "Insurance" value in the admin area. You need to do the same for blocks in frontend: 'sales/order_totals', 'sales/order_invoice_totals' and 'sales/order_creditmemo_totals'. After that you will see your row with a fee on frontend and backend.
If you use PayPal payment method you need to add your fee to PayPal request, in other case you will see error that total amount is not sum of items price and you will not be able to place order. To solve this just add your observer for 'paypal_prepare_line_items' event:
<events> <paypal_prepare_line_items> <observers> <turnkeye_insurance> <type>singleton</type> <class>turnkeye_insurance/observer</class> <method>addScreenToPayPal</method> </turnkeye_insurance> </observers> </paypal_prepare_line_items> </events>
The method which add your fee to PayPal request is:
public function addScreenToPayPal($observer) { $paypal_cart = $observer->getPaypalCart(); if ($paypal_cart && $paypal_cart->getSalesEntity()) { $amount = INSURANCE_FEE; if ($amount) { $paypal_cart->addItem(Mage::helper('turnkeye_insurance')->__('Insurance'), 1, $amount, 'insurance'); } } }
Finally, you can change INSURANCE_FEE in our example to any amount you need or better to change it to helper method with quote/order parameter. Also we recommend to store the fee value you want to apply to the orders in the database and use this value for creditmemo/invoices/order.
How to add new row for "Insurance" in Customer Order History view page and Customer sales order Email
I am using 1.7.0.2 & above code is not working when with paypal express checkout when applied tax to the product. Any idea about this?
Thanks in advance.
I didn't test your solution but I have a question. Is your total taxed ?
I created a module doing approximatively the same, add a new total for insurance to my checkout.
This total have a 19.6% tax applied. It's working well on the store in which I need it. But it cause problem on another store. A B2B store where price are configured excluding tax. I don't use insurance in this store, so the total insurance and total tax_insurance is always 0. But with this module orders are made excluding tax.
I.E you order a 100€ product. You should have 19.6€ tax and a total including tax at 119.6€. Since I installed this module I have my total including tax set to 100€ and my total excluding tax set to 80.4€... This was working fine in the past this problem occurs since I moved to from Magento CE 1.4.1 to Magento CE 1.7.0.2
You should add new field to the template and to the controller which save this field.
Also edit the total calculation logic in the controller using the value you send to it.
I want have a textbox in create order on admin panel, when i enter price to that textbox, this order will add INSURANCE_FEE to total section.
please help me this
We do not modify any files actually, we create new extension here. You can find more information about modules creation for Magento here:
http://www.slideshare.net/ceefour/how-to-develop-a-basic-magento-extension-tutorial
Hello Gabriel,
I recommend to contact our support team here: http://turnkeye.com/contact_us.html
Look if these steps could help me
I´m trying to add a tax for each different type of payment.
If customer choice Check / Money Order, He receive 5% off.
If customer choice Credit, He pay 5% under the final price.
and more about the others payment methods.
I will study your steps now... Please, help me =)
and sorry, my english is not so good =x
Thanks!