lib/active_merchant/billing/gateways/clearhaus.rb
module ActiveMerchant #:nodoc:
module Billing #:nodoc:
class ClearhausGateway < Gateway
self.test_url = 'https://gateway.test.clearhaus.com'
self.live_url = 'https://gateway.clearhaus.com'
self.supported_countries = %w[DK NO SE FI DE CH NL AD AT BE BG HR CY CZ FO GL EE FR GR
HU IS IE IT LV LI LT LU MT PL PT RO SK SI ES GB]
self.default_currency = 'EUR'
self.currencies_without_fractions = %w(BIF CLP DJF GNF JPY KMF KRW PYG RWF UGX VND VUV XAF XOF XPF)
self.supported_cardtypes = %i[visa master]
self.homepage_url = 'https://www.clearhaus.com'
self.display_name = 'Clearhaus'
self.money_format = :cents
ACTION_CODE_MESSAGES = {
20000 => 'Approved',
40000 => 'General input error',
40110 => 'Invalid card number',
40120 => 'Invalid CSC',
40130 => 'Invalid expire date',
40135 => 'Card expired',
40140 => 'Invalid currency',
40200 => 'Clearhaus rule violation',
40300 => '3-D Secure problem',
40310 => '3-D Secure authentication failure',
40400 => 'Backend problem',
40410 => 'Declined by issuer or card scheme',
40411 => 'Card restricted',
40412 => 'Card lost or stolen',
40413 => 'Insufficient funds',
40414 => 'Suspected fraud',
40415 => 'Amount limit exceeded',
50000 => 'Clearhaus error'
}
def initialize(options = {})
requires!(options, :api_key)
options[:private_key] = options[:private_key].strip if options[:private_key]
super
end
def purchase(amount, payment, options = {})
MultiResponse.run(:use_first_response) do |r|
r.process { authorize(amount, payment, options) }
r.process { capture(amount, r.authorization, options) }
end
end
def authorize(amount, payment, options = {})
post = {}
add_invoice(post, amount, options)
action =
if payment.respond_to?(:number)
add_payment(post, payment)
'/authorizations'
elsif payment.kind_of?(String)
"/cards/#{payment}/authorizations"
else
raise ArgumentError.new("Unknown payment type #{payment.inspect}")
end
post[:recurring] = options[:recurring] if options[:recurring]
post[:card][:pares] = options[:pares] if options[:pares]
commit(action, post)
end
def capture(amount, authorization, options = {})
post = {}
add_invoice(post, amount, options)
commit("/authorizations/#{authorization}/captures", post)
end
def refund(amount, authorization, options = {})
post = {}
add_amount(post, amount, options)
commit("/authorizations/#{authorization}/refunds", post)
end
def void(authorization, options = {})
commit("/authorizations/#{authorization}/voids", options)
end
def verify(credit_card, options = {})
MultiResponse.run(:use_first_response) do |r|
r.process { authorize(0, credit_card, options) }
r.process(:ignore_result) { void(r.authorization, options) }
end
end
def store(credit_card, options = {})
post = {}
add_payment(post, credit_card)
commit('/cards', post)
end
def supports_scrubbing?
true
end
def scrub(transcript)
transcript.
gsub(%r((Authorization: Basic )[\w=]+), '\1[FILTERED]').
gsub(%r((&?card(?:\[|%5B)csc(?:\]|%5D)=)[^&]*)i, '\1[FILTERED]').
gsub(%r((&?card(?:\[|%5B)pan(?:\]|%5D)=)[^&]*)i, '\1[FILTERED]')
end
private
def add_invoice(post, money, options)
add_amount(post, money, options)
post[:reference] = options[:order_id] if options[:order_id]
post[:text_on_statement] = options[:text_on_statement] if options[:text_on_statement]
end
def add_amount(post, amount, options)
post[:amount] = localized_amount(amount, options[:currency] || default_currency)
post[:currency] = (options[:currency] || default_currency)
end
def add_payment(post, payment)
card = {}
card[:pan] = payment.number
card[:expire_month] = '%02d' % payment.month
card[:expire_year] = payment.year
card[:csc] = payment.verification_value if payment.verification_value?
post[:card] = card if card.any?
end
def headers(api_key)
{
'Authorization' => 'Basic ' + Base64.strict_encode64("#{api_key}:"),
'User-Agent' => "Clearhaus ActiveMerchantBindings/#{ActiveMerchant::VERSION}"
}
end
def parse(body)
JSON.parse(body) rescue body
end
def commit(action, parameters)
url = (test? ? test_url : live_url) + action
headers = headers(@options[:api_key])
body = parameters.to_query
if @options[:signing_key] && @options[:private_key]
begin
headers['Signature'] = generate_signature(body)
rescue OpenSSL::PKey::RSAError => e
return Response.new(false, e.message)
end
end
response =
begin
parse(ssl_post(url, body, headers))
rescue ResponseError => e
raise unless e.response.code.to_s =~ /400/
parse(e.response.body)
end
Response.new(
success_from(response),
message_from(response),
response,
authorization: authorization_from(action, response),
test: test?,
error_code: error_code_from(response)
)
end
def success_from(response)
(response && (response['status']['code'] == 20000))
end
def message_from(response)
default_message = ACTION_CODE_MESSAGES[response['status']['code']]
if success_from(response)
default_message
else
(response['status']['message'] || default_message)
end
end
def authorization_from(action, response)
id_of_auth_for_capture(action) || response['id']
end
def id_of_auth_for_capture(action)
match = action.match(/authorizations\/(.+)\/captures/)
return nil unless match
match.captures.first
end
def generate_signature(body)
key = OpenSSL::PKey::RSA.new(@options[:private_key])
hex = key.sign(OpenSSL::Digest.new('sha256'), body).unpack1('H*')
"#{@options[:signing_key]} RS256-hex #{hex}"
end
def error_code_from(response)
response['status']['code'] unless success_from(response)
end
end
end
end