6

I want to remove the below lines in Magento\Quote\Model\PaymentMethodManagement model file

 if (!$this->zeroTotalValidator->isApplicable($payment->getMethodInstance(), $quote)) {
            throw new InvalidTransitionException(__('The requested Payment Method is not available.'));
        }

In PaymentMethodManagement file:

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

use Magento\Framework\Exception\State\InvalidTransitionException;

/**
 * Class PaymentMethodManagement
 */
class PaymentMethodManagement implements \Magento\Quote\Api\PaymentMethodManagementInterface
{
    /**
     * @var \Magento\Quote\Api\CartRepositoryInterface
     */
    protected $quoteRepository;

    /**
     * @var \Magento\Payment\Model\Checks\ZeroTotal
     */
    protected $zeroTotalValidator;

    /**
     * @var \Magento\Payment\Model\MethodList
     */
    protected $methodList;

    /**
     * Constructor
     *
     * @param \Magento\Quote\Api\CartRepositoryInterface $quoteRepository
     * @param \Magento\Payment\Model\Checks\ZeroTotal $zeroTotalValidator
     * @param \Magento\Payment\Model\MethodList $methodList
     */
    public function __construct(
        \Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
        \Magento\Payment\Model\Checks\ZeroTotal $zeroTotalValidator,
        \Magento\Payment\Model\MethodList $methodList
    ) {
        $this->quoteRepository = $quoteRepository;
        $this->zeroTotalValidator = $zeroTotalValidator;
        $this->methodList = $methodList;
    }

    /**
     * {@inheritdoc}
     */
    public function set($cartId, \Magento\Quote\Api\Data\PaymentInterface $method)
    {
        /** @var \Magento\Quote\Model\Quote $quote */
        $quote = $this->quoteRepository->get($cartId);

        $method->setChecks([
            \Magento\Payment\Model\Method\AbstractMethod::CHECK_USE_CHECKOUT,
            \Magento\Payment\Model\Method\AbstractMethod::CHECK_USE_FOR_COUNTRY,
            \Magento\Payment\Model\Method\AbstractMethod::CHECK_USE_FOR_CURRENCY,
            \Magento\Payment\Model\Method\AbstractMethod::CHECK_ORDER_TOTAL_MIN_MAX,
        ]);
        $payment = $quote->getPayment();

        $data = $method->getData();
        $payment->importData($data);

        if ($quote->isVirtual()) {
            $quote->getBillingAddress()->setPaymentMethod($payment->getMethod());
        } else {
            // check if shipping address is set
            if ($quote->getShippingAddress()->getCountryId() === null) {
                throw new InvalidTransitionException(__('Shipping address is not set'));
            }
            $quote->getShippingAddress()->setPaymentMethod($payment->getMethod());
        }
        if (!$quote->isVirtual() && $quote->getShippingAddress()) {
            $quote->getShippingAddress()->setCollectShippingRates(true);
        }

        if (!$this->zeroTotalValidator->isApplicable($payment->getMethodInstance(), $quote)) {
            throw new InvalidTransitionException(__('The requested Payment Method is not available.'));
        }

        $quote->setTotalsCollectedFlag(false)->collectTotals()->save();
        return $quote->getPayment()->getId();
    }}

How to do this. Thanks.

8

All other answers tell you how to rewrite the model, exactly what is asked. But Magento 2 offers another solution to your problem: Plugins. With plugins you can change the outcome of just about any public method in Magento 2. You stated you want to change the result of this function:

if (!$this->zeroTotalValidator->isApplicable($payment->getMethodInstance(), $quote)) {
    throw new InvalidTransitionException(__('The requested Payment Method is not available.'));
}

You can do this by adding a plugin on the \Magento\Payment\Model\Checks\ZeroTotal class. Add this to your etc/di.xml file:

<type name="Magento\Quote\Model\PaymentMethodManagement">
    <plugin name="your_unique_name_for_this_plugin" type="Vendor\Module\Plugin\PaymentMethodManagement" />
</type>

Then create the class:

<VendorName>\<ModuleName>\Plugin\PaymentMethodManagement

namespace Vendor\Module\Plugin;

class PaymentMethodManagement {
    public function afterIsApplicable($subject, $result)
    {
        return true;
    }
}

This will make sure the function always returns true. If you want a more granular approach you can change the function to this:

public function aroundIsApplicable($subject, callable $proceed, ...$args)
{
   if ($this->meetsMyCustomRequirement()) {
       // This will call the original function and return it's results.
       return $proceed(...$args);
   }

   return false;
}

If the $proceed function isn't called then the original function is also never called.

  • 1
    This is the best solution. I always refer plugin for overriding the class – Amit Bera Apr 19 at 3:15
  • Yes, Plugin is better than preference – Ravi Dudhara Apr 23 at 11:50
