In today lesson we will study Checkout Totals. Time length for this lesson is about 2-4 hours through the specific contents as follows:

  • Definition of custom total
  • Declaring a custom total to change (adjust) grand total of order when checkout
  • Creating Model to collect and fetch data for custom total
  • Creating block to show custom total on order view page (checkout page, view order in backend, new order email

Useful Resources for you:

Magestore’s Magento Tutorial Center

Magestore’s new Magento Tutorials help you to build your Store while you sleep.

The “must-have” extensions for your Magento 1 and Magento 2 Store

1. Definition of custom total

The custom total is a kind of fee or discount added to grand total value of order when checkout.

The custom total appears in order review pages.

custom total definition
Shopping Cart page
custom totals in magento
Order in frontend
checkout totals
Order in backend

2. Declaring custom total

Add this XML code to config file of module:

app/code/local/Magestore/Lesson23/etc/config.xml (Magestore is namespace and Lesson23 is module name)

<config>
…
<global>
…
<sales>
<quote>
<totals>
<lesson23>
<class>lesson23/total_address_lesson23</class>
<after>discount</after>
<before>tax</before>
</lesson23>
</totals>
</quote>
</sales>
…
</global>
…
</config>
  • <quote> is the object added custom total
  • <class>lesson23/total_address_lesson23</class> is model which collects and fetches data for custom total
  • <after>discount</after> and <before>tax</before> is method to set order of custom total. In this example, custom total is collected and shown before tax and after discount. Other Magento totals are wee, tax_subtotal, sub_total, grand_total and shipping.

And this is a bonus: Download a free guide that will show you 21-point Magento 2 Pre launch checklist.

3. Creating model to collect and fetch data for custom total

3.1. Address Total

Address Total is added to object Quote. It is calculated and shown before object Order is created.

Model of Address Total calculates value of custom total from data of object Quote and returns value and label of custom total.

Process to create model total:

  • Create file app/code/local/Magestore/Lesson23/Model/Total/Address/Lesson23.php
  • Declare class Magestore_Lesson23_Model_Total_Address_Lesson23 which extends from Mage_Sales_Model_Quote_Address_Total_Abstract
  • Declare function collect() as follows:
class Magestore_Lesson23_Model_Total_Address_Lesson23 extends Mage_Sales_Model_Quote_Address_Total_Abstract
{
public function __construct()
{
$this->setCode('lesson23_discount');
}

public function collect(Mage_Sales_Model_Quote_Address $address)
{
$quote = $address->getQuote();
if (!$quote->isVirtual() && $address->getAddressType() == 'billing'){
return $this;
}

$items = $address->getAllItems();
$baseDiscount = count($items) * 5;
$discount = Mage::app()->getStore()->convertPrice($baseDiscount);
$address->setBaseLesson23Discount(-$baseDiscount);
$address->setLesson23Discount(-$discount);

$address->setBaseGrandTotal($address->getBaseGrandTotal() - $baseDiscount);
$address->setGrandTotal($address->getGrandTotal() - $discount);

return $this;
}
}

In this example, I create $5 discount for each item in cart:

$baseDiscount = count($items) * 5;

Update grand total value

$address->setBaseGrandTotal($address->getBaseGrandTotal() - $baseDiscount);

Note: I use two variables to save discount value $baseDiscount and $discount. $baseDiscount is calculated according to base currency. And $discount is calculated according to current currency. You can convert value of these variables with the following function: 

$discount = Mage::app()->getStore()->convertPrice($baseDiscount);

  • Declare function fetch()

public function fetch(Mage_Sales_Model_Quote_Address $address){
$amount = $address->getLesson23Discount();
$title = Mage::helper('lesson23')->__('Lesson23 Discount');
if ($amount != 0){
$address->addTotal(array(
'code' => $this->getCode(),
'title' => $title,
'value' => $amount,
));
}
return $this;
}

This function gets discount value calculated in collect(), then add total to object $address. Title and Value are values printed in Shopping Cart and Checkout page.

3.2. Saving Address Total value in table Sales_flat_order

After user places order, we save this custom total value in table sales_flat_order:

  • Add two attributes base_lession23_discount and lesson23_discount to table sales_flat_order.Add the below function to file setup of module: /sql/lesson23_setup/mysql4-install-0.1.0.php

$installer->run("

ALTER TABLE {$this->getTable('sales/order')}

ADD COLUMN `lesson23_discount` decimal(12,4) default NULL,

ADD COLUMN `base_lesson23_discount` decimal(12,4) default NULL;

");
  • Declare attributes converted from object Quote to object Order in config.xml file of  module
<config>
…
<global>
…
<fieldsets>
<sales_convert_quote_address>
<base_lesson23_discount>
<to_order>*</to_order>
</base_lesson23_discount>
<lesson23_discount>
<to_order>*</to_order>
</lesson23_discount>
</sales_convert_quote_address>
</fieldsets>
…
</global>

…

</config>

After placing order, base_lesson23_discount value and lesson23_discount value we have added to object $address in model Magestore_Lesson23_Model_Total_Address_Lesson23 will be copied to Order object and saved in correspondent attributes in table sales_flat_order.

4. Creating block to display custom total on order view page

4.1. Displaying custom total in frontend

To display custom total values on order review page and email, add declaration in layout file and create more blocks:

  • Declare in layout (app/design/frontend/default/default/layout/lesson23.xml)
<layout>
…
<sales_order_view>
<reference name="order_totals">
<block type="lesson23/sales_ordertotal" />
</reference>
</sales_order_view>

<sales_order_print>
<reference name="order_totals">
<block type="lesson23/sales_ordertotal" />
</reference>
</sales_order_print>

<sales_email_order_items>
<reference name="order_totals">
<block type="lesson23/sales_ordertotal" />
</reference>
</sales_email_order_items>
…
</layout>
  • Create block displaying custom total: Add file app/code/local/Magestore/Block/Sales/Ordertotal.php

class Magestore_Lesson23_Block_Sales_Ordertotal extends Mage_Sales_Block_Order_Totals
{
public function getLesson23Discount(){
$order = $this->getOrder();
return $order->getLesson23Discount();
}

public function getBaseLesson23Discount(){
$order = $this->getOrder();
return $order->getBaseLesson23Discount();
}

public function initTotals(){
$amount = $this->getLesson23Discount();
if(floatval($amount)){
$total = new Varien_Object();
$total->setCode('Lesson23_discount');
$total->setValue($amount);
$total->setBaseValue($this->getBaseLesson23Discount());
$total->setLabel('Lesson23 Discount');
$parent = $this->getParentBlock();
$parent->addTotal($total,'subtotal');
}
}

public function getOrder(){
if(!$this->hasData('order')){
$order = $this->getParentBlock()->getOrder();
$this->setData('order',$order);
}
return $this->getData('order');
}
}

4.2. Displaying custom total in backend

Follow the same steps as in section 4.1.

  • Declare in layout (app/design/adminhtml/default/default/layout/lesson23.xml)

<layout>
…
<adminhtml_sales_order_view>
<reference name="order_totals">
<block type="lesson23/sales_ordertotal" />
</reference>
</adminhtml_sales_order_view>
…
</layout>
  • Block displaying custom total: Use block displaying custom total in frontend Magestore_Lesson23_Block_Sales_Ordertotal

So, lesson 23 ends here, next week we will learn lesson 24 with how to add custom total to Invoice and Creditmemo. Enjoy coding and see you later. Follow us in Magento Open Course for Magento Tutorial.

Author

Alex is the CTO & Co-founder of Magestore which has been providing retail solutions for Magento merchants since 2009. He started as a Magento developer just one year after the release of the first version of Magento. With over 10 years experience of working with Magento and clients all over the world, he gained great knowledge on e-commerce development, order management systems, inventory control & retail POS.

2 Comments

Write A Comment