Skip to content

Add New Payment Gateway

Pikender Sharma edited this page Mar 22, 2016 · 2 revisions

While integrating payments, our goal was to provide an easy & intuitive interface which can lay the ground-work of adding/removing payment_methods and should be a no-brainer.

While we were discussing and finding ways, we came across commerce_billing package which was already integrating bogus-payment and stripe at the time.

We started analysing it for the stripe integration and it appealed us.

Next, we started looking at changes needed in commerce_billing to support braintree integration and have it as the basis to develop something on our own or adapt it.

Integrating braintree was a breeze and we decided to use & extend commerce_billing for payments

We documented the steps to add any new payment gateway as:

  1. Create a module which should implement overridable functions in Commerce.Billing.Gateways.Base

    # web/gateways/new_payment_gateway.ex
    defmodule Nectar.Billing.Gateways.NewPaymentGateway do
      use Commerce.Billing.Gateways.Base
    
      # specific to payment gateway
      # Implement other functions too as needed from 
      # [purchase, capture, void, refund, store, unstore]
      def authorize(amount, nonce, options \\ :empty) do
        {:ok}
      end
    end
  2. Add a configuration to tell which module implements New Payment Gateway

    # config/dev.secret.exs
    
    config :nectar, :new_payment_gateway,
     type: Nectar.Billing.Gateways.NewPaymentGateway
  3. To leverage one process per payment gateway, we will start a Genserver as implemented in Commerce.Billing.Worker for new payment gateway too and will add as a children to App Supervisor

    # in lib/nectar.ex
      def start(_type, _args) do
         import Supervisor.Spec, warn: false
         ...
         children = [
           ...
           # Note: *id* should be different to start same worker with different configuration.
           # *id* is optional parameter so can be skipped but workers won't start without it
           worker(Commerce.Billing.Worker, new_payment_gateway_configuration, id: :new_payment_gateway)
           ...
         ]
    
      # Note: Configuration parsing can change, if
      # way to define configuration changed
      def new_payment_gateway_configuration do
        worker_config = Application.get_env(:nectar, :new_payment_gateway)
        gateway_type = worker_config[:type]
        settings = %{}
        [gateway_type, settings, [name: :new_payment_gateway]]
      end
    ...
    
  4. In web/gateways/gateway.ex, a pattern match need to be added for new payment gateway to get invoked, when chosen as payment_method of choice while processing order

    # web/gateways/gateway.ex
      defp do_authorize_payment(order, "new_payment_gateway", payment_method_params) do
        # Use Commerce.Billing instead of Module implementing authorize
        # to leverage GenServer created for each payment Gateway
        # Below, will dispatch `authorize` to the dedicated GenServer for it
        # which in turn will call App Module implementing `authorize`
        # Direct call like
        # Nectar.Billing.Gateway.NewPaymentGateway.authorize(order, payment_method_params["new_payment_gateway"])
        # above will leave the GenServer created useless / idle
        # Refer web/gateways/braintree.ex and web/gateways/braintree_impl.ex for using call like above :)
        Commerce.Billing.authorize(:new_payment_gateway,
          String.to_float(Decimal.to_string(order.total)),
          "123",
          # Refer web/gateways/braintree.ex for better separation and extraction
          billing_address: %Commerce.Billing.Address{
            street1: "House No - Unknown",
            street2: "Street Name",
            city:    "City Name",
            region:  "India",
            country: "India",
            postal_code: "121005"
          },
          description: "Order No. #{order.id}"
        )
      end
  5. As available payment methods are fetched from DB and shown on order payment page.

    It's better to add the new payment gateway in DB.

    Please make sure that name used in web/gateways/gateway.ex while pattern-match should be same as in DB or make arrangements to make pattern-match behave correctly for new payment method

  6. Finally, make sure that needed parameters for new payment gateway can be asked from user and passed for processing.

    Create a template as payment.new-payment-gateway-name.html.eex.

    Note new-payment-gateway-name is used to find the template while displaying payment methods view, so this also have to be same as payment gateway name as stored in DB.

  7. Payment Methods can be enabled/disabled from Settings

Refer web/templates/admin/checkout/payment.braintree.html.eex and not braintree

You can also refer for final changes at once at [New Payment Gateway] Minimal Payment Gateway Integration #23

Clone this wiki locally