Magento 2 - How do I programmatically remove payment method?

We will describe a simple solution based on the Payment Restriction module, where MageWorx – a vendor name and Payment Restriction – a module name.

  1. First, you need to create a directory for the module:

    app/code/MageWorx/PaymentRestriction

  2. Then, add a registration file:

    app/code/MageWorx/PaymentRestriction/registration.php

    <?php
    /**
     * Copyright © 2016 MageWorx. All rights reserved.
     * See LICENSE.txt for license details.
     */
    
    \Magento\Framework\Component\ComponentRegistrar::register(
        \Magento\Framework\Component\ComponentRegistrar::MODULE,
        'MageWorx_PaymentRestriction',
        __DIR__
    );
    
  3. A Composer file (if you decide to transfer the module with the ability to install it using the Composer):

    app/code/MageWorx/PaymentRestriction/composer.json

    {
        "name": "mageworx/module-paymentrestriction",
        "description": "N/A",
        "require": {
            "php": "~5.6.0|~7.0.0"
        },
        "type": "magento2-module",
        "version": "1.0.0",
        "license": [
            "OSL-3.0",
            "AFL-3.0"
        ],
        "autoload": {
            "files": [
                "registration.php"
            ],
            "psr-4": {
                "MageWorx\\PaymentRestriction\\": ""
            }
        }
    }
    
  4. A file with the module declaration:

    app/code/MageWorx/PaymentRestriction/etc/module.xml

    <?xml version="1.0"?>
    <!--
    /**
     * Copyright © 2016 MageWorx. All rights reserved.
     * See LICENSE.txt for license details.
     */
    -->
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
        <module name="MageWorx_PaymentRestriction" setup_version="1.0.0">
        </module>
    </config>
    
  5. Then, we need to create a di.xml file in a common area (this won't work on the Frontend) and declare our plugin in it:

    app/code/MageWorx/PaymentRestriction/etc/di.xml

    <?xml version="1.0"?>
    <!--
    /**
     * Copyright © 2016 MageWorx. All rights reserved.
     * See LICENSE.txt for license details.
     */
    -->
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
        <type name="Magento\OfflinePayments\Model\Cashondelivery">
            <plugin sortOrder="1" name="restrictByCustomer"
                    type="MageWorx\PaymentRestriction\Plugin\Payment\Method\CashOnDelivery\Available"/>
        </type>
    </config>
    
  6. Now, the last and main file with the plugin class that is responsible for the check:

    app/code/MageWorx/PaymentRestriction/Plugin/Payment/Method/CashOnDelivery/Available.php

    <?php
    /**
     * Copyright © 2016 MageWorx. All rights reserved.
     * See LICENSE.txt for license details.
     */
    
    namespace MageWorx\PaymentRestriction\Plugin\Payment\Method\CashOnDelivery;
    
    use Magento\Customer\Model\Session as CustomerSession;
    use Magento\Backend\Model\Auth\Session as BackendSession;
    use Magento\OfflinePayments\Model\Cashondelivery;
    
    class Available
    {
    
        /**
         * @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
         * @throws \Magento\Framework\Exception\LocalizedException
         */
        public function afterIsAvailable(Cashondelivery $subject, $result)
        {
            // Do not remove payment method for admin
            if ($this->backendSession->isLoggedIn()) {
                return $result;
            }
    
            $isLogged = $this->customerSession->isLoggedIn();
            if (!$isLogged) {
                return false;
            }
    
            return $result;
        }
    }
    

For unknown reasons, if you create this plugin only for the frontend, the payment method will be displayed on the checkout page. However, if you try to use it, it will result in an error and return to the checkout. That makes it necessary to validate not only the customer's session but also the admin session. If the admin is logged in, we should not change anything and return the original result.

Also, you can add an additional check on the frontend. For example, you can create a simple module that allows to segment the payment methods according to customer groups. Moreover, you can disable certain payment methods not only for the selected countries (the default option) but also for streets, phone numbers or any other data.

Here is the check:

  1. The Cash on Delivery method is hidden for the not logged in customer:

    The Cash on Delivery method is hidden

  2. The same for the logged in customer:

    enter image description here

  3. Visible:

    enter image description here

  4. Always visible for a store admin:

    enter image description here

Note:

  1. We recommend you to do the same actions in a separate module to have the ability to disable it.

  2. You have to change a vendor and module name to your own.

  3. This solution was created and tested on Magento 2.1.