6

Steps to Follow :

  • Override di.xml
  • Override PaymentMethodManagement.php
  • Launch SSH and Run Commands

Override di.xml

app/code/Namespace/Modulename/etc

<?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\Quote\Model\PaymentMethodManagement" type="Namespace\Modulename\PaymentMethodManagement" />
   </config>

Override PaymentMethodManagement.php

/**
* {@inheritdoc}
*/
public function set($cartId, \Magento\Quote\Api\Data\PaymentInterface $method)
{
    /** @var \Magento\Quote\Model\Quote $quote */
    $quote = $this->quoteRepository->get($cartId);

    $method->setChecks([
        \Magento\Payment\Model\Method\AbstractMethod::CHECK_USE_CHECKOUT,
        \Magento\Payment\Model\Method\AbstractMethod::CHECK_USE_FOR_COUNTRY,
        \Magento\Payment\Model\Method\AbstractMethod::CHECK_USE_FOR_CURRENCY,
        \Magento\Payment\Model\Method\AbstractMethod::CHECK_ORDER_TOTAL_MIN_MAX,
    ]);
    $payment = $quote->getPayment();

    $data = $method->getData();
    $payment->importData($data);

    if ($quote->isVirtual()) {
        $quote->getBillingAddress()->setPaymentMethod($payment->getMethod());
    } else {
        // check if shipping address is set
        if ($quote->getShippingAddress()->getCountryId() === null) {
            throw new InvalidTransitionException(__('Shipping address is not set'));
        }
        $quote->getShippingAddress()->setPaymentMethod($payment->getMethod());
    }
    if (!$quote->isVirtual() && $quote->getShippingAddress()) {
        $quote->getShippingAddress()->setCollectShippingRates(true);
    }
    /*** Do stuff with this code ***/
    if (!$this->zeroTotalValidator->isApplicable($payment->getMethodInstance(), $quote)) {
        throw new InvalidTransitionException(__(''));
    }
    /*** Do stuff with this code ***/

    $quote->setTotalsCollectedFlag(false)->collectTotals()->save();
    return $quote->getPayment()->getId();
}

Launch SSH and Run Commands

php bin/magento setup:di:compile
php bin/magento cache:clean
php bin/magento cache:flush

I hope it helps!

2

You can do it by using Preference in your di.xml file of your custom module.

<?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\Quote\Model\PaymentMethodManagement" type="vendor\module\Model\PaymentMethodManagement" />

</config>
2

in you 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\Quote\Model\PaymentMethodManagement" type="Vendor\Module\Model\Rewrite\Quote\PaymentMethodManagement" />

</config>

in your Model file

<?php 
 namespace Vendor\Module\Model\Rewrite\Quote;

        class PaymentMethodManagement extends \Magento\Quote\Model\PaymentMethodManagement
        {
            public function set($cartId, \Magento\Quote\Api\Data\PaymentInterface $method)
            {
                /** @var \Magento\Quote\Model\Quote $quote */
                $quote = $this->quoteRepository->get($cartId);

                $method->setChecks([
                    \Magento\Payment\Model\Method\AbstractMethod::CHECK_USE_CHECKOUT,
                    \Magento\Payment\Model\Method\AbstractMethod::CHECK_USE_FOR_COUNTRY,
                    \Magento\Payment\Model\Method\AbstractMethod::CHECK_USE_FOR_CURRENCY,
                    \Magento\Payment\Model\Method\AbstractMethod::CHECK_ORDER_TOTAL_MIN_MAX,
                ]);
                $payment = $quote->getPayment();

                $data = $method->getData();
                $payment->importData($data);

                if ($quote->isVirtual()) {
                    $quote->getBillingAddress()->setPaymentMethod($payment->getMethod());
                } else {
                    // check if shipping address is set
                    if ($quote->getShippingAddress()->getCountryId() === null) {
                        throw new InvalidTransitionException(__('Shipping address is not set'));
                    }
                    $quote->getShippingAddress()->setPaymentMethod($payment->getMethod());
                }
                if (!$quote->isVirtual() && $quote->getShippingAddress()) {
                    $quote->getShippingAddress()->setCollectShippingRates(true);
                }
                /*** Do stuff with this code ***/
                if (!$this->zeroTotalValidator->isApplicable($payment->getMethodInstance(), $quote)) {
                    throw new InvalidTransitionException(__(''));
                }
                /*** Do stuff with this code ***/

                $quote->setTotalsCollectedFlag(false)->collectTotals()->save();
                return $quote->getPayment()->getId();
            }

        }

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.