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\Payment\Model\Checks\ZeroTotal">
    <plugin name="your_unique_name_for_this_plugin" type="Vendor\Module\Plugin\ZeroTotal" />
</type>

Then create the class:

<VendorName>\<ModuleName>\Plugin\ZeroTotal

namespace Vendor\Module\Plugin;

class ZeroTotal
{
    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.

| improve this answer | |
  • 1
    This is the best solution. I always refer plugin for overriding the class – Amit Bera Apr 19 '19 at 3:15
  • Yes, Plugin is better than preference – Ravi Dudhara Apr 23 '19 at 11:50
  • You say to do a plugin on the ZeroTotal class, but then do a plugin on the PaymentMethodManagement class? Is one of these a typo? – Nick Rolando Jan 30 at 16:46
  • Oops, you're right. I've just fixed it. – Michiel Jan 30 at 20:38
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!

| improve this answer | |
  • Do you need to extend the class you're overriding? – Nick Rolando Jan 31 at 17:21
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>
| improve this answer | |
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();
            }

        }
| improve this answer | |

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.