Magento 2: Add Extra Fee To Order Totals

Sometimes we might need to add an extra fee ( i.e, Handling Fee ) to order total in Magento 2. Generally, the order totals comprise of subtotal, shipping cost, taxes, and discount, based on these values the grand total will be calculated. Now, if we want to add an extra fee it will affect the order grand total. In this article, we will guide you how to add an extra fee to your Magento 2 order without any issues.

Here we are going to add a new order total called Handling Fee with a fixed cost of $10.

Step 1: Define new module,

To create a new module in Magento 2, first create a XML file named module.xml like a below file path to define the new module,

Saple File Path: app/code/MyModule/HandlingFee/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="MyModule_HandlingFee" setup_version="1.0.0">
    </module>
</config>

Next, create a PHP file named registration.php like a below file path,

Sample File Path: app/code/MyModule/HandlingFee/registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'MyModule_HandlingFee',
    __DIR__
);

Step 2: Create sales.xml,

Create a XML file name sales.xml in the following path to define extra fee model,

Sample File Path: app/code/MyModule/HandlingFee/etc/sales.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Sales:etc/sales.xsd">
    <section name="quote">
        <group name="totals">
            <item name="handlingfee" instance="MyModule\HandlingFee\Model\Quote\Address\Total\HandlingFee" sort_order="400"/>
        </group>
    </section>
</config>

Step 3: Create HandlingFee.php

Create a PHP file named HandlingFee.php in the following path, where the handling fee will be added to the order totals,

Sample File Path: app/code/MyModule/HandlingFee/Model/Quote/Address/Total/HandlingFee.php

<?php
namespace MyModule\HandlingFee\Model\Quote\Address\Total;
class HandlingFee extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
{
    /**
     * @var \Magento\Framework\Pricing\PriceCurrencyInterface
     */
    protected $_priceCurrency;

    /**
     * @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
     */
    public function __construct(
        \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
    ) {
        $this->_priceCurrency = $priceCurrency;
    }
    
    /**
     * @param \Magento\Quote\Model\Quote $quote
     * @param \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment
     * @param \Magento\Quote\Model\Quote\Address\Total $total
     * @return $this|HandlingFee
     */
    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);
        $handlingFee = 10;
        $total->addTotalAmount('handlingfee', $handlingFee);
        $total->addBaseTotalAmount('handlingfee', $handlingFee);
        $quote->setHandlingFee($handlingFee);
        return $this;
    }

    /**
     * @param \Magento\Quote\Model\Quote $quote
     * @param \Magento\Quote\Model\Quote\Address\Total $total
     * @return array
     */
    public function fetch(
        \Magento\Quote\Model\Quote $quote,
        \Magento\Quote\Model\Quote\Address\Total $total
    ) {
        return [
            'code' => 'Handling_Fee',
            'title' => $this->getLabel(),
            'value' => 10
        ];
    }

    /**
     * get label
     * @return string
     */
    public function getLabel() {
        return __('Handling Fee');
    }
}

Step 4: Create checkout_cart_index.xml

Create a XML file checkout_cart_index.xml in the following path, this file is used to add handling fee view in cart page layout.

Sample File Path: app/code/MyModule/HandlingFee/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">
                                <item name="handlingfee" xsi:type="array">
                                    <item name="component" xsi:type="string">MyModule_HandlingFee/js/view/checkout/summary/handling-fee</item>
                                    <item name="sortOrder" xsi:type="string">20</item>
                                    <item name="config" xsi:type="array">
                                        <item name="handlingfee" xsi:type="string" translate="true">Handling Fee</item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Step 5: Create checkout_index_index.xml

Create a XML file checkout_index_index.xml in the same path, this file is used to add handling fee view in checkout page layout.

Sample File Path: app/code/MyModule/HandlingFee/view/frontend/layout/checkout_index_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.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">
                                                        <item name="handlingfee" xsi:type="array">
                                                            <item name="component" xsi:type="string">MyModule_HandlingFee/js/view/checkout/cart/totals/handling-fee</item>
                                                            <item name="sortOrder" xsi:type="string">20</item>
                                                            <item name="config" xsi:type="array">
                                                                <item name="template" xsi:type="string">MyModule_HandlingFee/checkout/cart/totals/handling-fee</item>
                                                                <item name="title" xsi:type="string" translate="true">Handling Fee</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>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

Step 6: Create handling-fee.js

Create a JS file named handling-fee.js in the following file path, which is used to display the handling fee in cart summary section.

Sample File Path: app/code/MyModule/HandlingFee/view/frontend/web/js/view/checkout/cart/totals/handling-fee.js

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

Step 7: Create handling-fee.js

Create another JS file with the same name handling-fee.js in the following path, which is used to display the handling fee in checkout review section.

Sample File Path: app/code/MyModule/HandlingFee/view/frontend/web/js/view/checkout/summary/handling-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: 'MyModule_HandlingFee/checkout/summary/handling-fee'
            },
            totals: quote.getTotals(),
            isDisplayedHandlingfeeTotal : function () {
                return true;
            },
            getHandlingfeeTotal : function () {
                var price = 10;
                return this.getFormattedPrice(price);
            }
        });
    }
);

Step 8: Create handling-fee.html

Create a HTML file named handling-fee.html in the following file path to display the handling fee in the cart page,

Sample File Path: app/code/MyModule/HandlingFee/view/frontend/web/template/checkout/cart/totals/handling-fee.html

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

Step 9: Create handling-fee.html

Create a HTML file named handling-fee.html in the following file path to display the handling fee in the checkout page,

Sample File Path: app/code/MyModule/HandlingFee/view/frontend/web/template/checkout/summary/handling-fee.html

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

After completing all the above steps, you can see the extra fee on your cart and checkout page.

Reference image:

Magento 2: Add Extra Fee To Order Totals

Hope this helps.

5 Comments on “Magento 2: Add Extra Fee To Order Totals”

  1. Hello,
    Great article ! Very helpful for adding extra fee at checkout page. However, can we modify this extension so that customer can choose whether they need to pay extra fee or not, it seems like the customer will not have a choice with this.


    Thank You

  2. Hi,

    Great article. I have implemented it. It works fine. But you have misses something.
    When order is complete. Then fee is not showing in customer’s order page (/sales/order/view/order_id/{{$id}}/ )
    Also additional fee section is not available in admin as well.

    It is missing in email too.

    But final calculation is correct.

  3. Helpful tutorial, but I would like to see the handling fee added to the cart totals/quote model responses from an API REST call. Only time I see this is from the total segments object array thanks to the Fetch method.

  4. I have build the same module.but not working.extra fees is not showing on frontend and the error is also not showing.

    1. Hi,

      Thanks for reading our blog. If you used and third party modules to override the checkout process, it may conflict. Can you please specify your Magento version and the third party modules if you used.

Leave a Reply

Your email address will not be published. Required fields are marked *