13

I go to Magento 2 Admin> Marketing> Promotions> Cart Price Rules and create a new Rule: Bank Transfer Payment:

Tab Rule Information:

  • Rule Name: Bank Transfer Payment
  • Status: Active
  • Websites: Main Website
  • Customer Groups: select all
  • Coupon: No Coupon
  • Uses per Customer: 0
  • From: blank
  • To: blank
  • Priority: 0
  • Public in RSS Feed: No

Conditions tab:

  • If ALL of these conditions are TRUE :
    • Payment Method is Bank Transfer Payment

Actions Tab:

  • Apply: percent of product price discount
  • Discount Amount: 2
  • Maximum Qty Discount is Applied To: 0
  • Discount Qty Step (Buy X): 0
  • Apply to Shipping Amount: No
  • Discard subsequent rules: No
  • Free Shipping: No
  • Apply the rule only to cart items matching the following conditions (leave blank for all items): nothing

Then I enable Bank Transfer Payment method, go to checkout page, click on Bank Transfer Payment but the Discount Percent Price does not show up in Order Summary.

enter image description here

Please give me an advice. How can make a discount on payment method on Magento 2. For Magento 1, it wroks well.

Thanks very much

Siarhey Uchukhlebau
16.2k11 gold badges57 silver badges89 bronze badges
asked Aug 2, 2016 at 12:26
6
  • You can post your rule here? Commented Aug 2, 2016 at 12:29
  • I posted my Rule. Can you check for me please? Commented Aug 2, 2016 at 12:43
  • Try to add the activated date of the rule? Commented Aug 2, 2016 at 12:46
  • I try to add the start Date of the rule but still nothing happen in Order Summary when click on Bank Transfer Payment option Commented Aug 2, 2016 at 12:55
  • 1
    Thanks. I posted the issue here: github.com/magento/magento2/issues/5937 Commented Aug 2, 2016 at 13:12

6 Answers 6

11

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

    <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.

Marius
199k55 gold badges431 silver badges837 bronze badges
answered Aug 2, 2016 at 14:02
3
  • 1
    Thanks very much MagestyApps, I created a new Module follow your instruction. However, at the end I got this problem jquery.js 192.168.41.59/phoenix_checkout/checkout/applyPaymentMethod 404 (Not Found). Did you get this bug before? Commented Aug 2, 2016 at 15:17
  • 1
    It works really well. Thanks MagestyApps very much. This solution is perfect. Commented Aug 3, 2016 at 8:00
  • Awesome stuff, thx. The Cart price rule for payment methods was removed btw (github.com/magento/magento2/commit/…). I added the line "'payment_method' => __('Payment Method')," again, now I can create cart price rules for payment methods. Commented Oct 16, 2017 at 19:53
3

On Magento 2.2 i couldn't get MagestyApps answer to work. I needed to add some additional files. Because:

  • Cart Price Rule for Payment Method was removed from admin (as pointed out by DaFunkyAlex);
  • In Magento 2.2 the discount was not being applied on the quote, because the method \Magento\AdvancedSalesRule\Model\Rule\Condition\FilterTextGenerator\Address\PaymentMethod::generateFilterText (actually it falls back to \Magento\AdvancedSalesRule\Model\Rule\Condition\FilterTextGenerator\Address::generateFilterText), was expecting the data payment_method to be set on the quote addresses;
  • Even changing the controller from MagestyApps answer to set payment_method data on the quote addresses, didn't work when the quote became an order, because it don't persist payment_method;

The following module worked out for me (thanks to MagestyApps answer, it was based on top of that):

registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
 \Magento\Framework\Component\ComponentRegistrar::MODULE,
 'Vendor_SalesRulesPaymentMethod',
 __DIR__
);

etc/module.xml

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
 <module name="Vendor_SalesRulesPaymentMethod" setup_version="1.0.0">
 <sequence>
 <module name="Magento_AdvancedSalesRule"/>
 <module name="Magento_Checkout"/>
 <module name="Magento_SalesRules"/>
 <module name="Magento_Quote"/>
 </sequence>
 </module>
</config>

etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
 <preference for="Magento\AdvancedSalesRule\Model\Rule\Condition\FilterTextGenerator\Address\PaymentMethod"
 type="Vendor\SalesRulesPaymentMethod\Model\Rule\Condition\FilterTextGenerator\Address\PaymentMethod"/>
 <type name="Magento\SalesRule\Model\Rule\Condition\Address">
 <plugin name="addPaymentMethodOptionBack" type="Vendor\SalesRulesPaymentMethod\Plugin\AddPaymentMethodOptionBack" />
 </type>
</config>

etc/frontend/routes.xml

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
 <router id="standard">
 <route id="salesrulespaymentmethod" frontName="salesrulespaymentmethod">
 <module name="Vendor_SalesRulesPaymentMethod"/>
 </route>
 </router>
</config>

Controller/Checkout/ApplyPaymentMethod.php

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

Model/Rule/Condition/FilterTextGenerator/Address/PaymentMethod.php

<?php
namespace Vendor\SalesRulesPaymentMethod\Model\Rule\Condition\FilterTextGenerator\Address;
use Magento\AdvancedSalesRule\Model\Rule\Condition\FilterTextGenerator\Address\PaymentMethod as BasePaymentMethod;
class PaymentMethod extends BasePaymentMethod
{
 /**
 * @param \Magento\Framework\DataObject $quoteAddress
 * @return string[]
 */
 public function generateFilterText(\Magento\Framework\DataObject $quoteAddress)
 {
 $filterText = [];
 if ($quoteAddress instanceof \Magento\Quote\Model\Quote\Address) {
 $value = $quoteAddress->getQuote()->getPayment()->getMethod();
 if (is_scalar($value)) {
 $filterText[] = $this->getFilterTextPrefix() . $this->attribute . ':' . $value;
 }
 }
 return $filterText;
 }
}

