lib/active_merchant/billing/gateways/mastercard.rb
module ActiveMerchant
module Billing
module MastercardGateway
def initialize(options = {})
requires!(options, :userid, :password)
super
end
def purchase(amount, payment_method, options = {})
if options[:pay_mode]
post = new_post
add_invoice(post, amount, options)
add_reference(post, *new_authorization(options))
add_payment_method(post, payment_method)
add_customer_data(post, payment_method, options)
add_3dsecure_id(post, options)
commit('pay', post)
else
MultiResponse.run do |r|
r.process { authorize(amount, payment_method, options) }
r.process { capture(amount, r.authorization, options) }
end
end
end
def authorize(amount, payment_method, options = {})
post = new_post
add_invoice(post, amount, options)
add_reference(post, *new_authorization(options))
add_payment_method(post, payment_method)
add_customer_data(post, payment_method, options)
add_3dsecure_id(post, options)
commit('authorize', post)
end
def capture(amount, authorization, options = {})
post = new_post
add_invoice(post, amount, options, :transaction)
add_reference(post, *next_authorization(authorization))
add_customer_data(post, nil, options)
add_3dsecure_id(post, options)
commit('capture', post)
end
def refund(amount, authorization, options = {})
post = new_post
add_invoice(post, amount, options, :transaction)
add_reference(post, *next_authorization(authorization))
add_customer_data(post, nil, options)
commit('refund', post)
end
def void(authorization, options = {})
post = new_post
add_reference(post, *next_authorization(authorization), :targetTransactionId)
commit('void', post)
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 verify_credentials
url = build_url(SecureRandom.uuid, 'nonexistent')
begin
ssl_get(url, headers)
rescue ResponseError => e
return false if e.response.code.to_i == 401
end
true
end
def supports_scrubbing?
true
end
def scrub(transcript)
transcript.
gsub(%r((Authorization: Basic ).*\\r\\n), '\1[FILTERED]').
gsub(%r(("number"?\\?":"?\\?")\d*), '\1[FILTERED]').
gsub(%r(("securityCode"?\\?":"?\\?")\d*), '\1[FILTERED]')
end
private
def new_post
{
order: {},
sourceOfFunds: {
provided: {
card: {
}
}
},
customer: {},
billing: {},
device: {},
shipping: {},
transaction: {}
}
end
def add_invoice(post, amount, options, node = :order)
post[node][:amount] = amount(amount)
post[node][:currency] = (options[:currency] || currency(amount))
end
def add_reference(post, orderid, transactionid, transaction_reference, reference_key = :reference)
post[:orderid] = orderid
post[:transactionid] = transactionid
post[:transaction][reference_key] = transaction_reference if transaction_reference
end
def add_payment_method(post, payment_method)
card = {}
card[:expiry] = {}
card[:number] = payment_method.number
card[:securityCode] = payment_method.verification_value
card[:expiry][:year] = format(payment_method.year, :two_digits)
card[:expiry][:month] = format(payment_method.month, :two_digits)
post[:sourceOfFunds][:type] = 'CARD'
post[:sourceOfFunds][:provided][:card].merge!(card)
end
def add_customer_data(post, payment_method, options)
billing = {}
shipping = {}
customer = {}
device = {}
customer[:firstName] = payment_method.first_name if payment_method
customer[:lastName] = payment_method.last_name if payment_method
customer[:email] = options[:email] if options[:email]
device[:ipAddress] = options[:ip] if options[:ip]
if (billing_address = options[:billing_address])
billing[:address] = {}
billing[:address][:street] = billing_address[:address1]
billing[:address][:street2] = billing_address[:address2]
billing[:address][:city] = billing_address[:city]
billing[:address][:stateProvince] = billing_address[:state]
billing[:address][:postcodeZip] = billing_address[:zip]
billing[:address][:country] = country_code(billing_address[:country])
customer[:phone] = billing_address[:phone]
end
if (shipping_address = options[:shipping_address])
shipping[:address] = {}
shipping[:address][:street] = shipping_address[:address1]
shipping[:address][:street2] = shipping_address[:address2]
shipping[:address][:city] = shipping_address[:city]
shipping[:address][:stateProvince] = shipping_address[:state]
shipping[:address][:postcodeZip] = shipping_address[:zip]
shipping[:address][:shipcountry] = country_code(shipping_address[:country])
first_name, last_name = split_names(shipping_address[:name])
shipping[:firstName] = first_name if first_name
shipping[:lastName] = last_name if last_name
end
post[:billing].merge!(billing)
post[:shipping].merge!(shipping)
post[:device].merge!(device)
post[:customer].merge!(customer)
end
def add_3dsecure_id(post, options)
return unless options[:threed_secure_id]
post.merge!({ '3DSecureId' => options[:threed_secure_id] })
end
def country_code(country)
if country
country = ActiveMerchant::Country.find(country)
country.code(:alpha3).value
end
rescue InvalidCountryCodeError
end
def headers
{
'Authorization' => 'Basic ' + Base64.encode64("merchant.#{@options[:userid]}:#{@options[:password]}").strip.delete("\r\n"),
'Content-Type' => 'application/json'
}
end
def commit(action, post)
url = build_url(post.delete(:orderid), post.delete(:transactionid))
post[:apiOperation] = action.upcase
begin
raw = parse(ssl_request(:put, url, build_request(post), headers))
rescue ResponseError => e
raw = parse(e.response.body)
end
succeeded = success_from(raw)
Response.new(
succeeded,
message_from(succeeded, raw),
raw,
authorization: authorization_from(post, raw),
test: test?
)
end
def build_url(orderid, transactionid)
"#{base_url}merchant/#{@options[:userid]}/order/#{orderid}/transaction/#{transactionid}"
end
def base_url
if test?
test_url
else
case @options[:region]
when 'asia_pacific'
live_ap_url
when 'europe'
live_eu_url
when 'north_america', nil
live_na_url
end
end
end
def build_request(post = {})
post.to_json
end
def parse(body)
JSON.parse(body)
end
def success_from(response)
response['result'] == 'SUCCESS'
end
def message_from(succeeded, response)
if succeeded
'Succeeded'
else
[
response['result'],
response['response'] && response['response']['gatewayCode'],
response['error'] && response['error']['cause'],
response['error'] && response['error']['explanation']
].compact.join(' - ')
end
end
def authorization_from(request, response)
[response['order']['id'], response['transaction']['id']].join('|') if response['order']
end
def split_authorization(authorization)
authorization.split('|')
end
def new_authorization(options)
# Must be unique within a merchant id.
orderid = options[:order_id] || SecureRandom.uuid
# Must be unique within an order id.
transactionid = '1'
# New transactions have no previous reference.
transaction_reference = nil
[orderid, transactionid, transaction_reference]
end
def next_authorization(authorization)
orderid, prev_transactionid = split_authorization(authorization)
next_transactionid = SecureRandom.uuid
[orderid, next_transactionid, prev_transactionid]
end
end
end
end