Creating Custom Payment Method in Magento 2

Out of the box, Magento comes with several payment methods such as Paypal, Braintree, COD, Bank transfer etc. But we might need to create our own custom payment method to meet any specific need to business. generally, there are two types of payment methods:

  1. Offline Payment Method
  2. Online Payment Method

In this blog, we will learn about creating an offline payment method.

We will need to create a custom module with following files:

1. create Excellence/Payment/registration.php (this will be used to register your module)

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Excellence_Payment',
    __DIR__
);

2. Create Excellence/Payment/etc/module.xml (this will be used to define the module)

<?xml version="1.0"?>
<!--
/**
* @copyright Copyright (c) 2015 X.commerce, Inc. (http://www.magentocommerce.com)
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd">
 <module name="Excellence_Payment" setup_version="1.0.0">
 </module>
</config>

3. Create Excellence/Payment/etc/config.xml for define your payment method.

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../Store/etc/config.xsd">
    <default>
        <payment>
                <paymentmethod>
                <active>1</active>
                <title>PaymentMethod</title>
                <order_status>pending_payment</order_status>
                <instructions>Instruction.</instructions>
                <payment_action>true</payment_action>
                <model>Excellence\Payment\Model\PaymentMethod</model>
                <group>offline</group>
            </paymentmethod>
            <!-- payment-config -->
        </payment>
    </default>
</config>

4. Now we will define the system configuration using Excellence/Payment/etc/adminhtml/system.xml, so that admin can handle the configuration of the payment method

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../Config/etc/system_file.xsd">
    <system>
        <section id="payment">
            <group id="paymentmethod" translate="label" type="text" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>Payment</label>
                <field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Enabled</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </field>
                <field id="title" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Title</label>
                </field>
                <field id="order_status" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>New Order Status</label>
                    <source_model>Excellence\Payment\Model\Config\Source\Order\Status\Pendingpayment</source_model>
                </field>
              
                <field id="allowspecific" translate="label" type="allowspecific" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Payment from Applicable Countries</label>
                    <source_model>Magento\Payment\Model\Config\Source\Allspecificcountries</source_model>
                </field>
                <field id="specificcountry" translate="label" type="multiselect" sortOrder="41" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Payment from Specific Countries</label>
                    <source_model>Magento\Directory\Model\Config\Source\Country</source_model>
                    <can_be_empty>1</can_be_empty>
                </field>
                <field id="instructions" translate="label" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Instructions</label>
                </field>
                <field id="sort_order" translate="label" type="text" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Sort Order</label>
                    <frontend_class>validate-number</frontend_class>
                </field>
            </group>
            <!-- payment-group -->
        </section>
    </system>
</config>

5. Now create the model file that we had defined in config.xml at Excellence/Payment/Model/PaymentMethod.php

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Excellence\Payment\Model;

/**
 * Pay In Store payment method model
 */
class PaymentMethod extends \Magento\Payment\Model\Method\AbstractMethod
{

    /**
     * Payment code
     *
     * @var string
     */
    protected $_code = 'paymentmethod';

    /**
     * Availability option
     *
     * @var bool
     */
    protected $_isOffline = true;
}

Now we are done with the basic files and configurations, now we will show the payment method on the frontend.

6. Create Excellence/Payment/view/frontend/web/js/view/payment/paymentmethod.js (it will be used to register the template and render it)

/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
/*browser:true*/
/*global define*/
define(
    [
        'uiComponent',
        'Magento_Checkout/js/model/payment/renderer-list'
    ],
    function (
        Component,
        rendererList
    ) {
        'use strict';
        rendererList.push(
            {
                type: 'paymentmethod',
                component: 'Excellence_Payment/js/view/payment/method-renderer/paymentmethod-method'
            }
        );
        /** Add view logic here if needed */
        return Component.extend({});
    }
);

7. Create Excellence/Payment/view/frontend/web/js/view/payment/method-renderer/paymentmethod-method.js

/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
/*browser:true*/
/*global define*/
define(
    [
        'Magento_Checkout/js/view/payment/default'
    ],
    function(Component) {
        'use strict';

        return Component.extend({
            defaults: {
                template: 'Excellence_Payment/payment/paymentmethod'
            },

            /** Returns send check to info */
            getMailingAddress: function() {
                return window.checkoutConfig.payment.checkmo.mailingAddress;
            },


        });
    }
);

8. Now create the template file at Excellence/Payment/view/frontend/web/template/payment/paymentmethod.html

<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<div class="payment-method" data-bind="css: {'_active': (getCode() == isChecked())}">
    <div class="payment-method-title field choice">
        <input type="radio"
               name="payment[method]"
               class="radio"
               data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()"/>
        <label data-bind="attr: {'for': getCode()}" class="label"><span data-bind="text: getTitle()"></span></label>
    </div>
    <div class="payment-method-content">
        <!-- ko foreach: getRegion('messages') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->
        <div class="payment-method-billing-address">
            <!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) -->
            <!-- ko template: getTemplate() --><!-- /ko -->
            <!--/ko-->
        </div>
        <div class="checkout-agreements-block">
            <!-- ko foreach: $parent.getRegion('before-place-order') -->
                <!-- ko template: getTemplate() --><!-- /ko -->
            <!--/ko-->
        </div>
        <div class="actions-toolbar">
            <div class="primary">
                <button class="action primary checkout"
                        type="submit"
                        data-bind="
                        click: placeOrder,
                        attr: {title: $t('Place Order')},
                        css: {disabled: !isPlaceOrderActionAllowed()},
                        enable: (getCode() == isChecked())
                        "
                        disabled>
                    <span data-bind="i18n: 'Place Order'"></span>
                </button>
            </div>
        </div>
    </div>
</div>

9. Now create Excellence/Payment/view/frontend/layout/checkout_index_index.xml for adding the payment method to checkout page.

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="checkout.root">
            <arguments>
                <argument name="jsLayout" xsi:type="array">
                    <item name="components" xsi:type="array">
                        <item name="checkout" xsi:type="array">
                            <item name="children" xsi:type="array">
                                <item name="steps" xsi:type="array">
                                    <item name="children" xsi:type="array">
                                        <item name="billing-step" xsi:type="array">
                                            <item name="children" xsi:type="array">
                                                <item name="payment" xsi:type="array">
                                                    <item name="children" xsi:type="array">
                                                        <item name="renders" xsi:type="array">
                                                            <item name="children" xsi:type="array">
                                                            <!-- merge payment method renders here -->
                                                                <item name="payment-paymentmethod" xsi:type="array">
                                                                    <item name="component" xsi:type="string">Excellence_Payment/js/view/payment/paymentmethod</item>
                                                                    <item name="methods" xsi:type="array">
                                                                  
                                                                         <item name="paymentmethod" xsi:type="array">
                                                                            <item name="isBillingAddressRequired" xsi:type="boolean">true</item>
                                                                        </item>
                                                                    </item>
                                                                </item>
                                                            <!-- item-renderer -->
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

That’s all folks.

In next blog, we will learn to create online payment method.