1. app/code/Namespace/ModuleName/etc/frontend/routesapp/code/Namespace/ModuleName/etc/frontend/routes.xml

    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
        <router id="standard">
            <route id="namespace_modulename" frontName="namespace_modulename">
                <module name="Namespace_ModuleName"/>
            </route>
        </router>
    </config>
    

    This will define a new controller for our module.xml

      
  2. app/code/Namespace/ModuleName/Controller/Checkout/ApplyPaymentMethod.php

    <?php
    
    namespace Namespace\ModuleName\Controller\Checkout;
    
    class ApplyPaymentMethod extends \Magento\Framework\App\Action\Action
    {
        /**
         * @var \Magento\Framework\Controller\Result\ForwardFactory
         */
        protected $resultForwardFactory;
    
        /**
         * @var \Magento\Framework\View\LayoutFactory
         */
        protected $layoutFactory;
    
        /**
         * @var \Magento\Checkout\Model\Cart
         */
        protected $cart;
    
        /**
         * @param \Magento\Framework\App\Action\Context $context
         * @param \Magento\Framework\View\LayoutFactory $layoutFactory
         * @param \Magento\Framework\Controller\Result\ForwardFactory $resultForwardFactory
         */
        public function __construct(
            \Magento\Framework\App\Action\Context $context,
            \Magento\Framework\Controller\Result\ForwardFactory $resultForwardFactory,
            \Magento\Framework\View\LayoutFactory $layoutFactory,
            \Magento\Checkout\Model\Cart $cart
        ) {
            $this->resultForwardFactory = $resultForwardFactory;
            $this->layoutFactory = $layoutFactory;
            $this->cart = $cart;
    
            parent::__construct($context);
        }
    
        /**
         * @return \Magento\Framework\Controller\ResultInterface
         */
        public function execute()
        {
            $pMethod = $this->getRequest()->getParam('payment_method');
    
            $quote = $this->cart->getQuote();
    
            $quote->getPayment()->setMethod($pMethod['method']);
    
            $quote->setTotalsCollectedFlag(false);
            $quote->collectTotals();
            $quote->save();
        }
    }
    

    This file creates controller action to save the selected payment method to quote

  3. app/code/Namespace/ModuleName/view/frontend/requirejs-config.js

    var config = {
        map: {
            '*': {
                'Magento_Checkout/js/action/select-payment-method':
                    'Namespace_ModuleName/js/action/select-payment-method'
            }
        }
    };
    

    This file allows to override Magento_Checkout/js/action/select-payment-method file

  4. app/code/Namespace/ModuleName/view/frontend/web/js/action/select-payment-method.js

    define(
        [
            'Magento_Checkout/js/model/quote',
            'Magento_Checkout/js/model/full-screen-loader',
            'jquery',
            'Magento_Checkout/js/action/get-totals',
        ],
        function (quote, fullScreenLoader, jQuery, getTotalsAction) {
            'use strict';
            return function (paymentMethod) {
                quote.paymentMethod(paymentMethod);
    
                fullScreenLoader.startLoader();
    
                jQuery.ajax('/namespace_modulename/checkout/applyPaymentMethod', {
                    data: {payment_method: paymentMethod},
                    complete: function () {
                        getTotalsAction([]);
                        fullScreenLoader.stopLoader();
                    }
                });
    
            }
        }
    );
    

    Sends ajax request to save payment method and reload cart totals.

This will define a new controller for our module

  1. app/code/Namespace/ModuleName/Controller/Checkout/ApplyPaymentMethod.php

    resultForwardFactory = $resultForwardFactory; $this->layoutFactory = $layoutFactory; $this->cart = $cart; parent::__construct($context); } /** * @return \Magento\Framework\Controller\ResultInterface */ public function execute() { $pMethod = $this->getRequest()->getParam('payment_method'); $quote = $this->cart->getQuote(); $quote->getPayment()->setMethod($pMethod['method']); $quote->setTotalsCollectedFlag(false); $quote->collectTotals(); $quote->save(); }

}

This file creates controller action to save the selected payment method to quote

  1. app/code/Namespace/ModuleName/view/frontend/requirejs-config.js

    var config = { map: { '*': { 'Magento_Checkout/js/action/select-payment-method': 'Namespace_ModuleName/js/action/select-payment-method' } } };

