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.
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
-
You can post your rule here?Khoa Truong– Khoa Truong2016年08月02日 12:29:39 +00:00Commented Aug 2, 2016 at 12:29
-
I posted my Rule. Can you check for me please?Nguyễn Hồng Quang– Nguyễn Hồng Quang2016年08月02日 12:43:21 +00:00Commented Aug 2, 2016 at 12:43
-
Try to add the activated date of the rule?Khoa Truong– Khoa Truong2016年08月02日 12:46:43 +00:00Commented 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 optionNguyễn Hồng Quang– Nguyễn Hồng Quang2016年08月02日 12:55:37 +00:00Commented Aug 2, 2016 at 12:55
-
1Thanks. I posted the issue here: github.com/magento/magento2/issues/5937Nguyễn Hồng Quang– Nguyễn Hồng Quang2016年08月02日 13:12:32 +00:00Commented Aug 2, 2016 at 13:12
6 Answers 6
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:
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.
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
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-methodfileapp/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.
-
1Thanks 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?Nguyễn Hồng Quang– Nguyễn Hồng Quang2016年08月02日 15:17:37 +00:00Commented Aug 2, 2016 at 15:17
-
1It works really well. Thanks MagestyApps very much. This solution is perfect.Nguyễn Hồng Quang– Nguyễn Hồng Quang2016年08月03日 08:00:44 +00:00Commented 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.DaFunkyAlex– DaFunkyAlex2017年10月16日 19:53:50 +00:00Commented Oct 16, 2017 at 19:53
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 datapayment_methodto be set on the quote addresses; - Even changing the controller from MagestyApps answer to set
payment_methoddata on the quote addresses, didn't work when the quote became an order, because it don't persistpayment_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();
}
});
}
}
);
-
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.2Alex Bogias– Alex Bogias2018年03月11日 15:09:17 +00:00Commented Mar 11, 2018 at 15:09 -
for magento 2.1.9, should we omit AdvancedSalesRule parts?Yohanes Pradono– Yohanes Pradono2018年03月29日 07:10:48 +00:00Commented 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 7Magecode– Magecode2019年03月22日 12:44:15 +00:00Commented Mar 22, 2019 at 12:44
-
AdvancedSalesRule is not available in Magento 2.1.5Magecode– Magecode2019年03月22日 12:44:55 +00:00Commented Mar 22, 2019 at 12:44
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.
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).
We suppose, that this is Magento bug. When you choose a payment method the information should be sent in advance.
-
2The answer from MagestyApps is accepted. Thanks.Nguyễn Hồng Quang– Nguyễn Hồng Quang2016年08月03日 08:01:47 +00:00Commented Aug 3, 2016 at 8:01
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
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>
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)
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 }, } } };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(); }); }); }; });