How To Add Fees To Order Totals In Magento 2
If you are familiar with the way fees are added to order totals in Magento 1, you will have to master an absolutely different approach implemented in Magento 2. And below, we shed light on one of the possible ways to achieve this goal.
The desired functionality has been moved to the Quote module. You can create a new module that contains a “Fee” column. The concept of the module is described below.
The two core goals are to add a new row in “Cart Total” as well as a sidebar on the checkout page. Both elements are dedicated to fees. Besides, the fee amount is added to the total amount. Once a new order is placed, the total contains the fee. Note that the following module implements only the frontend functionality.
- Go to your module etc folder and create the sales.xml file there:
1 2 3 4 5 6 7 8 9 10 11 |
<?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="Sugarcode\Test\Model\Total\Fee" sort_order="150"/> </group> </section> </config> |
- Now, implement app\code\Sugarcode\Test\view\frontend\web\js\view\checkout\cart\totals\fee.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ define( [ 'Sugarcode_Test/js/view/checkout/summary/fee' ], function (Component) { 'use strict'; return Component.extend({ /** * @override */ isDisplayed: function () { return true; } }); } ); |
- app\code\Sugarcode\Test\view\frontend\web\js\view\checkout\summary\fee.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ /*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: 'Sugarcode_Test/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()); } }); } ); |
- app\code\Sugarcode\Test\view\frontend\web\template\checkout\summary\fee.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<!-- /** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ --> <!-- ko --> <tr class="totals fee excl"> <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 --> |
- app\code\Sugarcode\Test\view\frontend\web\template\checkout\cart\totals\fee.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!-- /** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ --> <!-- ko --> <tr class="totals fee excl"> <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 --> |
- app\code\Sugarcode\Test\Model\Total\Fee.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
<?php /** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ namespace Sugarcode\Test\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; //$quote->getFee(); $fee = 100; //Excellence_Fee_Model_Fee::getFee(); $balance = $fee - $exist_amount; $total->setTotalAmount('fee', $balance); $total->setBaseTotalAmount('fee', $balance); $total->setFee($balance); $total->setBaseFee($balance); $total->setGrandTotal($total->getGrandTotal() + $balance); $total->setBaseGrandTotal($total->getBaseGrandTotal() + $balance); 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' => 'Fee', 'value' => 100 ]; } /** * Get Subtotal label * * @return \Magento\Framework\Phrase */ public function getLabel() { return __('Fee'); } } |
- app\code\Sugarcode\Test\etc\module.xml
1 2 3 4 5 6 7 8 9 10 |
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd"> <module name="Sugarcode_Test" setup_version="2.0.6" schema_version="2.0.6"> <sequence> <module name="Magento_Sales"/> <module name="Magento_Quote"/> <module name="Magento_Checkout"/> </sequence> </module> </config> |
- app\code\Sugarcode\Test\view\frontend\layout\checkout_cart_index.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<?xml version="1.0"?> <!-- /** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ --> <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">Sugarcode_Test/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">Sugarcode_Test/checkout/cart/totals/fee</item> <item name="title" xsi:type="string" translate="true">Fee</item> </item> </item> </item> </item> </item> </argument> </arguments> </referenceBlock> </body> </page> |
- app\code\Sugarcode\Test\view\frontend\layout\checkout_index_index.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<?xml version="1.0"?> <!-- /** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ --> <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">Sugarcode_Test/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">Sugarcode_Test/checkout/cart/totals/fee</item> <item name="title" xsi:type="string" translate="true">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> |
- app\code\Sugarcode\Test\view\frontend\layout\sales_order_view.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?xml version="1.0"?> <!-- /** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ --> <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="Sugarcode\Test\Block\Sales\Order\Fee" name="fee"/> </referenceContainer> </body> </page> |
- app\code\Sugarcode\Test\Block\Sales\Order\Fee.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
<?php /** * Copyright © 2015 Magento. All rights reserved. * See COPYING.txt for license details. */ /** * Tax totals modification block. Can be used just as subblock of \Magento\Sales\Block\Order\Totals */ namespace Sugarcode\Test\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' => 100, //'value' => $this->_source->getFee(), 'label' => __('Fee'), ] ); $parent->addTotal($fee, 'fee'); // $this->_addTax('grand_total'); $parent->addTotal($fee, 'fee'); return $this; } } |
Once the above steps are done, run the command below; otherwise, your JS and HTML files won’t be available in the pub/static folder:
1 |
bin\magento setup:static-content:deploy |
We hope this article was useful. It is based on the