lib/active_merchant/billing/gateways/payway.rb
module ActiveMerchant
module Billing
class PaywayGateway < Gateway
self.live_url = self.test_url = 'https://ccapi.client.qvalent.com/payway/ccapi'
self.supported_countries = ['AU']
self.supported_cardtypes = %i[visa master diners_club american_express bankcard]
self.display_name = 'Pay Way'
self.homepage_url = 'http://www.payway.com.au'
self.default_currency = 'AUD'
self.money_format = :cents
SUMMARY_CODES = {
'0' => 'Approved',
'1' => 'Declined',
'2' => 'Erred',
'3' => 'Rejected'
}
RESPONSE_CODES = {
'00' => 'Completed Successfully',
'01' => 'Refer to card issuer',
'03' => 'Invalid merchant',
'04' => 'Pick-up card',
'05' => 'Do not honour',
'08' => 'Honour only with identification',
'12' => 'Invalid transaction',
'13' => 'Invalid amount',
'14' => 'Invalid card number (no such number)',
'30' => 'Format error',
'36' => 'Restricted card',
'41' => 'Lost card',
'42' => 'No universal card',
'43' => 'Stolen card',
'51' => 'Not sufficient funds',
'54' => 'Expired card',
'61' => 'Exceeds withdrawal amount limits',
'62' => 'Restricted card',
'65' => 'Exceeds withdrawal frequency limit',
'91' => 'Issuer or switch is inoperative',
'92' => 'Financial institution or intermediate network facility cannot be found for routing',
'94' => 'Duplicate transmission',
'Q1' => 'Unknown Buyer',
'Q2' => 'Transaction Pending',
'Q3' => 'Payment Gateway Connection Error',
'Q4' => 'Payment Gateway Unavailable',
'Q5' => 'Invalid Transaction',
'Q6' => 'Duplicate Transaction - requery to determine status',
'QA' => 'Invalid parameters or Initialisation failed',
'QB' => 'Order type not currently supported',
'QC' => 'Invalid Order Type',
'QD' => 'Invalid Payment Amount - Payment amount less than minimum/exceeds maximum allowed limit',
'QE' => 'Internal Error',
'QF' => 'Transaction Failed',
'QG' => 'Unknown Customer Order Number',
'QH' => 'Unknown Customer Username or Password',
'QI' => 'Transaction incomplete - contact Westpac to confirm reconciliation',
'QJ' => 'Invalid Client Certificate',
'QK' => 'Unknown Customer Merchant',
'QL' => 'Business Group not configured for customer',
'QM' => 'Payment Instrument not configured for customer',
'QN' => 'Configuration Error',
'QO' => 'Missing Payment Instrument',
'QP' => 'Missing Supplier Account',
'QQ' => 'Invalid Credit Card Verification Number',
'QR' => 'Transaction Retry',
'QS' => 'Transaction Successful',
'QT' => 'Invalid currency',
'QU' => 'Unknown Customer IP Address',
'QV' => 'Invalid Original Order Number specified for Refund, Refund amount exceeds capture amount, or Previous capture was not approved',
'QW' => 'Invalid Reference Number',
'QX' => 'Network Error has occurred',
'QY' => 'Card Type Not Accepted',
'QZ' => 'Zero value transaction'
}
TRANSACTIONS = {
authorize: 'preauth',
purchase: 'capture',
capture: 'captureWithoutAuth',
status: 'query',
refund: 'refund',
store: 'registerAccount'
}
def initialize(options = {})
@options = options
@options[:merchant] ||= 'TEST' if test?
requires!(options, :username, :password, :merchant, :pem)
@options[:eci] ||= 'SSL'
end
def authorize(amount, payment_method, options = {})
requires!(options, :order_id)
post = {}
add_payment_method(post, payment_method)
add_order(post, amount, options)
commit(:authorize, post)
end
def capture(amount, authorization, options = {})
requires!(options, :order_id)
post = {}
add_reference(post, authorization)
add_order(post, amount, options)
commit(:capture, post)
end
def purchase(amount, payment_method, options = {})
requires!(options, :order_id)
post = {}
add_payment_method(post, payment_method)
add_order(post, amount, options)
commit(:purchase, post)
end
def refund(amount, authorization, options = {})
requires!(options, :order_id)
post = {}
add_reference(post, authorization)
add_order(post, amount, options)
commit(:refund, post)
end
def store(credit_card, options = {})
requires!(options, :billing_id)
post = {}
add_payment_method(post, credit_card)
add_payment_method(post, options[:billing_id])
commit(:store, post)
end
def status(options = {})
requires!(options, :order_id)
commit(:status, 'customer.orderNumber' => options[:order_id])
end
private
def add_payment_method(post, payment_method)
if payment_method.respond_to?(:number)
post['card.cardHolderName'] = "#{payment_method.first_name} #{payment_method.last_name}"
post['card.PAN'] = payment_method.number
post['card.CVN'] = payment_method.verification_value
post['card.expiryYear'] = payment_method.year.to_s[-2, 2]
post['card.expiryMonth'] = sprintf('%02d', payment_method.month)
else
post['customer.customerReferenceNumber'] = payment_method
end
end
def add_reference(post, reference)
post['customer.originalOrderNumber'] = reference
end
def add_order(post, amount, options)
post['order.ECI'] = @options[:eci]
post['order.amount'] = amount
post['card.currency'] = (options[:currency] || currency(amount))
post['customer.orderNumber'] = options[:order_id][0...20]
end
def add_auth(post)
post['customer.username'] = @options[:username]
post['customer.password'] = @options[:password]
post['customer.merchant'] = @options[:merchant]
end
# Creates the request and returns the summarized result
def commit(action, post)
add_auth(post)
post['order.type'] = TRANSACTIONS[action]
request = post.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&')
response = ssl_post(self.live_url, request)
params = {}
CGI.parse(response).each_pair do |key, value|
actual_key = key.split('.').last
params[actual_key.underscore.to_sym] = value[0]
end
message = "#{SUMMARY_CODES[params[:summary_code]]} - #{RESPONSE_CODES[params[:response_code]]}"
success = (params[:summary_code] ? (params[:summary_code] == '0') : (params[:response_code] == '00'))
Response.new(
success,
message,
params,
test: (@options[:merchant].to_s == 'TEST'),
authorization: post[:order_number]
)
rescue ActiveMerchant::ResponseError => e
raise unless e.response.code == '403'
return Response.new(false, 'Invalid credentials', {}, test: test?)
rescue ActiveMerchant::ClientCertificateError
return Response.new(false, 'Invalid certificate', {}, test: test?)
end
end
end
end