Create Custom Payment Method in Magento 2

Posted by

In this article we will be creating a custom payment method which will be used by a customer to place an order. The code given below will create a simple payment method. You will need to do more modification to fit with payment getaway etc.

In Magento 2, a leading e-commerce platform, a diverse array of secure and efficient payment methods is integrated to facilitate seamless transactions. Customers can choose from a variety of options, including credit and debit cards, digital wallets, and bank transfers. The platform supports major payment gateways such as PayPal, Stripe, and Braintree, ensuring a global reach for businesses. The payment process is designed to be user-friendly, providing customers with a smooth checkout experience. Additionally, Magento 2 supports various currencies, making it convenient for businesses operating in different regions. The platform’s flexibility allows merchants to configure and customize payment methods according to their specific requirements, ensuring a tailored and secure payment experience for both businesses and customers.

Developing a custom payment method

Within this article, we shall craft a bespoke payment method tailored for both store administrators and customers. This fundamental payment approach doesn’t necessitate any intricate API integration for a payment gateway. Consider this as the foundation for more intricate developments in the realm of payment systems. The below code for custom payment method is available on github magento_custom_payment_method.

Basic files for a module

Here I will be adding using the module name as Learningmagento_CustomPayment. You can do according to yours.

module.xml

Create module.xml file at app/code/Learningmagento/CustomPayment/etc/module.xml and add the below code in the file.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Learningmagento_CustomPayment" setup_version="1.0.0">
    </module>
</config>

registration.php

Create a file inside the module name registration.php under app/code/Learningmagento/CustomPayment/ and add the below code.

<?php

/**
 *
 * @category  Custom Development
 * @email     contactus@learningmagento.com
 * @author    Avesh Naik
 * @website   learningmagento.com
 * @Date      23-02-2024
 */
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Learningmagento_CustomPayment',
    __DIR__
);

Magento Configuration files

To add a configuration settings you will need to create a file name system.xml under app/code/Learningmagento/CustomPayment/etc/adminhtml/system.xml. Add the following code to add an enable disable dropdown to enable and disable payment method. Add one more field to show the name of the payment method.

system.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <section id="payment">
            <group id="in_store_payment" translate="label" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>Store Payment</label>
                <field id="active" translate="label comment" sortOrder="10" type="select" showInDefault="1" showInWebsite="1" showInStore="0">
                    <label>Enable</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </field>
                <field id="title" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Payment Method Name</label>
                </field>
            </group>
        </section>
     </system>
</config>

The above code will add a payment method inside Configuration->Sales->Payment Method

config.xml

It is also recommended to add a default value for the above settings. To add a default value you will need to add a config.xml file which is responsible to add default values for the configurational settings. Create a file under  app/code/Learningmagento/CustomPayment/etc/config.xml, add the below code.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../Store/etc/config.xsd">
    <default>
        <payment>
            <in_store_payment>
                <payment_action>authorize</payment_action>
                <model>Learningmagento\CustomPayment\Model\PaymentMethod</model>
                <active>1</active>
                <title>In Store</title>
                <order_status>pending_payment</order_status>
            </in_store_payment>
        </payment>
    </default>
</config>

Unlike other settings in this you will need to add 3 more fields which are not there in while adding the system.xml file. These are payment_action, model and order_status. Each of these elements are explained on adobe website on Payment method configuration.

Next you will need to create a model class for the above custom payment method as described in the config.xml file. Create a PaymentMethod.php class under app/code/Learningmagento/CustomPayment/Model and add the below code.

<?php

/**
 *
 * @category  Custom Development
 * @email     contactus@learningmagento.com
 * @author    Avesh Naik
 * @website   learningmagento.com
 * @Date      24-02-2024
 */
namespace Learningmagento\CustomPayment\Model;

class PaymentMethod extends \Magento\Payment\Model\Method\AbstractMethod
{
    const CODE = 'in_store_payment';

    protected $_canAuthorize = 'true';

    protected $_code = self::CODE;
}

We have finished work for backend now the next part is adding this Custom Payment Method on frontend. Where the user will place an order using it.

Frontend Files for Custom Payment Method

The place where the custom payment method must be show is on checkout section. The file which is resposible for checkout is checkout_index_index.xml.

checkout_index_index.xml

Create a file checkout_index_index.xml under app/code/Learningmagento/CustomPayment/view/frontend/layout/checkout_index_index.xml add the below code.

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn: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="component" xsi:type="string">uiComponent</item>
                                            <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">
                                                                <item name="in_store_payment" xsi:type="array">
                                                                    <item name="component" xsi:type="string">Learningmagento_CustomPayment/js/view/payment/method-renderer</item>
                                                                    <item name="methods" xsi:type="array">
                                                                        <item name="in_store_payment" xsi:type="array">
                                                                            <item name="isBillingAddressRequired" xsi:type="boolean">true</item>
                                                                        </item>
                                                                    </item>
                                                                </item>
                                                            </item>
                                                        </item>
                                                    </item>
                                                </item>
                                            </item>
                                        </item>
                                    </item>
                                </item>
                            </item>
                        </item>
                    </item>
                </argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

The code from in_store_payment adds our custom payment method to the checkout process.

<item name="in_store_payment" xsi:type="array">
    <item name="component" xsi:type="string">Learningmagento_CustomPayment/js/view/payment/method-renderer</item>
     <item name="methods" xsi:type="array">
          <item name="in_store_payment" xsi:type="array">
               <item name="isBillingAddressRequired" xsi:type="boolean">true</item>
          </item>
     </item>
</item>

As defined in checkout_index_index.xml, we have to create a renderer file name method-renderer under app/code/Learningmagento/CustomPayment/view/frontend/web/js/view/payment/method-renderer.js

renderer.js

define(
    [
        'uiComponent',
        'Magento_Checkout/js/model/payment/renderer-list'
    ],
    function (
        Component,
        rendererList
    ) {
        'use strict';
        rendererList.push(
            {
                type: 'in_store_payment',
                component: 'Learningmagento_CustomPayment/js/view/payment/method-renderer/in_store_payment'
            }
        );
        return Component.extend({});
    }
);

Component file

Next file in the list is a component file. Create a file under app/code/Learningmagento/CustomPayment/view/frontend/web/js/view/payment/method-renderer/in_store_payment.js

define(
    [
        'Magento_Checkout/js/view/payment/default'
    ],
    function (Component) {
        'use strict';

        return Component.extend({
            defaults: {
                template: 'Learningmagento_CustomPayment/payment/in_store_payment'
            }
        });
    }
);

The last file which is a template file which will serve as a view for the customer when placing an order. Create the last file under app/code/Learningmagento/CustomPayment/view/frontend/web/web/template/payment/in_store_payment.html

<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>

Conclusion

The above given code will create a custom payment method which will be visible on frontend. Do check more of our development by following our development category. We will be using this payment method in creating an order programmatically and any future development.