Plugin/AddPaymentMethodOptionBack.php

<?php
namespace Vendor\SalesRulesPaymentMethod\Plugin;
use Magento\SalesRule\Model\Rule\Condition\Address;
class AddPaymentMethodOptionBack
{
 /**
 * @param Address $subject
 * @param $result
 * @return Address
 */
 public function afterLoadAttributeOptions(Address $subject, $result)
 {
 $attributeOption = $subject->getAttributeOption();
 $attributeOption['payment_method'] = __('Payment Method');
 $subject->setAttributeOption($attributeOption);
 return $subject;
 }
}

view/frontend/requirejs-config.js

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

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('/salesrulespaymentmethod/checkout/applyPaymentMethod', {
 data: {payment_method: paymentMethod},
 complete: function () {
 getTotalsAction([]);
 fullScreenLoader.stopLoader();
 }
 });
 }
 }
);
answered Jan 31, 2018 at 21:36
4
  • I get this when trying to compile: Fatal error: Class 'Magento\AdvancedSalesRule\Model\Rule\Condition\Address\PaymentMethod' not found in Vendor/SalesRulesPaymentMethod/Model/Rule/Condition/FilterTextGenerator/Address/PaymentMethod.php on line 7. I even tried to change AdvancedSalesRule to SalesRule as I can see there is no AdvancedSalesRule Model in Magento 2.2.2 Commented Mar 11, 2018 at 15:09
  • for magento 2.1.9, should we omit AdvancedSalesRule parts? Commented Mar 29, 2018 at 7:10
  • Getting error when compile: Fatal error: Class 'Magento\AdvancedSalesRule\Model\Rule\Condition\Address\PaymentMethod' not found in Vendor/SalesRulesPaymentMethod/Model/Rule/Condition/FilterTextGenerator/Address/PaymentMethod.php on line 7 Commented Mar 22, 2019 at 12:44
  • AdvancedSalesRule is not available in Magento 2.1.5 Commented Mar 22, 2019 at 12:44
2

We just checked the same rule and found that it doesn't work. Using the same conditions, no information about selected chosen method is sent and it is not recorded anywhere until the order is placed and the rule may not work.

enter image description here

Address has no payment method until validation and it gets the payment method from payment quote that doesn't exist because no information has been sent ($model->getQuote()->getPayment()->getMethod() returns null).

enter image description here

We suppose, that this is Magento bug. When you choose a payment method the information should be sent in advance.

answered Aug 2, 2016 at 14:00
1
  • 2
    The answer from MagestyApps is accepted. Thanks. Commented Aug 3, 2016 at 8:01
1

The solution with the custom module is working.

I just thought that it would be useful info for Magento beginners to know that you also need to add these files to be able to add and enable this module:

(copy from a different module and change files according to your module name and namespace)

app/code/Namespace/ModuleName/composer.js
app/code/Namespace/ModuleName/registration.php
app/code/Namespace/ModuleName/etc/module.xml

then you would be able to run bin/magento setup:upgrade

0

i created the files and replaced the Namespaces and modulename but i think my files wont be executed.

Maybe an error on my files??

registration.php

<?php
use Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(
ComponentRegistrar::MODULE,
'Jacor_Checkoutpayment',
__DIR__
);

composer.json

{
"name": "jacor/checkoutpayment",
"autoload": {
 "psr-4": {
 "Jacor\\Checkoutpayment\\": ""
 },
 "files": [
 "registration.php"
 ]
}

}

module.xml

<?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="Jacor_Checkoutpayment" setup_version="1.0.0" />
</config>
answered Sep 11, 2017 at 15:25
0

actually, overriding of magento core files is not a good idea. Instead of override Magento_Checkout/js/action/select-payment-method better create a mixin for it. And you can deale it without creating a new controller. See below (in addition to @magestyapps answer)

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

     var config = {
     config: {
     mixins: {
     'Magento_Checkout/js/action/select-payment-method': {
     'Namespace_ModuleName/js/checkout/action/select-payment-method-mixin': true
     },
     }
     }
     };
    
  2. app/code/Namespace/ModuleName/view/frontend/js/checkout/action/select-payment-method-mixin.js

     define([
     'jquery',
     'mage/utils/wrapper',
     'mage/storage',
     'Magento_Checkout/js/action/get-totals',
     'Magento_Checkout/js/model/full-screen-loader',
     'Magento_Checkout/js/model/quote',
     'Magento_Checkout/js/model/url-builder',
     'Magento_Customer/js/model/customer',
    ], function (,ドル wrapper, storage, getTotalsAction, fullScreenLoader, quote, urlBuilder, customer) {
     'use strict';
     return function (selectPaymentMethod) {
     return wrapper.wrap(selectPaymentMethod, function (originalAction, paymentMethod) {
     var serviceUrl, payload;
     originalAction(paymentMethod);
     payload = {
     method: paymentMethod
     };
     if (customer.isLoggedIn()) {
     serviceUrl = urlBuilder.createUrl('/carts/mine/selected-payment-method', {});
     } else {
     serviceUrl = urlBuilder.createUrl('/guest-carts/:cartId/selected-payment-method', {
     cartId: quote.getQuoteId()
     });
     }
     fullScreenLoader.startLoader();
     storage.put(
     serviceUrl,
     JSON.stringify(payload)
     ).success(function () {
     getTotalsAction([]);
     fullScreenLoader.stopLoader();
     });
     });
     };
    });
    
answered Aug 20, 2019 at 16:18

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.