1

How to disable the Cash on Delivery payment method in backend and frontend Programmatically?

Here the code I'm using:

etc/di.xml

<type name="Magento\OfflinePayments\Model\Cashondelivery">
    <plugin name="cashondeliveryplugin" type="Xxx\Yyy\Plugin\Model\Cashondelivery" sortOrder="10" disabled="false" />
</type>

Plugin:

public function aroundIsAvailable(
    \Magento\OfflinePayments\Model\Cashondelivery $subject,
    callable $proceed,
    $quote = null
) {
    $result          = $proceed($quote);
    $codAvailability = $this->_pincodeModel->isCODAvailable($quote->getShippingAddress()->getPostcode()) ? "yes" : "no";
    if ($codAvailability == 'no') {
        return false;
    }

    return $result;
}

The actual problem is: the quote is missed when plugin called from the frontend (checkout page).

  • did you get your solution? – Jigs Parmar Feb 21 '18 at 11:14
  • @Ravindrasinh Zala answer is current please try that – Jigs Parmar Feb 21 '18 at 11:17
  • i got it...But i want to know about core flow................where to call isAvailable() method for showing available payment method list in core file – Mano M Feb 21 '18 at 11:19
  • core file located at vendor\magento\module-payment\Model\Method\AbstractMethod.php – Jigs Parmar Feb 21 '18 at 11:24
  • ill give path in my answer and if use for you please access it – Jigs Parmar Feb 21 '18 at 11:26
2

You can use a simple plugin on the method isAvailable of the model Magento\OfflinePayments\Model\Cashondelivery:

<?php
/**
 * Copyright © 2018 MageWorx. All rights reserved.
 * See LICENSE.txt for license details.
 */

namespace MageWorx\DisableCOD\Plugin;

use Magento\Customer\Model\Session as CustomerSession;
use Magento\Backend\Model\Auth\Session as BackendSession;
use Magento\OfflinePayments\Model\Cashondelivery;

class DisableCashOnDelivery
{
    /**
     * @var CustomerSession
     */
    protected $customerSession;

    /**
     * @var BackendSession
     */
    protected $backendSession;

    /**
     * @param CustomerSession $customerSession
     * @param BackendSession $backendSession
     */
    public function __construct(
        CustomerSession $customerSession,
        BackendSession $backendSession
    ) {
        $this->customerSession = $customerSession;
        $this->backendSession = $backendSession;
    }

    /**
     *
     * @param Cashondelivery $subject
     * @param                $result
     * @return bool
     */
    public function afterIsAvailable(Cashondelivery $subject, $result)
    {
        $condition = true; // Replace with your condition

        if ($condition) {
            return false;
        }

        return $result;
    }
}

Just change the conditions to desired one.

The result on the frontend (checkout page):

The result on the frontend

The result on the backend (create new order page):

The result on the backend

Full plugin could be found on github

Updated code:

<?php
/**
 * Copyright © 2018 MageWorx. All rights reserved.
 * See LICENSE.txt for license details.
 */

namespace MageWorx\DisableCOD\Plugin;

use Magento\Customer\Model\Session as CustomerSession;
use Magento\Backend\Model\Auth\Session as BackendSession;
use Magento\Framework\App\State;
use Magento\OfflinePayments\Model\Cashondelivery;
use Magento\Checkout\Model\Session as CheckoutFrontendSession;
use Magento\Backend\Model\Session\Quote as CheckoutBackendSession;

class DisableCashOnDelivery
{
    /**
     * @var CustomerSession
     */
    protected $customerSession;

    /**
     * @var BackendSession
     */
    protected $backendSession;

    /**
     * @var CheckoutFrontendSession|CheckoutBackendSession
     */
    protected $session;

