require 'nokogiri'
module ActiveMerchant #:nodoc:
module Billing #:nodoc:
class S5Gateway < Gateway
self.test_url = 'https://test.ctpe.io/payment/ctpe'
self.live_url = 'https://ctpe.io/payment/ctpe'
self.supported_countries = ['DK']
self.default_currency = 'EUR'
self.supported_cardtypes = [:visa, :master, :maestro]
self.homepage_url = 'http://www.s5.dk/'
self.display_name = 'S5'
SUPPORTED_TRANSACTIONS = {
'sale' => 'CC.DB',
'authonly' => 'CC.PA',
'capture' => 'CC.CP',
'refund' => 'CC.RF',
'void' => 'CC.RV',
'store' => 'CC.RG'
}
def initialize(options={})
requires!(options, :sender, :channel, :login, :password)
super
end
def purchase(money, payment, options={})
request = build_xml_request do |xml|
add_identification(xml, options)
add_payment(xml, money, 'sale', options)
add_account(xml, payment)
add_customer(xml, payment, options)
add_recurrence_mode(xml, options)
end
commit(request)
end
def refund(money, authorization, options={})
request = build_xml_request do |xml|
add_identification(xml, options, authorization)
add_payment(xml, money, 'refund', options)
end
commit(request)
end
def authorize(money, payment, options={})
request = build_xml_request do |xml|
add_identification(xml, options)
add_payment(xml, money, 'authonly', options)
add_account(xml, payment)
add_customer(xml, payment, options)
add_recurrence_mode(xml, options)
end
commit(request)
end
def capture(money, authorization, options={})
request = build_xml_request do |xml|
add_identification(xml, options, authorization)
add_payment(xml, money, 'capture', options)
end
commit(request)
end
def void(authorization, options={})
request = build_xml_request do |xml|
add_identification(xml, options, authorization)
add_payment(xml, nil, 'void', options)
end
commit(request)
end
def store(payment, options = {})
request = build_xml_request do |xml|
xml.Payment(code: SUPPORTED_TRANSACTIONS['store'])
add_account(xml, payment)
add_customer(xml, payment, options)
add_recurrence_mode(xml, options)
end
commit(request)
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
def supports_scrubbing?
true
end
def scrub(transcript)
transcript.
gsub(%r((pwd=).+?(/>))i, '\1[FILTERED]\2').
gsub(%r(().+?())i, '\1[FILTERED]\2').
gsub(%r(().+?())i, '\1[FILTERED]\2')
end
private
def add_identification(xml, options, authorization = nil)
xml.Identification do
xml.TransactionID options[:order_id] if options[:order_id]
xml.ReferenceID authorization if authorization
end
end
def add_payment(xml, money, action, options)
xml.Payment(code: SUPPORTED_TRANSACTIONS[action]) do
xml.Memo "return_code=#{options[:memo]}" if options[:memo]
xml.Presentation do
xml.Amount amount(money)
xml.Currency options[:currency] || currency(money)
xml.Usage options[:description]
end
end
end
def add_account(xml, payment_method)
if !payment_method.respond_to?(:number)
xml.Account(registration: payment_method)
else
xml.Account do
xml.Number payment_method.number
xml.Holder "#{payment_method.first_name} #{payment_method.last_name}"
xml.Brand payment_method.brand
xml.Expiry(year: payment_method.year, month: payment_method.month)
xml.Verification payment_method.verification_value
end
end
end
def add_customer(xml, creditcard, options)
return unless creditcard.respond_to?(:number)
address = options[:billing_address]
xml.Customer do
xml.Contact do
xml.Email options[:email]
xml.Ip options[:ip]
xml.Phone address[:phone] if address
end
add_address(xml, address)
xml.Name do
xml.Given creditcard.first_name
xml.Family creditcard.last_name
xml.Company options[:company]
end
end
end
def add_address(xml, address)
return unless address
xml.Address do
xml.Street "#{address[:address1]} #{address[:address2]}"
xml.Zip address[:zip]
xml.City address[:city]
xml.State address[:state]
xml.Country address[:country]
end
end
def add_recurrence_mode(xml, options)
if options[:recurring] == true
xml.Recurrence(mode: 'REPEATED')
else
xml.Recurrence(mode: 'INITIAL')
end
end
def parse(body)
results = {}
xml = Nokogiri::XML(body)
resp = xml.xpath('//Response/Transaction/Identification')
resp.children.each do |element|
results[element.name.downcase.to_sym] = element.text
end
resp = xml.xpath('//Response/Transaction/Processing')
resp.children.each do |element|
results[element.name.downcase.to_sym] = element.text
end
results
end
def commit(xml)
url = (test? ? test_url : live_url)
headers = {
'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'
}
response = parse(ssl_post(url, post_data(xml), headers))
Response.new(
success_from(response),
message_from(response),
response,
authorization: authorization_from(response),
test: test?
)
end
def success_from(response)
response[:result] == 'ACK'
end
def message_from(response)
response[:return]
end
def authorization_from(response)
response[:uniqueid]
end
def post_data(xml)
"load=#{xml}"
end
def build_xml_request
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
xml.Request(version: '1.0') do
xml.Header do
xml.Security(sender: @options[:sender])
end
xml.Transaction(mode: @options[:mode] || 'LIVE', channel: @options[:channel]) do
xml.User(login: @options[:login], pwd: @options[:password])
yield(xml)
end
end
end
builder.to_xml
end
end
end
end