How to Create a Payment Method in Magento 2
How to Create a Payment Method in Magento 2

How to Create a Payment Method in Magento 2

Published March 27, 2018 in Development
How to Build a Theme in Magento 2
March 6, 2018

Sometimes you might need more than the standard out-of-the-box payment method. Perhaps you have an agreement with a credit card processor and a solution for their platform is not available. Maybe you need to interject specific logic into the checkout flow to support an ERP. By building a custom payment method, you will be able to customize the fields the user will interact with on checkout and highly customize the API logic used to implement the payment method.

As an example, we’ll look at a scenario where a credit card processor doesn’t have a solution available for Magento 2. So we’ll examine how to add a credit card based payment method to Magento 2. We’ll examine the backend and frontend changes required to make the payment method work and where we can rely on native Magento logic. (Unless otherwise specified, all the following code examples and file paths will be relative to a new Magento module named ClassyLlama_LlamaCoin. For more detailed examples of the code here, you can refer to this GitHub.)

Foundation of a New Payment Method

Configuration

First, in our new module we’ll need to add configuration settings for our payment method. For a custom payment method, you will likely have many additional configuration settings, but here we’re only going to add a few very basic settings. We will need an “enabled” setting, a title to display for our payment method, and a setting for which credit card types we will accept. These will be added in etc/adminhtml/system.xml. These fields, active, title, and cctypes, are used by the core classes we’re extending so make sure to match the field ids exactly. Additionally, it’s important to make sure these fields are added in the payment config namespace as Magento references this namespace when loading configuration fields.

Now we can define default values for the configuration settings we created. Create a new file in the etc folder named config.xml and define your values. There’s an additional field that has been added that we didn’t define in the system.xml file: the field model. This field defines the payment method model for our payment method.

Payment Model

Since the config.xml file tells Magento where to find our payment model class, we want to make sure this class is created: Model\LlamaCoin. This class is where the main logic that processes the payment information is found. The core Magento class defines several methods that we will want to implement in our class: authorize and capture. (There are several other methods defined, like void, but we won’t be implementing them in this example.) Your payment model must extend \Magento\Payment\Model\Method\AbstractMethod; if you’re creating a credit card method, though, you’ll probably want to extend \Magento\Payment\Model\Method\Cc, which provides helpful logic in the validate method. We’ll come back to this model and fill it in later.

After creating the system.xml and config.xml files and defining the base class for our payment method, we can now see our configuration settings in the admin. (Found at Stores > Configuration > Sales > Payment Methods)

Accessing the Configuration Data

On the frontend, we’ll need to give the checkout interface access to our payment method’s configuration fields. To provide this information, we must define a PHP provider class. Magento will use this provider class to store all the checkout-related configuration in the window.checkoutConfig Javascript object. The provider we create will need to implement the \Magento\Checkout\Model\ConfigProviderInterface interface and use the getConfig method to return the data we configured. However, Magento has built a generic class, \Magento\Payment\Model\CcGenericConfigProvider, that implements this required interface and additionally goes through all the available payment methods and gathers all the configuration fields we’ll need. This means we can simply inject our payment method into this CcGenericConfigProvider and it will load our data to the window.checkoutConfig object. Create a new file etc/frontend/di.xml and add our payment method code as an argument.

We have the foundation of our custom payment method in place, and the frontend will be able to access our data, so now we can display the payment method on the frontend.

Displaying the New Payment During Checkout

We’re adding a payment method that will utilize credit cards to checkout. Since Magento natively has several payment methods with credit card templates, we can utilize several core templates to render our payment method.

Javascript

There are two important JS files to add: the payment method renderer and the component that registers the renderer. The contents of the component file, view/frontend/web/js/view/payment/llamacoin.js, are rather simple and only serve to add the renderer:

The file path of the renderer file is view/frontend/web/js/view/payment/method-renderer/. This file handles the frontend logic specific to the new payment method: validation on the form fields and accessor methods for the Knockout template data. In its simplest form, the renderer only needs to include the path to the Knockout template, and this renderer can depend on Magento_Checkout/js/view/payment/default. Since our payment method uses credit card fields, we can extend Magento_Payment/js/view/payment/cc-form. This base JavaScript file (and its associated Knockout template, cc-form.html) provide a form that contains the basic fields and validation for the credit card fields (number, date, type, year, and csv). By depending on these forms, you can leverage a great deal of basic functionality and then customize it to your needs.

Templates

The JS renderer uses Knockout to render the uiComponent. The native templates used in this rendering process are found in the Magento_Payment/view/frontend/web/template/payment/ folder. But we’ll need to add one template, effectively a wrapper around our form, to contain a radio button, title, and billing address for our payment method. Create the new template at /view/frontend/web/template/payment/llamacoin.html. In this template, we’re using Knockout to render the native credit card form and a place to display the address. (This new template is heavily based off the native free.html template in the location referenced above.)

If you need to customize the fields on the credit card form, simply copy forward the native cc-form.html file to your module, update the reference in your JavaScript renderer file, and make your changes to the new template.

Layout

