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 backend (create new order page):
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.