Sometimes we need to modify the totals of transactions in Magento, to add extra fees or extra discounts. Totals are the calculation of the product, shipping costs, taxes, discounts, etc.

In this article, we will show you how to modify totals by adding total collectors to the calculation process.

Steps to create a new item in quote total calculation from declaration to display would consist of the following steps:

  • Step 1: Declare A Total Collector
  • Step 2: Implement The Total Collector Class
  • Step 3: Modify Cart Layout
  • Step 4: Modify Checkout Layout
  • Step 5: Create Js Components For Total Item
  • Step 6: Create Templates For Total Item

1. Declare a Total Collector

Collectors are declared in app/code/Vendor/Module/etc/sales.xml :

<?xml version="1.0"?>
<config>
<section name="quote">
        <group name="totals">
            <item name="discount" instance="Vendor\Module\Model\Total\Quote\Custom" sort_order="300"/>
        </group>
 </section>
</config>

Here we’ve added a total item for quote section. Possible sections include “quote”, “order_invoice”, “order_creditmemo”.

  • instance”: the class to handle the calculation and collection of this item.
  • sort_order”: the order in which the item will be collected. 

2. Implement The Total Collector Class

Here we specify Vendor\Module\Model\Totals\Custom class as a model of our custom total collector. 

This class must extend the Magento\Quote\Model\Quote\Address\Total\AbstractTotal and implement the collect and fetch methods. 

The collect method is used to calculate the value of our total, while the fetch method returns the result along with the total collector’s code and its name.

For this example we’ll add a collector for ‘discount’ adding 10% discount to quote total:

class Custom extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal {

public function collect(
        \Magento\Quote\Model\Quote $quote,
        \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment,
        \Magento\Quote\Model\Quote\Address\Total $total
    ) {
        parent::collect($quote, $shippingAssignment, $total);
        
       $discount = 0.1 * $quote->getGrandTotal();
       $total->addTotalAmount($this->getCode(), -$discount);
        $total->addBaseTotalAmount($this->getCode(), -$discount);
        $quote->setDiscount($discount);

      return $this;
    }
 
    public function fetch(
        \Magento\Quote\Model\Quote $quote,
        \Magento\Quote\Model\Quote\Address\Total $total
    ) {
       $discount = 0.1 * $quote->getGrandTotal();
        return [
            'code' => $this->getCode(),
            'title' => $this->getLabel(),
            'value' => -$discount  //You can change the reduced amount, or replace it with your own variable
        ];
  	  }
}

3. Modify Cart Layout

To add the new total item to cart layout, we need to create the file Vendor/Module/view/frontend/layout/checkout_cart_index.xml :

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="checkout.cart.totals">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="block-totals" xsi:type="array">
                            <item name="children" xsi:type="array">
<!-- Start of the main content that needs to be added-->
                                <item name="discount" xsi:type="array">
<!-- The path to our js file-->
                                    <item name="component" xsi:type="string">Vendor_Module/js/view/checkout/summary/discount-fee</item>
                                    <item name="sortOrder" xsi:type="string">20</item>
                                    <item name="config" xsi:type="array">
<!-- Show custom discount on order summary-->
                                       <item name="discount" xsi:type="string" translate="true">Custom Discount</item>
                                    </item>
                                </item>
<!--  End-->
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

4. Modify Checkout Layout

Just like the previous step, we need to add the discount item to the checkout layout. Create the file Vendor/Module/view/frontend/layout/checkout_index_index.xml :

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="checkout.root">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="checkout" xsi:type="array">
                            <item name="children" xsi:type="array">
                                <item name="sidebar" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="summary" xsi:type="array">
                                            <item name="children" xsi:type="array">
                                                <item name="totals" xsi:type="array">
                                                    <item name="children" xsi:type="array">
<!--  Start of the main content that needs to be added-->
                                                        <item name="discount" xsi:type="array">
<!-- The path to our js file-->
                                                            <item name="component" xsi:type="string">Vendor_Module/js/view/checkout/cart/totals/discount</item>
                                                            <item name="sortOrder" xsi:type="string">20</item>
                                                            <item name="config" xsi:type="array">
                                                                <item name="template" xsi:type="string">Vendor_Module/checkout/cart/totals/discount</item>
<!--  Show custom discount on order summary-->
                                                                <item name="title" xsi:type="string" translate="true">Custom Discount</item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                                <item name="cart_items" xsi:type="array">
                                                    <item name="children" xsi:type="array">
                                                        <item name="details" xsi:type="array">
                                                            <item name="children" xsi:type="array">
                                                                <item name="subtotal" xsi:type="array">
                                                                    <item name="component" xsi:type="string">Magento_Tax/js/view/checkout/summary/item/details/subtotal</item>
                                                                </item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
<!--  End-->
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

5. Create JS Components For Total Item

Create the file Vendor/Module/view/frontend/web/js/view/checkout/cart/totals/discount.js :

define(
   [
       ‘Vendor_Module’/js/view/checkout/summary/discount-fee'
   ],
   function (Component) {
       'use strict';
       return Component.extend({
           /**
            * @override
            */
           isDisplayed: function () {
               return true;
           }
       });
   }
);

and Vendor/Module/view/frontend/web/js/view/checkout/summary/discount-fee.js :

define(
   [
       'jquery',
       'Magento_Checkout/js/view/summary/abstract-total',
       'Magento_Checkout/js/model/quote',
       'Magento_Checkout/js/model/totals',
       'Magento_Catalog/js/price-utils'
   ],
   function ($,Component,quote,totals,priceUtils) {
       "use strict";
       return Component.extend({
           defaults: {
               template: ‘Vendor_Module’/checkout/summary/discount-fee'
           },
           totals: quote.getTotals(),
           isDisplayedDiscountTotal : function () {
               return true;
           },
           getDiscountTotal : function () {
               var price = totals.getSegment('discount').value;
               return this.getFormattedPrice(price);
           }
       });
   }
);

6. Create Templates For Total Item

For this step we’ll create HTML templates to display the discount on cart and checkout pages:

a/ Create Vendor/Module/view/frontend/web/template/checkout/cart/totals/discount.html

<!-- ko if: isDisplayedDiscountTotal() -->
<tr class="totals discount excl">
   <th class="mark" colspan="1" scope="row" data-bind="text: title"></th>
   <td class="amount">
       <span class="price" data-bind="text: getDiscountTotal()"></span>
   </td>
</tr>
<!-- /ko -->

b/ Create Vendor/Module/view/frontend/web/template/checkout/summary/discount-fee.html

<!-- ko if: isDisplayedDiscountTotal() -->
<tr class="totals coupon-fee excl">
   <th class="mark" colspan="1" scope="row" data-bind="text: discount"></th>
   <td class="amount">
       <span class="price" data-bind="text: getDiscountTotal(), attr: {'data-th': discount}"></span>
   </td>
</tr>
<!-- /ko →

Here’s our result:

You can download example Magenest_Discount module here.