lib/active_merchant/billing/gateways/checkout.rb
require 'rubygems'
require 'nokogiri'
module ActiveMerchant #:nodoc:
module Billing #:nodoc:
class CheckoutGateway < Gateway
self.default_currency = 'USD'
self.money_format = :cents
self.supported_countries = %w[AD AT BE BG CH CY CZ DE DK EE ES FO FI FR GB GI GL GR HR HU IE IS IL IT LI LT LU LV MC MT NL NO PL PT RO SE SI SM SK SJ TR VA]
self.supported_cardtypes = %i[visa master american_express diners_club]
self.homepage_url = 'https://www.checkout.com/'
self.display_name = 'Checkout.com'
self.live_url = 'https://api.checkout.com/Process/gateway.aspx'
ACTIONS = {
'purchase' => '1',
'authorize' => '4',
'capture' => '5',
'refund' => '2',
'void_purchase' => '3',
'void_authorize' => '9',
'void_capture' => '7'
}
def initialize(options = {})
requires!(options, :merchant_id, :password)
super
end
def purchase(amount, payment_method, options)
commit('purchase', amount, options) do |xml|
add_credentials(xml, options)
add_invoice(xml, amount, options)
add_track_id(xml, options[:order_id] || generate_unique_id)
add_payment_method(xml, payment_method)
add_billing_info(xml, options)
add_shipping_info(xml, options)
add_user_defined_fields(xml, options)
add_other_fields(xml, options)
end
end
def authorize(amount, payment_method, options)
commit('authorize', amount, options) do |xml|
add_credentials(xml, options)
add_invoice(xml, amount, options)
add_track_id(xml, options[:order_id] || generate_unique_id)
add_payment_method(xml, payment_method)
add_billing_info(xml, options)
add_shipping_info(xml, options)
add_user_defined_fields(xml, options)
add_other_fields(xml, options)
end
end
def capture(amount, authorization, options = {})
commit('capture', amount, options) do |xml|
add_credentials(xml, options)
add_reference(xml, authorization)
add_invoice(xml, amount, options)
add_user_defined_fields(xml, options)
add_other_fields(xml, options)
end
end
def void(authorization, options = {})
_, _, orig_action, amount, currency = split_authorization(authorization)
commit("void_#{orig_action}") do |xml|
add_credentials(xml, options)
add_invoice(xml, amount.to_i, options.merge(currency: currency))
add_reference(xml, authorization)
end
end
def refund(amount, authorization, options = {})
commit('refund') do |xml|
add_credentials(xml, options)
add_invoice(xml, amount.to_i, options)
add_reference(xml, authorization)
end
end
def verify(credit_card, options = {})
MultiResponse.run(:use_first_response) do |r|
r.process { authorize(100, credit_card, options) }
r.process(:ignore_result) { void(r.authorization, options) }
end
end
private
def add_credentials(xml, options)
xml.merchantid_ @options[:merchant_id]
xml.password_ @options[:password]
end
def add_invoice(xml, amount, options)
xml.bill_amount_ amount(amount)
xml.bill_currencycode_ options[:currency] || currency(amount)
end
def add_payment_method(xml, payment_method)
xml.bill_cardholder_ payment_method.name
xml.bill_cc_ payment_method.number
xml.bill_expmonth_ format(payment_method.month, :two_digits)
xml.bill_expyear_ format(payment_method.year, :four_digits)
xml.bill_cvv2_ payment_method.verification_value if payment_method.verification_value?
end
def add_billing_info(xml, options)
if options[:billing_address]
xml.bill_address_ options[:billing_address][:address1]
xml.bill_city_ options[:billing_address][:city]
xml.bill_state_ options[:billing_address][:state]
xml.bill_postal_ options[:billing_address][:zip]
xml.bill_country_ options[:billing_address][:country]
xml.bill_phone_ options[:billing_address][:phone]
end
end
def add_shipping_info(xml, options)
if options[:shipping_address]
xml.ship_address_ options[:shipping_address][:address1]
xml.ship_address2_ options[:shipping_address][:address2]
xml.ship_city_ options[:shipping_address][:city]
xml.ship_state_ options[:shipping_address][:state]
xml.ship_postal_ options[:shipping_address][:zip]
xml.ship_country_ options[:shipping_address][:country]
xml.ship_phone_ options[:shipping_address][:phone]
end
end
def add_user_defined_fields(xml, options)
xml.udf1_ options[:udf1]
xml.udf2_ options[:udf2]
xml.udf3_ options[:udf3]
xml.udf4_ options[:udf4]
xml.udf5_ options[:udf5]
end
def add_other_fields(xml, options)
xml.bill_email_ options[:email]
xml.bill_customerip_ options[:ip]
xml.merchantcustomerid_ options[:customer]
xml.descriptor_name options[:descriptor_name]
xml.descriptor_city options[:descriptor_city]
end
def add_reference(xml, authorization)
transid, trackid, = split_authorization(authorization)
xml.transid transid
add_track_id(xml, trackid)
end
def add_track_id(xml, trackid)
xml.trackid(trackid) if trackid
end
def commit(action, amount = nil, options = {}, &builder)
response = parse_xml(ssl_post(live_url, build_xml(action, &builder)))
Response.new(
(response[:responsecode] == '0'),
(response[:result] || response[:error_text] || 'Unknown Response'),
response,
authorization: authorization_from(response, action, amount, options),
test: test?
)
end
def build_xml(action)
Nokogiri::XML::Builder.new do |xml|
xml.request do
xml.action_ ACTIONS[action]
yield xml
end
end.to_xml
end
def parse_xml(xml)
response = {}
Nokogiri::XML(CGI.unescapeHTML(xml)).xpath('//response').children.each do |node|
if node.text?
next
elsif node.elements.size == 0
response[node.name.downcase.to_sym] = node.text
else
node.elements.each do |childnode|
name = "#{node.name.downcase}_#{childnode.name.downcase}"
response[name.to_sym] = childnode.text
end
end
end
response
end
def authorization_from(response, action, amount, options)
currency = options[:currency] || currency(amount)
[response[:tranid], response[:trackid], action, amount, currency].join('|')
end
def split_authorization(authorization)
transid, trackid, action, amount, currency = authorization.split('|')
[transid, trackid, action, amount, currency]
end
end
end
end