This file allows to override "Magento_Checkout/js/action/select-payment-method" file

  1. app/code/Namespace/ModuleName/view/frontend/web/js/action/select-payment-method.js

    define( [ 'Magento_Checkout/js/model/quote', 'Magento_Checkout/js/model/full-screen-loader', 'jquery', 'Magento_Checkout/js/action/get-totals', ], function(quote, fullScreenLoader, jQuery, getTotalsAction) { 'use strict'; return function (paymentMethod) { quote.paymentMethod(paymentMethod);

         fullScreenLoader.startLoader();
    
         jQuery.ajax('/namespace_modulename/checkout/applyPaymentMethod', {
             data: { payment_method: paymentMethod },
             complete: function () {
                 getTotalsAction([]);
                 fullScreenLoader.stopLoader();
             }
         });
    
     }
    

    } );

Sends ajax request to save payment method and reload cart totals.

P.S.P.S. Parts of the code were taken from Payment Fee extension for Magento 2.

  1. app/code/Namespace/ModuleName/etc/frontend/routes.xml

     

This will define a new controller for our module

  1. app/code/Namespace/ModuleName/Controller/Checkout/ApplyPaymentMethod.php

    resultForwardFactory = $resultForwardFactory; $this->layoutFactory = $layoutFactory; $this->cart = $cart; parent::__construct($context); } /** * @return \Magento\Framework\Controller\ResultInterface */ public function execute() { $pMethod = $this->getRequest()->getParam('payment_method'); $quote = $this->cart->getQuote(); $quote->getPayment()->setMethod($pMethod['method']); $quote->setTotalsCollectedFlag(false); $quote->collectTotals(); $quote->save(); }

}

This file creates controller action to save the selected payment method to quote

  1. app/code/Namespace/ModuleName/view/frontend/requirejs-config.js

    var config = { map: { '*': { 'Magento_Checkout/js/action/select-payment-method': 'Namespace_ModuleName/js/action/select-payment-method' } } };

This file allows to override "Magento_Checkout/js/action/select-payment-method" file

  1. app/code/Namespace/ModuleName/view/frontend/web/js/action/select-payment-method.js

    define( [ 'Magento_Checkout/js/model/quote', 'Magento_Checkout/js/model/full-screen-loader', 'jquery', 'Magento_Checkout/js/action/get-totals', ], function(quote, fullScreenLoader, jQuery, getTotalsAction) { 'use strict'; return function (paymentMethod) { quote.paymentMethod(paymentMethod);

         fullScreenLoader.startLoader();
    
         jQuery.ajax('/namespace_modulename/checkout/applyPaymentMethod', {
             data: { payment_method: paymentMethod },
             complete: function () {
                 getTotalsAction([]);
                 fullScreenLoader.stopLoader();
             }
         });
    
     }
    

    } );

Sends ajax request to save payment method and reload cart totals.

