/binary_merchant

A payment processing utility tool built on top of Active Merchant

Primary LanguageRuby

BinaryMerchant

Update: This gem has been discontinued. Please do not use this gem

It is a payment processing utility tool built on top of Active Merchant .

Currently BinaryMerchant supports AuthorizeNetGateway and AuthorizeNetCimGateway gateways.

The API provided by Authorize.net CIM could be a bit confusing. Active Merchant has good job of hiding the complexity. However BinaryMerchant makes it even simpler.

Show me an example of how BinaryMerchant is simpler than ActiveMerchant

Let's say you are making an authorization request with Authorize.net using AuthorizeNetCimGateway . Using ActiveMechant your code will look like this.

options = { transaction: { type: :auth_only, amount: amount,
                           customer_profile_id: customer_profile_id,
                           customer_payment_profile_id: customer_payment_profile_id }}
response = gateway.create_customer_profile_transaction(options)
if response.success?
  transaction_id = response.params['direct_response']['transaction_id']
else
  transaction_id = nil
end

In the above case method named create_customer_profile_transaction was invoked. Also when you get the response object you need to do response.params['direct_response']['transaction_id'] .

With BinaryMerchant above could could be written as

options = {amount: amount, customer_profile_id: customer_profile_id, customer_payment_id: customer_payment_id}
transaction_id, response = *gateway.authorize(options)

In the above case you are calling a method called authorize which is much better to look at than a method named create_customer_profile_transaction. If the authorization was a success then transaction_id will have a value. If authorization fails then transaction_id will be nil.

Testing with BinaryMerchant without hitting the Authorize.net server

You have built your application using AuthorizeNetCimGateway. Now you want to test your code. Howver you do not want to hit Authorize.net server during tests. Well you can mock the requests with stub . But before that you need to know what params to expect in response. BinaryMerchant has figured all that out for you.

This gem provides a gateway called AuthorizeNetCimMockedGateway and this gateway returns predefined responses and does not hit Authorize.net server.

Put the following code at config/intializers/binary_merchant.rb and now in test you are using mocked gateway.

credentials = { login: login_id_provided_by_authorize_dot_net,
                password: transaction_key_provided_by_authorize_net }

ActiveMerchant::Billing::Base.mode = Rails.env.production? ? :production : :test

gateway_klass = if Rails.env.test?
  ActiveMerchant::Billing::AuthorizeNetCimMockedGateway
else
  ActiveMerchant::Billing::AuthorizeNetCimGateway
end

gateway_klass.logger = Rails.logger

::ADNCIMP = BinaryMerchant::AuthorizeNetCimGateway.new( gateway_klass.new(credentials) )

Above we configured the gateway. Now let's see a concrete example. Let's say whenver a user record is created we want to create customer_profile_id for that record. The code would look something like this.

class User < ActiveRecord::Base
  before_create :create_customer_profile_id

  private

  def create_customer_profile_id
   _vault_id, response = *(ADNCIMP.add_user(email: self.email))
   if _vault_id
     self.vault_id = _vault_id
   else
     raise "customer_profile_id could not be created"
   end
  end
end

Test for above code would be like

describe User do
  context "customer_profile_id" do
    it "without roundtrip" do
      user = Factory(:user)
      user.vault_id.should_not be_nil
      user.vault_id.should == ActiveMerchant::Billing::AuthorizeNetCimMockedGateway::CUSTOMER_PROFILE_ID
    end
  end
end

In the above case the call to gateway is intercepted and a response object is returned.

Testing with BinaryMerchnat with full roundtrip

Testing using above mechanism works. However it has one issue. ActiveMerchant does a number of validation checks while building the xml. In the above case xml is never built. To do exhaustive testing we would like xml to be built. Howver that xml should not be sent to Authorize.net . Here is how you can do full roundtrip testing.

describe User do
  before do
    ADNCIMP.gateway.make_roundtrip = false
  end
  context "customer_profile_id" do
    it "with roundtrip" do
      ADNCIMP.gateway.make_roundtrip = true
      user = Factory(:user)
      user.vault_id.should_not be_nil
      user.vault_id.should == "4581836"
    end
    it "without roundtrip" do
      user = Factory(:user)
      user.vault_id.should_not be_nil
      user.vault_id.should == ActiveMerchant::Billing::AuthorizeNetCimMockedGateway::CUSTOMER_PROFILE_ID
    end
  end
end

By default make_roundtrip value is false.

Stronger validations

ActiveMerchant has validations to ensure that needed require fields are passed. For example when update the customer profile using AuthorizeNetCimGateway the method should look like this

gateway.update_customer_profile({customer_profile_id: '2358805854', email: 'newemail@example.com'})

In the above code if you forget to pass the key customer_profile_id then ActiveMerchant will raise an error indicating that key customer_profile_id is required.

However if you pass the value nil for key customer_profile_id then ActiveMerchant will not complain during validations. However the code fails somewhere deep down and I had to spend some time debugging it. BinaryMerchant strengthenes that validations by ensuring that for every required key the value passed must also be not nil.

Tip: Logging of xml in development

In development you can see the xml that is sent to gateway and the response that is received from the gateway by adding following line.

gateway_klass.logger = Rails.logger