0

I want to disable a cash on delivery payment method on the checkout for specific products I followed the code in this question

Disable Payment Method at Checkout in Magento 2 Based on Product Attribute

I modified the payment name in this file

Vendor/DisableCOD/Observer/DisablePaymentMethods.php

to cashondelivery

<?php
namespace Vendor\DisableCOD\Observer;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\App\Request\DataPersistorInterface;
use Magento\Framework\App\ObjectManager;
class DisablePaymentMethods implements ObserverInterface
{
    public function __construct(\Psr\Log\LoggerInterface $logger)
    {
        $this->_logger = $logger;
    }
    /**
     *
     * @param \Magento\Framework\Event\Observer $observer
     * @return void
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $cart = $objectManager->get('\Magento\Checkout\Model\Cart'); 

        // get cart items
        $items = $cart->getItems();

        // get attribute value of cart items
        foreach ($items as $item) 
        {
            $p = $objectManager->get('Magento\Catalog\Model\Product')->load($item['product_id']);
            $attribute = $p->getResource()->getAttribute('cod'); 

            if ($attribute) 
            {
                $attr_value = $attribute ->getFrontend()->getValue($p);
                if($attr_value == 'Yes' || $attr_value == 'yes' || $attr_value == 'YES')
                {
                    if($observer->getEvent()->getMethodInstance()->getCode()=="cashondelivery")
                    {
                        $checkResult = $observer->getEvent()->getResult();
                        $checkResult->setData('is_available', false); 
                    }
                }

            }
        }
    }
}

then I created new Product Attribute that named 'cod' with input type 'Yes/No' but nothing happened the cash on delivery method still enabled for

1 Answer 1

0

The Catalog attribute Yes/No input type uses the Magento\Eav\Model\Entity\Attribute\Source\Boolean class as the source model and has int as the backend type.

The Magento\Eav\Model\Entity\Attribute\Source\Boolean class source model has a value of 1 for Yes and 0 for No.

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Magento\Eav\Model\Entity\Attribute\Source;

/**
 * @api
 * @since 100.0.2
 */
class Boolean extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
{
    /**
     * Option values
     */
    const VALUE_YES = 1;

    const VALUE_NO = 0;

...

    /**
     * Retrieve all options array
     *
     * @return array
     */
    public function getAllOptions()
    {
        if ($this->_options === null) {
            $this->_options = [
                ['label' => __('Yes'), 'value' => self::VALUE_YES],
                ['label' => __('No'), 'value' => self::VALUE_NO],
            ];
        }
        return $this->_options;
    }
    ...
}

Therefore, to check if the attribute value is Yes, you need to replace the following code:

if($attr_value == 'Yes' || $attr_value == 'yes' || $attr_value == 'YES')

with

if ($attr_value)

Additionally, to retrieve the product attribute value, you can use the $item variable without the need to load the product model:

$CODAttributeValue = $item->getProduct()->getData('cod');

To follow best practices, you shouldn't use the Object Manager in your code. There is a post discussing this To use or not to use the ObjectManager directly?

To optimize your code, you can replace your class with the following content:

<?php
declare(strict_types=1);

namespace Vendor\DisableCOD\Observer;

use Magento\Framework\DataObject;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\OfflinePayments\Model\Cashondelivery;
use Magento\Payment\Model\Method\AbstractMethod;
use Magento\Quote\Api\Data\CartInterface;

class DisablePaymentMethods implements ObserverInterface
{
    /**
     * Disable Cash On Delivery payment method based on defined the `cod` product attribute
     *
     * @param Observer $observer
     * @throws LocalizedException
     */
    public function execute(Observer $observer)
    {
        /** @var DataObject $result */
        $result = $observer->getResult();
        /** @var AbstractMethod $methodInstance */
        $methodInstance = $observer->getMethodInstance();
        /** @var CartInterface $quote */
        $quote = $observer->getQuote();
        $paymentCode = $methodInstance->getCode();

        if ($paymentCode === Cashondelivery::PAYMENT_METHOD_CASHONDELIVERY_CODE) {
            $allItems = $quote->getAllItems();
            /** @var $item \Magento\Quote\Model\Quote\Item */
            foreach ($allItems as $item) {
                if ($item->getProduct()->getData('cod')) {
                    $result->setData('is_available', false);
                    break;
                }
            }
        }
    }
}

4
  • thanks for your assistance after I tried your code I get this error Error: Call to a member function getAllItems() on null in DisablePaymentMethods.php:34
    – Ibrahim
    Sep 26 at 15:09
  • It appears there is an issue on your end. In my provided code, the getAllItems() method was called on the line 33, not 34. Additionally, please confirm that you have properly applied an observer to the payment_method_is_active event? You can reference the solution in the following post for guidance: magento.stackexchange.com/questions/364348/….
    – Tu Van
    Sep 26 at 15:35
  • it is called on the line 33 for me also, I wrote 34 by mistake. I checked the event file also and it is correct as the solution that you mentioned and still same error
    – Ibrahim
    Sep 26 at 16:51
  • Please remove the cookies and test it again.
    – Tu Van
    Sep 26 at 17:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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