How to add fee to order totals in magento 2
This Blog helps 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 user like gift-wrapping, cash on delivery, payment method, rush delivery, payment fee etc...
For This Solution we have also created our Magento Extension Named MageAnts Magento 2 Extra Fee.
To add fee to order total programatically you have to follow below steps : -
Step : 1
Now You have to update module.xml at 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
First of all you have to create Sales.xml in your etc folder at below path
app/code/Mageants/Fee/etc/sales.xml
After creating file you have to put below code.
<?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 kind of total objects like discount, subtotal, grandtotal, tax which display on cart page or order details page in admin or frontend and many more places. we can say everthing that is related to total in quote or order defines in this file.
Step : 3
Now You have to define fee.php at 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); } /** * @param \Magento\Quote\Model\Quote $quote * @param Address\Total $total * return array|null */ /** * 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
Now You have to define fee.html at 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 --> |
Step : 5
Now You have to define fee.html at 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 : 6
Now You have to define fee.js at 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; } }); } ); |
Step : 7
Now You have to define fee.js at 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()); } }); } ); |
Step : 8
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> |
Step : 9
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> |
Step : 10
Now You have to define sales_order_view.xml at below path and put below code.
app/code/Mageants/Fee/view/frontend/layout/sales_order_view.xml
<?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 : 11
Now You have to define Fee.php at 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; } } |
Frontend Screen Shots : -
1) View And Edit Cart Page : -
2) Checkout Page : -
3) In Customer Account My Order Page : -
Conclusion:
That’s All, By Following the Steps of this blog you can easily add extra fees to your order totals.
We have displayed frontend Screen shots as well so you can see where the actuall fee will be displayed.
We hope that this tutorial is helpful and you can follow it easily.