This blog helps magento 2 store owners to add extra charges for different services and display them on the checkout page.
By adding extra fees owners can provide many different services to users like gift-wrapping, cash on delivery, payment method, rush delivery, payment fee, etc.
For this solution we have also created our Magento 2 Extension named MageAnts Magento 2 Extra Fee.
This guide walks you through each step of the process to add fees on Magento 2 checkout, with clear instructions, code snippets, and frontend output examples.
Let’s dive in!
11 Simple Steps to Add Extra Fee to Order Totals Programmatically in Magento 2
Step 1. Configure module.xml for Your Custom Module
Now you have to update module.xml at the below path as below code:
app/code/Mageants/Fee/etc/module.xml
Note: You just have to change your Vendor_Name and Module_Name from below code, here Vendor_Name is Mageants and Module_Name is Fee.
<?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="Mageants_Fee" setup_version="1.0.0">
<sequence>
<module name=="Magento_Sales"/>
<module name="Magento_Quote"/>
<module name="Magento_Checkout"/>
</sequence>
</module>
</config>
|
Step 2: Define Sales.xml for Total Calculations
First of all, we’ll define where the new fee fits into the total calculations:
Create the file at:
app/code/Mageants/Fee/etc/sales.xml
Add the following:
<?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="fee" instance="Mageants\Fee\Model\Total\Fee"sort_order="150"/>
<group>
<section>
</config>
|
In Magento, sales.xml contains all kinds of total objects like discount, subtotal, grand total, tax which display on cart page or order details page in admin or frontend and many more places. We can say everything that is related to total in quote or order defined in this file.
Step 3: Create the fee.php Model for Order Totals
Now you have to define fee.php at the below path and put below code:
app/code/Mageants/Fee/Model/Total/Fee.php
<?php
namespace Mageants\Fee\Model\Total;
class Fee extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
{
/**
* Collect grand total address amount
*
* @param \Magento\Quote\Model\Quote $quote
* @param \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment
* @param \Magento\Quote\Model\Quote\Address\Total $total
* @return $this
*/
protected $quoteValidator = null;
public function __construct(
\Magento\Quote\Model\QuoteValidator $quoteValidator
) {
$this->quoteValidator = $quoteValidator;
}
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);
$exist_amount = 0;
$fee = 10;
$balance = $fee - $exist_amount;
$total->setTotalAmount('fee', $balance);
$total->setBaseTotalAmount('fee', $balance);
$total->setFee($balance);
$total->setBaseFee($balance);
$total->setGrandTotal($total->getGrandTotal());
$total->setBaseGrandTotal($total->getBaseGrandTotal());
return $this;
}
protected function clearValues(Address\Total $total)
{
$total->setTotalAmount('subtotal', 0);
$total->setBaseTotalAmount('subtotal', 0);
$total->setTotalAmount('tax', 0);
$total->setBaseTotalAmount('tax', 0);
$total->setTotalAmount('discount_tax_compensation', 0);
$total->setBaseTotalAmount('discount_tax_compensation', 0);
$total->setTotalAmount('shipping_discount_tax_compensation', 0);
$total->setBaseTotalAmount('shipping_discount_tax_compensation', 0);
$total->setSubtotalInclTax(0);
$total->setBaseSubtotalInclTax(0);
}
/**
* Assign subtotal amount and label to address object
*
* @param \Magento\Quote\Model\Quote $quote
* @param Address\Total $total
* @return array
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function fetch(
\Magento\Quote\Model\Quote $quote,
\Magento\Quote\Model\Quote\Address\Total $total
) {
return [
'code'=>'fee',
'title'=>'Custom Fee',
'value'=>10
];
}
/**
* Get Subtotal label
*
* @return \Magento\Framework\Phrase
*/
public function getLabel()
{
return __('Custom Fee');
}
}
|
Step 4: Add Frontend Templates
Now let’s show this fee visually!
fee.html for Checkout Summary
Now you have to define fee.html at the below path and put below code:
app/code/Mageants/Fee/view/frontend/web/template/checkout/summary/fee.html
<!-- ko -->
<tr class="border border-gray">
<th class="mark"scope="row">
<span class="label" data-bind="text: title"></span>
<span class="value" data-bind="text: getValue()"></span>
</th>
<td class="amount">
<span class="price"data-bind="text: getValue(), attr: {'data-th': title}"></span>
</td>
</tr>
<!-- /ko -->
|
fee.html for Cart Totals
Now you have to define fee.html at the below path and put below code:
app/code/Mageants/Fee/view/frontend/web/template/checkout/cart/totals/fee.html
<!-- ko -->
<tr class="border border-gray">
<th class="mark" colspan="1" scope="row" data-bind="text: title"></th>
<td class="amount">
<span class="price" data-bind="text: getValue()"></span>
</td>
</tr>
<!-- /ko -->
|
Step 5: Implement JavaScript for Dynamic Fee Display
This JS ensures the fee dynamically appears during checkout and cart updates.
fee.js for Cart Totals Component
Now you have to define fee.js at the below path and put below code:
app/code/Mageants/Fee/view/frontend/web/js/view/checkout/cart/totals/fee.js
define(
[
'Mageants_Fee/js/view/checkout/summary/fee'
],
function (Component) {
'use strict';
return Component.extend({
/**
* @override
*/
isDisplayed: function () {
return true;
}
});
}
);
|
fee.js for Checkout Summary Component
Now you have to define fee.js at the below path and put below code:
app/code/Mageants/Fee/view/frontend/web/js/view/checkout/summary/fee.js
/*jshint browser:true jquery:true*/
/*global alert*/
define(
[
'Magento_Checkout/js/view/summary/abstract-total',
'Magento_Checkout/js/model/quote',
'Magento_Catalog/js/price-utils',
'Magento_Checkout/js/model/totals'
],
function (Component, quote, priceUtils, totals) {
"use strict";
return Component.extend({
defaults: {
isFullTaxSummaryDisplayed: window.checkoutConfig.isFullTaxSummaryDisplayed || false,
template: 'Mageants_Fee/checkout/summary/fee'
},
totals: quote.getTotals(),
isTaxDisplayedInGrandTotal: window.checkoutConfig.includeTaxInGrandTotal || false,
isDisplayed: function() {
return this.isFullMode();
},
getValue: function() {
var price = 0;
if (this.totals()) {
price = totals.getSegment('fee').value;
}
return this.getFormattedPrice(price);
},
getBaseValue: function() {
var price = 0;
if (this.totals()) {
price = this.totals().base_fee;
}
return priceUtils.formatPrice(price, quote.getBasePriceFormat());
}
});
}
);
|
These files pull data dynamically and display your custom fee in real time.
Step 6: Modify Layout XML
To load the fee components into the layout, let’s update the layout XMLs.
Configure Cart Page Layout XML
Now you have to define checkout_cart_index.xml at below path and put below code:
app/code/Mageants/Fee/view/frontend/layout/checkout_cart_index.xml
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"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="fee" xsi:type="array">
<item name="component" xsi:type="string">Mageants_Fee/js/view/checkout/cart/totals/fee
</item>
<item name="sortOrder" xsi:type="string">20</item>
<item name="config" xsi:type="array">
<item name="template" xsi:type="string">
Mageants_Fee/checkout/cart/totals/fee
</item>
<item name="title" xsi:type="string"translate="true">Custom Fee</item>
</item>
</item>
</item>
</item>
</item>
</argument>
</arguments>
</referenceBlock>
</body>
</page>
|
Configure Checkout Page Layout XML
Now you have to define checkout_index_index.xml at below path and put below code:
app/code/Mageants/Fee/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="fee" xsi:type="array">
<item name="component"
xsi:type="string">
Mageants_Fee/js/view/checkout/cart/totals/fee
</item>
<item name="sortOrder" xsi:type="string">20</item>
<item name="config" xsi:type="array">
<item name="template"
xsi:type="string">
Mageants_Fee/checkout/cart/totals/fee
</item>
<item name="title" xsi:type="string"translate="true">Custom 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>
|
This step ensures your fee block is injected correctly into Magento’s checkout layout.
Step 7: Display Fee on Customer Order View
Now let’s make sure customers can see the fee in their "My Orders" section.
For that you have to define sales_order_view.xml at below path:
app/code/Mageants/Fee/view/frontend/layout/sales_order_view.xml
And insert the below code:
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="order_totals">
<block class="Mageants\Fee\Block\Sales\Order\Fee"name="fee"/>
</referenceContainer>
</body>
</page>
|
Step 8: Display Fees in Admin & Customer Order Views
Next, let’s create the PHP block that will handle rendering the custom fee.
Now you have to define Fee.php at the below path and put below code:
app/code/Mageants/Fee/Block/Sales/Order/Fee.php
<?php
namespace Mageants\Fee\Block\Sales\Order;
class Fee extends \Magento\Framework\View\Element\Template
{
/**
* Tax configuration model
*
* @var \Magento\Tax\Model\Config
*/
protected $_config;
/**
* @var Order
*/
protected $_order;
/**
* @var \Magento\Framework\DataObject
*/
protected $_source;
/**
* @param \Magento\Framework\View\Element\Template\Context $context
* @param \Magento\Tax\Model\Config $taxConfig
* @param array $data
*/
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
\Magento\Tax\Model\Config $taxConfig,
array $data = []
) {
$this->_config = $taxConfig;
parent::__construct($context, $data);
}
/**
* Check if we nedd display full tax total info
*
* @return bool
*/
public function displayFullSummary()
{
return true;
}
/**
* Get data (totals) source model
*
* @return \Magento\Framework\DataObject
*/
public function getSource()
{
return $this->_source;
}
public function getStore()
{
return $this->_order->getStore();
}
/**
* @return Order
*/
public function getOrder()
{
return $this->_order;
}
/**
* @return array
*/
public function getLabelProperties()
{
return $this->getParentBlock()->getLabelProperties();
}
/**
* @return array
*/
public function getValueProperties()
{
return $this->getParentBlock()->getValueProperties();
}
/**
* Initialize all order totals relates with tax
*
* @return \Magento\Tax\Block\Sales\Order\Tax
*/
public function initTotals()
{
$parent = $this->getParentBlock();
$this->_order = $parent->getOrder();
$this->_source = $parent->getSource();
$store = $this->getStore();
$fee = new \Magento\Framework\DataObject(
[
'code'=>'fee',
'strong'=>false,
'value'=>10,
'label'=>__('Custom Fee'),
]
);
$parent->addTotal($fee, 'fee');
return $this;
}
}
|
This ensures your custom fee appears not just in the frontend but also in the admin panel for easy order tracking.
Frontend Screenshots:
1) View And Edit Cart Page
Your fee shows clearly in the cart order total summary.
2) Checkout Page
Fee is included on the checkout page.
3) In Customer Account My Order Page
Customers can view fees in their order history under ‘My Orders.’
Conclusion
That’s it, following the steps of this blog you can easily add extra fees to your order totals.
We have displayed frontend screenshots as well so you can see where the actual fee will be displayed.
We hope that this tutorial is helpful and you can follow it easily.