P.S. Parts of the code were taken from Payment Fee extension for Magento 2.

  1. app/code/Namespace/ModuleName/etc/frontend/routes.xml

    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
        <router id="standard">
            <route id="namespace_modulename" frontName="namespace_modulename">
                <module name="Namespace_ModuleName"/>
            </route>
        </router>
    </config>
    

    This will define a new controller for our module.

     
  2. app/code/Namespace/ModuleName/Controller/Checkout/ApplyPaymentMethod.php

    <?php
    
    namespace Namespace\ModuleName\Controller\Checkout;
    
    class ApplyPaymentMethod extends \Magento\Framework\App\Action\Action
    {
        /**
         * @var \Magento\Framework\Controller\Result\ForwardFactory
         */
        protected $resultForwardFactory;
    
        /**
         * @var \Magento\Framework\View\LayoutFactory
         */
        protected $layoutFactory;
    
        /**
         * @var \Magento\Checkout\Model\Cart
         */
        protected $cart;
    
        /**
         * @param \Magento\Framework\App\Action\Context $context
         * @param \Magento\Framework\View\LayoutFactory $layoutFactory
         * @param \Magento\Framework\Controller\Result\ForwardFactory $resultForwardFactory
         */
        public function __construct(
            \Magento\Framework\App\Action\Context $context,
            \Magento\Framework\Controller\Result\ForwardFactory $resultForwardFactory,
            \Magento\Framework\View\LayoutFactory $layoutFactory,
            \Magento\Checkout\Model\Cart $cart
        ) {
            $this->resultForwardFactory = $resultForwardFactory;
            $this->layoutFactory = $layoutFactory;
            $this->cart = $cart;
    
            parent::__construct($context);
        }
    
        /**
         * @return \Magento\Framework\Controller\ResultInterface
         */
        public function execute()
        {
            $pMethod = $this->getRequest()->getParam('payment_method');
    
            $quote = $this->cart->getQuote();
    
            $quote->getPayment()->setMethod($pMethod['method']);
    
            $quote->setTotalsCollectedFlag(false);
            $quote->collectTotals();
            $quote->save();
        }
    }
    

    This file creates controller action to save the selected payment method to quote

  3. app/code/Namespace/ModuleName/view/frontend/requirejs-config.js

    var config = {
        map: {
            '*': {
                'Magento_Checkout/js/action/select-payment-method':
                    'Namespace_ModuleName/js/action/select-payment-method'
            }
        }
    };
    

    This file allows to override Magento_Checkout/js/action/select-payment-method file

  4. app/code/Namespace/ModuleName/view/frontend/web/js/action/select-payment-method.js

    define(
        [
            'Magento_Checkout/js/model/quote',
            'Magento_Checkout/js/model/full-screen-loader',
            'jquery',
            'Magento_Checkout/js/action/get-totals',
        ],
        function (quote, fullScreenLoader, jQuery, getTotalsAction) {
            'use strict';
            return function (paymentMethod) {
                quote.paymentMethod(paymentMethod);
    
                fullScreenLoader.startLoader();
    
                jQuery.ajax('/namespace_modulename/checkout/applyPaymentMethod', {
                    data: {payment_method: paymentMethod},
                    complete: function () {
                        getTotalsAction([]);
                        fullScreenLoader.stopLoader();
                    }
                });
    
            }
        }
    );
    

    Sends ajax request to save payment method and reload cart totals.

P.S. Parts of the code were taken from Payment Fee extension for Magento 2.

Source Link

This rule doesn't work because Magento 2 doesn't save payment method to quote when you select one. And it also doesn't reload totals when selecting a payment method. And unfortunately, you have to write a custom module to solve the issue.

The new module needs only 4 files to be created:

  1. app/code/Namespace/ModuleName/etc/frontend/routes.xml

This will define a new controller for our module

  1. app/code/Namespace/ModuleName/Controller/Checkout/ApplyPaymentMethod.php

    resultForwardFactory = $resultForwardFactory; $this->layoutFactory = $layoutFactory; $this->cart = $cart; parent::__construct($context); } /** * @return \Magento\Framework\Controller\ResultInterface */ public function execute() { $pMethod = $this->getRequest()->getParam('payment_method'); $quote = $this->cart->getQuote(); $quote->getPayment()->setMethod($pMethod['method']); $quote->setTotalsCollectedFlag(false); $quote->collectTotals(); $quote->save(); }

}

This file creates controller action to save the selected payment method to quote

  1. app/code/Namespace/ModuleName/view/frontend/requirejs-config.js

    var config = { map: { '*': { 'Magento_Checkout/js/action/select-payment-method': 'Namespace_ModuleName/js/action/select-payment-method' } } };

This file allows to override "Magento_Checkout/js/action/select-payment-method" file

  1. app/code/Namespace/ModuleName/view/frontend/web/js/action/select-payment-method.js

    define( [ 'Magento_Checkout/js/model/quote', 'Magento_Checkout/js/model/full-screen-loader', 'jquery', 'Magento_Checkout/js/action/get-totals', ], function(quote, fullScreenLoader, jQuery, getTotalsAction) { 'use strict'; return function (paymentMethod) { quote.paymentMethod(paymentMethod);

         fullScreenLoader.startLoader();
    
         jQuery.ajax('/namespace_modulename/checkout/applyPaymentMethod', {
             data: { payment_method: paymentMethod },
             complete: function () {
                 getTotalsAction([]);
                 fullScreenLoader.stopLoader();
             }
         });
    
     }
    

    } );

Sends ajax request to save payment method and reload cart totals.

P.S. Parts of the code were taken from Payment Fee extension for Magento 2.