lib/active_merchant/billing/gateways/verifi.rb
require 'rexml/document'
module ActiveMerchant #:nodoc:
module Billing #:nodoc:
class VerifiGateway < Gateway
class VerifiPostData < PostData
# Fields that will be sent even if they are blank
self.required_fields = %i[amount type ccnumber ccexp firstname lastname
company address1 address2 city state zip country phone]
end
self.live_url = self.test_url = 'https://secure.verifi.com/gw/api/transact.php'
RESPONSE_CODE_MESSAGES = {
'100' => 'Transaction was Approved',
'200' => 'Transaction was Declined by Processor',
'201' => 'Do Not Honor',
'202' => 'Insufficient Funds',
'203' => 'Over Limit',
'204' => 'Transaction not allowed',
'220' => 'Incorrect payment Data',
'221' => 'No Such Card Issuer',
'222' => 'No Card Number on file with Issuer',
'223' => 'Expired Card',
'224' => 'Invalid Expiration Date',
'225' => 'Invalid Card Security Code',
'240' => 'Call Issuer for Further Information',
'250' => 'Pick Up Card',
'251' => 'Lost Card',
'252' => 'Stolen Card',
'253' => 'Fraudulent Card',
'260' => 'Declined With further Instructions Available (see response text)',
'261' => 'Declined - Stop All Recurring Payments',
'262' => 'Declined - Stop this Recurring Program',
'263' => 'Declined - Update Cardholder Data Available',
'264' => 'Declined - Retry in a few days',
'300' => 'Transaction was Rejected by Gateway',
'400' => 'Transaction Error Returned by Processor',
'410' => 'Invalid Merchant Configuration',
'411' => 'Merchant Account is Inactive',
'420' => 'Communication Error',
'421' => 'Communication Error with Issuer',
'430' => 'Duplicate Transaction at Processor',
'440' => 'Processor Format Error',
'441' => 'Invalid Transaction Information',
'460' => 'Processor Feature Not Available',
'461' => 'Unsupported Card Type'
}
SUCCESS = 1
TRANSACTIONS = {
authorization: 'auth',
purchase: 'sale',
capture: 'capture',
void: 'void',
credit: 'credit',
refund: 'refund'
}
self.supported_countries = ['US']
self.supported_cardtypes = %i[visa master american_express discover]
self.homepage_url = 'http://www.verifi.com/'
self.display_name = 'Verifi'
def initialize(options = {})
requires!(options, :login, :password)
super
end
def purchase(money, credit_card, options = {})
sale_authorization_or_credit_template(:purchase, money, credit_card, options)
end
def authorize(money, credit_card, options = {})
sale_authorization_or_credit_template(:authorization, money, credit_card, options)
end
def capture(money, authorization, options = {})
capture_void_or_refund_template(:capture, money, authorization, options)
end
def void(authorization, options = {})
capture_void_or_refund_template(:void, 0, authorization, options)
end
def credit(money, credit_card_or_authorization, options = {})
if credit_card_or_authorization.is_a?(String)
ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
refund(money, credit_card_or_authorization, options)
else
sale_authorization_or_credit_template(:credit, money, credit_card_or_authorization, options)
end
end
def refund(money, reference, options = {})
capture_void_or_refund_template(:refund, money, reference, options)
end
private
def sale_authorization_or_credit_template(trx_type, money, credit_card, options = {})
post = VerifiPostData.new
add_security_key_data(post, options, money)
add_credit_card(post, credit_card)
add_addresses(post, options)
add_customer_data(post, options)
add_invoice_data(post, options)
add_optional_data(post, options)
commit(trx_type, money, post)
end
def capture_void_or_refund_template(trx_type, money, authorization, options)
post = VerifiPostData.new
post[:transactionid] = authorization
commit(trx_type, money, post)
end
def add_credit_card(post, credit_card)
post[:ccnumber] = credit_card.number
post[:ccexp] = expdate(credit_card)
post[:firstname] = credit_card.first_name
post[:lastname] = credit_card.last_name
post[:cvv] = credit_card.verification_value
end
def add_addresses(post, options)
if billing_address = options[:billing_address] || options[:address]
post[:company] = billing_address[:company]
post[:address1] = billing_address[:address1]
post[:address2] = billing_address[:address2]
post[:city] = billing_address[:city]
post[:state] = billing_address[:state]
post[:zip] = billing_address[:zip]
post[:country] = billing_address[:country]
post[:phone] = billing_address[:phone]
post[:fax] = billing_address[:fax]
end
if shipping_address = options[:shipping_address]
post[:shipping_firstname] = shipping_address[:first_name]
post[:shipping_lastname] = shipping_address[:last_name]
post[:shipping_company] = shipping_address[:company]
post[:shipping_address1] = shipping_address[:address1]
post[:shipping_address2] = shipping_address[:address2]
post[:shipping_city] = shipping_address[:city]
post[:shipping_state] = shipping_address[:state]
post[:shipping_zip] = shipping_address[:zip]
post[:shipping_country] = shipping_address[:country]
post[:shipping_email] = shipping_address[:email]
end
end
def add_customer_data(post, options)
post[:email] = options[:email]
post[:ipaddress] = options[:ip]
end
def add_invoice_data(post, options)
post[:orderid] = options[:order_id]
post[:ponumber] = options[:invoice]
post[:orderdescription] = options[:description]
post[:tax] = options[:tax]
post[:shipping] = options[:shipping]
end
def add_optional_data(post, options)
post[:billing_method] = options[:billing_method]
post[:website] = options[:website]
post[:descriptor] = options[:descriptor]
post[:descriptor_phone] = options[:descriptor_phone]
post[:cardholder_auth] = options[:cardholder_auth]
post[:cavv] = options[:cavv]
post[:xid] = options[:xid]
post[:customer_receipt] = options[:customer_receipt]
end
def add_security_key_data(post, options, money)
# MD5(username|password|orderid|amount|time)
now = Time.now.to_i.to_s
md5 = Digest::MD5.new
md5 << @options[:login].to_s + '|'
md5 << @options[:password].to_s + '|'
md5 << options[:order_id].to_s + '|'
md5 << amount(money).to_s + '|'
md5 << now
post[:key] = md5.hexdigest
post[:time] = now
end
def commit(trx_type, money, post)
post[:amount] = amount(money)
response = parse(ssl_post(self.live_url, post_data(trx_type, post)))
Response.new(
response[:response].to_i == SUCCESS,
message_from(response),
response,
test: test?,
authorization: response[:transactionid],
avs_result: { code: response[:avsresponse] },
cvv_result: response[:cvvresponse]
)
end
def message_from(response)
response[:response_code_message] || ''
end
def parse(body)
results = {}
CGI.parse(body).each { |key, value| results[key.intern] = value[0] }
results[:response_code_message] = RESPONSE_CODE_MESSAGES[results[:response_code]] if results[:response_code]
results
end
def post_data(trx_type, post)
post[:username] = @options[:login]
post[:password] = @options[:password]
post[:type] = TRANSACTIONS[trx_type]
post.to_s
end
end
end
end