Finally, we need to tell Magento where to include these JavaScript files. Create a new layout file view/frontend/layout/checkout_index_index.xml. (Sections of the file below have been left out. For the entire file, view checkout_index_index.xml in the GitHub example I’ve created.) In this layout file, the new payment method is registered in layout so that it will be included on the checkout page. This XML file contains a reference to the JavaScript component we created.

Now our payment method will be an option during checkout.

Now in order to make our payment method work, we’ll need to update our payment class with logic on how to handle the submitted data.

Payment Method Model

Before our payment model LlamaCoin can be used to process an order, we need to update a few properties: $_canCapture and $_canAuthorize. The payment abstract method class (\Magento\Payment\Model\Method\AbstractMethod) checks these properties before calling the associated methods on our payment model instance. Since we’ll be implementing a capture and authorize method, we will want to change these properties to be true. If your payment method implements methods for voids, refunds, or partial captures, you’ll want to set the corresponding property on your payment method instance. Look through the AbstractMethod class to be familiar with all the available properties.

We’ll need one more property: $_code. The value of this property will be the payment method code that we’re using: “classyllama_llamacoin”. The AbstractMethod class uses this property in the getCode method which is called any time Magento needs to get the payment model code. This means it’s important that the $_code property matches the section name we defined in system.xml. This is used several times, one of which is to set and save the payment method code on the order object.

Now that these properties are in place, we can look at the logic around how an order is processed. When an order is placed, the place method in the \Magento\Sales\Model\Order\Payment class decides how to handle the payment. Several important steps happen during this method:

  1. The place method finds an instance of our payment method model.
  2. The payment is validated. This validation happens in the validate method on the payment model. Since we extended the \Magento\Payment\Model\Method\Cc class, this parent class is used to validate our payment. To customize the validation logic, simply define a validate method in your payment class.
  3. Payment Action. This method determines how the payment will be handled. By default, there are three actions defined as constants on \Magento\Payment\Model\Method\AbstractMethod: order, authorize, and authorize_capture. We’ll need to implement the getConfigPaymentAction method in our class and return the action we want to use. (This option can be made configurable. The Authorize.Net module adds a source model for payment action to make it a configurable field.)
  4. The authorize and capture methods are called. (See full payment model class below.)
  5. We will use two API calls. One to authorize the amount, and one to capture the amount.
  6. Two parameters are passed to the authorize and capture methods. An amount (the total price of the order) and a $payment object which implements the \Magento\Payment\Model\InfoInterface interface. This $payment object will have all data we need to reference set on it. (Credit card data, address info, and order data.) We can now build an array of data to pass to the credit card processor.
  7. makeCaptureRequest and makeAuthRequest have been implemented as placeholder methods that return test data. In reality, these methods would be where you implement specific logic to reach out to the API of a credit card processor.
  8. The capture method first checks to make sure an authorize request has been successful. Once authorization and capture happen, the status of the payment is updated by setting setIsTransationClosed to true.
  9. After the authorize and capture methods, Magento updates the order status and saves the payment data to the database. The order process is now complete!

Here is the final state of the payment method model:

Conclusion

We’ve completed building a custom payment method for Magento. We built the foundational backend configuration settings and model, then we added the frontend changes necessary to display the payment method to the customer, and then added logic to have the model process the payment data. This tutorial can be used as a basis for adding payment methods to Magento. There are many ways to built upon what we’ve done to provide the best experience for the merchant and their customers.

I’ve added all the code for this example to this GitHub. (This example was built and tested on Magento 2.2.2.) Additionally, the Braintree and Authorize.Net modules in the core Magento code provide great examples of how several of these files interact.

1 Comment

  1. mike says:

    I was walking through the tutorial and got a 500 error when i got to the part where you add in the di.xml. Because you are doing an override on Magento\Payment\Model\CcGenericConfigProvider with ClassyLlama\LlamaCoin\Model\LlamaCoin::CODE, Magento will freak out because the Model class doesn’t have the constant in it yet (you add that in at the end). I added that in and all way good with the world again.

Leave a Reply

Your email address will not be published. Required fields are marked *

Related postsView all
February 12, 2018

Display Configurable Product Price Ranges in Magento 2

Today we’re going to look at the advantages of using configurable products and how we can update how their prices display on Magento 2 product listing […]
January 11, 2018

Selling Bundles the Right Way on Magento 2

Magento has a variety of product types to help you find the right way to sell your products. There are downloadable products for digital items (such […]
November 30, 2017

Creating a Shipping Method in Magento 2

There are existing extensions available for many of the shipping carriers that you may choose to utilize on your Magento 2 site, but what about a […]
Most Recent PostsView all
March 6, 2018

How to Build a Theme in Magento 2

When building a custom theme for Magento, it’s important to follow best practices for how the system is designed to be extended. Magento 2’s frontend is […]
February 22, 2018

Does Social Media Affect My SEO?

How do we know if our social posts affect our SEO? We’ve been told it does, we’ve been told it doesn’t. And with Google’s ever-changing algorithm, […]
February 12, 2018

Display Configurable Product Price Ranges in Magento 2

Today we’re going to look at the advantages of using configurable products and how we can update how their prices display on Magento 2 product listing […]