The following is the extension of the ActiveMerchant gem that will allow the system to store information about the customer and its credit card in realex, typically this is used for recurring payments (in fact it's the name of the pdf provided by Realex), but in our case the need was for charging customers that don't show up at the hotel. It's not the final refactory.
# see: RealVault - Recurring Payments.pdf
module ActiveMerchant::Billing
class RealVault < RealexGateway
# 7. on page 24
URL = 'https://check-doc.cgi'
# 7.1 (Setup a new Payer)
# Create a Profile for a payer using payer‐new
# If the payer exists another one will be stored
# payer is a hash (see self.test)
def send_payer(payer, options = {})
requires! options, :order_id
request = build_payer_new_request payer, options
commit request, URL
end
# 7.2 (Payment method setup)
# Store the Card details using Card‐New
# If the card exists another one will be stored
# card is a ActiveMerchant::Billing::CreditCard
# options is a hash
def send_card(card, options)
requires! options, :order_id
request = build_card_new_request card, options
commit request, URL
end
# see self.test or send_x methods
def store!(payer, card, options)
send_payer_response = send_payer(payer, options)
send_card_response = send_card(card, options) if send_payer_response.success?
{ :success? => (send_payer_response.success? && send_card_response.success?),
:send_payer_response => send_payer_response,
:send_card_response => send_card_response }
end
# ActiveMerchant::Billing::RealVault.test
# will store the payer and the card in the test account
# makes a purchase before as suggested by the doc. to make sure auth is ok
# works out of the box
def self.test
timestamp = Time.new.to_s :number
currency = 'EUR'
firstname = 'John'
surname = 'Smith'
payerref = timestamp
orderid = timestamp
rv = ActiveMerchant::Billing::RealVault.new({:password => "pwd",
:currency => currency,
:rebate => "rebate",
:account => "internettest",
:login => "merchant_id",
:gateway => "Realex"})
card = ActiveMerchant::Billing::CreditCard.new(
:number => 'test_cc_number',
:month => '12',
:year => '2012',
:type => 'visa',
:first_name => firstname,
:last_name => surname,
:verification_value => '123')
payer = { :type => 'Business',
:ref => payerref, # 'smithj01'
:title => 'Mr',
:firstname => firstname,
:surname => surname,
:email => 'jsmith@acme.com',
:company => 'Acme Inc',
:address => {
:line1 => '123 Fake St.',
# :line2
# :line3
:postcode => '3',
:city => 'Hytown',
:county => 'Dunham',
:country => 'Ireland',
:country_code => 'IE'
},
:phonenumbers => {
:home => '55555555',
:work => '+35317433923',
:fax => '+35317893248',
:mobile => '+353873748392',
}
}
options = {:order_id => orderid,
:currency => currency,
:payerref => payer[:ref]}
rv.purchase 777, card, options
rv.store! payer, card, options
# rv.send_payer payer, options
# rv.send_card card, options
end
private
def build_card_new_request(card, options)
action = 'card-new'
timestamp = Time.now.strftime '%Y%m%d%H%M%S' # same as to_s(:number), but not subjected to override
orderid = sanitize_order_id options[:order_id]
chname = "#{card.first_name}#{card.last_name}"
expdate = card.year.to_s[2..3] + card.month.to_s
sha1 = sha1from "#{timestamp}.#{@options[:login]}.#{orderid}...#{options[:payerref]}.#{chname}.#{card.number}"
xml = Builder::XmlMarkup.new :indent => 2
xml.tag! :request, :timestamp => timestamp, :type => action do
xml.tag! :merchantid, @options[:login]
xml.tag! :orderid , orderid
xml.tag! :card do
xml.tag! :ref , card.type + timestamp[3..14]
xml.tag! :payerref, options[:payerref]
xml.tag! :number , card.number
xml.tag! :expdate , expdate
xml.tag! :chname , chname
xml.tag! :type , CARD_MAPPING[card_brand(card).to_s]
xml.tag! :issueno
end
xml.tag! :sha1hash, sha1
end
end
def build_payer_new_request(payer, options)
action = 'payer-new'
timestamp = Time.now.strftime '%Y%m%d%H%M%S' # same as to_s(:number), but not subjected to override
orderid = sanitize_order_id options[:order_id]
sha1 = sha1from "#{timestamp}.#{@options[:login]}.#{orderid}...#{payer[:ref]}"
xml = Builder::XmlMarkup.new :indent => 2
xml.tag! :request, :timestamp => timestamp, :type => action do
xml.tag! :merchantid, @options[:login]
xml.tag! :account , @options[:account]
xml.tag! :orderid , orderid
xml.tag! :payer, :type => payer[:type], :ref => payer[:ref] do
[:title, :firstname, :surname, :company].each do |tag|
xml.tag! tag, payer.send('[]', tag)
end
xml.tag! :address do
address = payer[:address]
[:line1, :line2, :line3, :city, :county, :postcode].each do |tag|
xml.tag! tag, address.send('[]', tag)
end
xml.tag! :country, address[:country], :code => address[:country_code]
end
xml.tag! :phonenumbers do
phonenumbers = payer[:phonenumbers]
[:home, :work, :fax, :mobile].each do |tag|
xml.tag! tag, phonenumbers[tag]
end
end
xml.tag! :email, payer[:email]
xml.tag! :comments do
xml.tag! :comment, nil, :id => 1
xml.tag! :comment, nil, :id => 2
end
end
xml.tag! :sha1hash, sha1
xml.tag! :comments do
xml.tag! :comment, nil, :id => 1
xml.tag! :comment, nil, :id => 2
end
end
xml.target!
end
end
end
Unfortunately even the gem itself needed a slight change, due to constant priority order in Ruby (this wouldn't be necessary in java for example):
# Realex.rb in ActiveMerchant 1.9.4
# commit method in private section
- def commit(request)
+ def commit(request, url = URL)
No comments:
Post a Comment