    /**
     * @param CustomerSession         $customerSession
     * @param BackendSession          $backendSession
     * @param CheckoutFrontendSession $checkoutFrontendSession
     * @param CheckoutBackendSession  $checkoutBackendSession
     * @param State                   $state
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function __construct(
        CustomerSession $customerSession,
        BackendSession $backendSession,
        CheckoutFrontendSession $checkoutFrontendSession,
        CheckoutBackendSession $checkoutBackendSession,
        State $state
    ) {
        $this->customerSession = $customerSession;
        $this->backendSession  = $backendSession;
        if ($state->getAreaCode() == \Magento\Framework\App\Area::AREA_ADMINHTML) {
            $this->session = $checkoutBackendSession;
        } else {
            $this->session = $checkoutFrontendSession;
        }
    }

    public function aroundIsAvailable(
        \Magento\OfflinePayments\Model\Cashondelivery $subject,
        callable $proceed,
        \Magento\Quote\Api\Data\CartInterface $quote = null
    ) {
        $result = $proceed($quote);
        if ($quote === null) {
            $quote = $this->session->getQuote();
        }
        $codAvailability = $this->_pincodeModel->isCODAvailable($quote->getShippingAddress()->getPostcode()) ? 1 : 0;
        if (!$codAvailability) {
            return false;
        }

        return $result;
    }
}

Do not forget add your classes to the di (_pincodeModel).

Update 2:

On the frontend the $quote argument is null because it was called from the method \Magento\OfflinePayments\Model\InstructionsConfigProvider::getConfig() where the method isAvailable() of the each payment method was called without providing arguments, what means the $quote will be null:

public function getConfig()
{
    $config = [];
    foreach ($this->methodCodes as $code) {
        if ($this->methods[$code]->isAvailable()) {
            $config['payment']['instructions'][$code] = $this->getInstructions($code);
        }
    }
    return $config;
}

But in the checkout session, it exists, and we can access it from the checkout session object.

Update 3:

For the backend the method isAvailable() of the all payment methods was called from the Magento\Payment\Block\Form\Container::getMethods() method which provides a quote in the arguments list:

/**
 * Retrieve available payment methods
 *
 * @return array
 */
public function getMethods()
{
    $methods = $this->getData('methods');
    if ($methods === null) {
        $quote = $this->getQuote();
        $store = $quote ? $quote->getStoreId() : null;
        $methods = [];
        foreach ($this->getPaymentMethodList()->getActiveList($store) as $method) {
            $methodInstance = $this->getPaymentMethodInstanceFactory()->create($method);
            if ($methodInstance->isAvailable($quote) && $this->_canUseMethod($methodInstance)) {
                $this->_assignMethod($methodInstance);
                $methods[] = $methodInstance;
            }
        }
        $this->setData('methods', $methods);
    }
    return $methods;
}

Here is why you can access the quote object from the backend directly, and can not do that on the frontend.

  • where to call isAvailable() method in core – Mano M Feb 21 '18 at 11:17
  • In the class 'Magento\OfflinePayments\Model\Cashondelivery' – Siarhey Uchukhlebau Feb 21 '18 at 11:19
  • $pinCode = $this->_pincodeModel->isCODAvailable($quote->getShippingAddress()->getPostcode()) ? "yes" : "no"; if ($pinCode == 'no') { return false; }..........................its working for backend only – Mano M Feb 21 '18 at 11:22
  • @PriyaM This plugin works for the backend and frontend. Could you update your question with actual conditions you are using? – Siarhey Uchukhlebau Feb 21 '18 at 11:37
  • .it has quote....I can get pincode backend only from this quote...But i need it both ends – Mano M Feb 21 '18 at 11:40
0

Now this way disable payment method so please try COD ok

First you will need to create events.xml file under app/code/Company/Module/etc/. Then write “payment_method_is_active” event in it. This is the event which hits on checkout page for payment method availability.

app/code/Company/Module/etc/

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="payment_method_is_active">
        <observer name="custom_payment" instance="Company\Module\Observer\PaymentMethodAvailable" />
    </event>
</config>

Now create PaymentMethodAvailable.php under Company/Module/Observer/ and write following code in the file. I am disabling the check money order payment method, you can change payment method code according to your need.

app/code/Company/Module/Observer/PaymentMethodAvailable.php

<?php

namespace Company\Module\Observer;

use Magento\Framework\Event\ObserverInterface;


class PaymentMethodAvailable implements ObserverInterface
{
    /**
     * payment_method_is_active event handler.
     *
     * @param \Magento\Framework\Event\Observer $observer
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        // you can replace "cashondelivery" with your required payment method code
        if($observer->getEvent()->getMethodInstance()->getCode()=="cashondelivery"){
            $checkResult = $observer->getEvent()->getResult();
            $checkResult->setData('is_available', false); //this is disabling the payment method at checkout page
        }
    }
}

Now the payment method Cash On Delivery Order is disabled from checkout page

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.