Skip to content
Shopify edited this page Sep 14, 2010 · 22 revisions

#summary A quick overview of adding new a new payment gateway to ActiveMerchant

= Introduction =

This is a brief guide to contributing new payment gateways to Active Merchant. This guide includes instructions on checking out the source code, developing the new gateway, and finally contributing the new gateway back to the project.

= Developing the Gateway =

Following is information on coding the new payment gateway. Also included are some of the common patterns and data structures used by gateways in Active Merchant.

Please note that while some payment gateways use SOAP as the format for communication, we do not accept any gateways that have a requirement on [http://dev.ctor.org/soap4r soap4r]. We find that the overhead required in using the soap4r library is greater than just creating the SOAP document by hand using [http://builder.rubyforge.org/ Builder].

It should also be noted that when there is a choice between the implementation of a Name-Value pair API and an XML API that the Name-Value pair API code will usually be faster to develop, more elegant, and smaller in size than equivalent implementation of the XML API.

== Getting Started ==

= Download the Source =

{{{
svn checkout http://activemerchant.googlecode.com/svn/trunk/active_merchant
}}}

= Generating the Gateway Skeleton =

Then, from the root directory of
Active Merchant, run (replace !CardStream with the name of your gateway):

{{{
> script/generate gateway CardStream
Writing file lib/active_merchant/billing/gateways/card_stream.rb
Writing file test/unit/gateways/card_stream_test.rb
Writing file test/remote_tests/remote_card_stream_test.rb
}}}

Then from here you just want to edit `lib/active_merchant/billing/gateways.rb` to include your new gateway.

At this point it is a good idea to look at other gateways in `lib/active_merchant/billing/gateways/` and the remote tests in `test/remote_tests`
for examples.

The first step is usually getting a successful `purchase()` with the minimum number of required parameters. Most gateways support some or all of the following operations:

  • `purchase(money, creditcard, options = {})`
  • `authorize(money, creditcard, options = {})`
  • `capture(money, identification, options = {})`
  • `void(identification, options = {})`
  • `credit(money, identification, options = {})`

`money` is either a [http://dist.leetsoft.com/api/money/ Money object] responding to the two methods `cents` and `currency` or an `Integer` value in cents. We are removing the support for `money` in the future, so it would be a good idea to pass in integers, and use the `:currency` option for the currency.

== Base Gateway Class ==

The base Gateway class provides a lot of helpful methods that will save you effort when implementing your gateway.

= Setting the Money Format =

There are two different styles for formatting amounts in use:

  • `:dollars` – The amount is formatted as a float dollar amount with two decimal places (Default)
  • `:cents` – The amount is formatted as an integer value in cents

You set the money format using the class accessor `money_format`. For example:

{{{
class ProtxGateway < Gateway
self.money_format = :cents
end
}}}

Setting the money format allows you to use the `amount()` method defined on the base gateway class. Simply pass in the amount, either as a `Money` object, or a as an `Integer` value in cents, and the amount will be formatted appopriately.

= Setting the Default Currency =

You need to set the default currency of the gateway if the gateway supports multiple currencies. This is done by using the class accessor `default_currency`. For example:

{{{
class ProtxGateway < Gateway
self.default_currency = ‘GBP
end
}}}

= Setting the Gateway's Metadata =

Each gateway contains metadata, which are available as class accessors. The metadata is needed for generating documentation, and for intelligent display within applications such as [http://shopify.info Shopify].

  • `Gateway.supported_countries` – sets the countries of merchants the gateway supports.
  • `Gateway.supported_cardtypes` – sets the card types supported by the gateway.
  • `Gateway.homepage_url` – sets the homepage URL of the payment gateway.
  • `Gateway.display_name` – sets the name of the gateway for display purposes, such as generating documentation.
  • `Gateway.application_id` – This is the application making calls to the gateway. This is useful for things like the Paypal build notation (BN) id fields.

== Credit Card Types ==

  • `:visa` – Visa
  • `:master` – !MasterCard
  • `:discover` – Discover Card
  • `:american_express` – American Express
  • `:diners_club` – Diners Club
  • `:jcb` – JCB
  • `:switch` – UK Maestro, formerly Switch
  • `:solo` – Solo
  • `:dankort` – Dankort
  • `:maestro` – International Maestro
  • `:forbrugsforeningen` – Forbrugsforeningen
  • `:laser` – Laser

The Visa Electron, and Visa Delta cards are not in the list because payment gateways accept the cards as the `:visa` card type.

Example usage:

{{{
class AuthorizeNetGateway < Gateway
self.supported_countries = [‘US’]
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
self.homepage_url = ‘http://www.authorize.net/’
self.display_name = ‘Authorize.net’
end
}}}

== Options Hash ==

You shouldn’t be inventing new options
for the options hash that gets passed into the public methods. Try to
look at the other gateways for the hash keys they use as options and
copy those. This allows the easy substitution of one gateway for
another.

The options hash can include the following keys:

  • `:order_id`
  • `:ip`
  • `:customer`
  • `:invoice`
  • `:merchant`
  • `:description`
  • `:email`
  • `:currency`

The reason that the option has has a `:currency` option is because we are phasing out support for the Money object. This means that in the future the money amount will always be an Integer in cents, and the currency will be set by the `:currency` option.

The current pattern to use when setting the currency is:

{{{
options[:currency] || currency(money)
}}}

The `currency()` method is defined in the base `Gateway` class, and will use the currency of the money, if it has one, or return the default currency for the gateway.

There are 3 different addresses you can use. There are
`:billing_address`, `:shipping_address`, or you can just pass in `:address`
and it will be used for both. This is the common pattern to use for
the address:

{{{
billing_address = options[:billing_address] || options[:address]
shipping_address = options[:shipping_address] || billing_address
}}}

  • `:billing_address`
  • `:shipping_address`
  • `:address`

= Address Hash =

The address is a hash with the following keys:

  • `:name`
  • `:company`
  • `:address1`
  • `:address2`
  • `:city`
  • `:state`
  • `:country`
  • `:zip`
  • `:phone`

= Example =

A complete options hash might be:

{{{
options = {
:order_id => ‘1’,
:ip => ‘10.0.0.1’,
:customer => ‘Cody Fauser’,
:description => ‘200 Web 2.0 M&Ms’,
:email => ‘[email protected]’,
:address => {
:name => ‘Cody Fauser’,
..
..
:zip => ‘90210’
}
}
}}}

== Testing ==

There are two types of unit tests for each gateway. The first are the normal unit tests, which test the normal functionality of the gateway, and use [http://mocha.rubyforge.org/ Mocha] to stub out any communications with live servers.

The second type are the remote unit tests. These use real test accounts, if available, and communicate with the test servers of the payments gateway. These are critical to having confidence in the implementation of the gateway. If the gateway doesn’t have a global public test account then you should remove your private test account credentials from the file before submitting your patch. We highly discourage submitting patches that don’t include these remote tests.

= Contributing Your Gateway =

Now that your gateway is coded and tested you need to submit it back to us for inclusion in the project.

== Creating the patch ==

Once you’ve finished the development of your gateway you need to package it up as a patch and contribute it back for permanent addition to the project.

To create your patch you need to add any new files you’ve added to subversion by doing:

{{{
svn add [filename]
}}}

Once all new files are added to subversion you can create your patch, from the root folder of the Active Merchant code:

{{{
svn diff > my_gateway_patch.diff
}}}

The you just have to open a new ticket in the the [http://code.google.com/p/activemerchant/issues/entry Active Merchant bug tracker] so that we can apply your code to the project.

Clone this wiki locally