If you try to create a new discount rule in Magento 2, you'll see a condition called "Payment Method" there. This condition means that the discount will be applied in case a customer selects a certain payment method. But actually, this rule will not work due to a small omission in Magento 2 checkout. In this article, we'll try to help you fix the issue in your Magento setup.

We've already developed a ready-to-use solution. You can download it from GitHub for free. And below we'll only explain a little how it works.

The problem is caused by the fact that Magento 2 doesn't save the selected payment method to session (quote) and it doesn't reload totals when somebody selects a payment method. In the files below we'll try to explain how we've managed to fix the problem.

1. app/code/MagestyApps/FixRules/view/frontend/requirejs-config.js

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

When you select a payment method on checkout, Magento 2 executes the code from Magento_Checkout::view/frontend/web/js/action/select-payment-method.js file. In order to append our code to the original one, we have to override the file. Thanks to RequireJS technology, we can do it easily and securely. In the given file we are overriding the mentioned Magento file with our one.

2. app/code/MagestyApps/FixRules/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(
'/magestyapps_fixrules/checkout/applyPaymentMethod',
{ data: {payment_method: paymentMethod}, complete: function () { getTotalsAction([]); fullScreenLoader.stopLoader(); }
}
); } } );

Everything we need to do when somebody selects a payment method is to save the method to quote and reload totals after that. In the new file, we are sending an AJAX request to 'http://example.com/magestyapps_fixrules/checkout/applyPaymentMethod' when a customer selects a payment method.

3. app/code/MagestyApps/FixRules/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="MagestyApps_FixRules" frontName="magestyapps_fixrules">
            <module name="MagestyApps_FixRules"/>
        </route>
    </router>
</config>

As the AJAX request is sent to a custom URL, we need to create a new router for the URL to route it to our controller.

4. app/code/MagestyApps/FixRules/Controller/Checkout/

ApplyPaymentMethod.php


namespace MagestyAppsFixRulesControllerCheckout; class ApplyPaymentMethod extends MagentoFrameworkAppActionAction { /** * @var MagentoFrameworkControllerResultForwardFactory */ protected $resultForwardFactory; /** * @var MagentoFrameworkViewLayoutFactory */ protected $layoutFactory; /** * @var MagentoCheckoutModelCart */ protected $cart; /** * @param MagentoFrameworkAppActionContext $context * @param MagentoFrameworkViewLayoutFactory $layoutFactory * @param MagentoFrameworkControllerResultForwardFactory $resultForwardFactory */ public function __construct( MagentoFrameworkAppActionContext $context, MagentoFrameworkControllerResultForwardFactory $resultForwardFactory, MagentoFrameworkViewLayoutFactory $layoutFactory, MagentoCheckoutModelCart $cart ) { $this->resultForwardFactory = $resultForwardFactory; $this->layoutFactory = $layoutFactory; $this->cart = $cart; parent::__construct($context); } /** * @return MagentoFrameworkControllerResultInterface */ 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(); } }

In the controller, we save the selected payment method to quote. That is necessary in order Magento could see the selected billing method when reloading the totals.

In case you want to add an extra charge instead of discounts when somebody uses a certain payment method, we'd like to offer you our Payment Fees extension for Magento 2.