lib/active_merchant/billing/gateways/authorize_net.rb in activemerchant-1.61.0 vs lib/active_merchant/billing/gateways/authorize_net.rb in activemerchant-1.62.0
- old
+ new
@@ -6,18 +6,37 @@
include Empty
self.test_url = 'https://apitest.authorize.net/xml/v1/request.api'
self.live_url = 'https://api2.authorize.net/xml/v1/request.api'
- self.supported_countries = %w(AD AT AU BE BG CA CH CY CZ DE DK EE ES FI FR GB GB GI GR HU IE IL IS IT LI LT LU LV MC MT NL NO PL PT RO SE SI SK SM TR US VA)
+ self.supported_countries = %w(AD AT AU BE BG CA CH CY CZ DE DK EE ES FI FR GB GI GR HU IE IL IS IT LI LT LU LV MC MT NL NO PL PT RO SE SI SK SM TR US VA)
self.default_currency = 'USD'
self.money_format = :dollars
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro]
self.homepage_url = 'http://www.authorize.net/'
self.display_name = 'Authorize.Net'
+ # Authorize.net has slightly different definitions for returned AVS codes
+ # that have been mapped to the closest equivalent AM standard AVSResult codes
+ # Authorize.net's descriptions noted below
+ STANDARD_AVS_CODE_MAPPING = {
+ 'A' => 'A', # Street Address: Match -- First 5 Digits of ZIP: No Match
+ 'B' => 'I', # Address not provided for AVS check or street address match, postal code could not be verified
+ 'E' => 'E', # AVS Error
+ 'G' => 'G', # Non U.S. Card Issuing Bank
+ 'N' => 'N', # Street Address: No Match -- First 5 Digits of ZIP: No Match
+ 'P' => 'I', # AVS not applicable for this transaction
+ 'R' => 'R', # Retry, System Is Unavailable
+ 'S' => 'S', # AVS Not Supported by Card Issuing Bank
+ 'U' => 'U', # Address Information For This Cardholder Is Unavailable
+ 'W' => 'W', # Street Address: No Match -- All 9 Digits of ZIP: Match
+ 'X' => 'X', # Street Address: Match -- All 9 Digits of ZIP: Match
+ 'Y' => 'Y', # Street Address: Match - First 5 Digits of ZIP: Match
+ 'Z' => 'Z' # Street Address: No Match - First 5 Digits of ZIP: Match
+ }
+
STANDARD_ERROR_CODE_MAPPING = {
'36' => STANDARD_ERROR_CODE[:incorrect_number],
'237' => STANDARD_ERROR_CODE[:invalid_number],
'2315' => STANDARD_ERROR_CODE[:invalid_number],
'37' => STANDARD_ERROR_CODE[:invalid_expiry_date],
@@ -59,11 +78,11 @@
APPROVED, DECLINED, ERROR, FRAUD_REVIEW = 1, 2, 3, 4
TRANSACTION_ALREADY_ACTIONED = %w(310 311)
CARD_CODE_ERRORS = %w(N S)
- AVS_ERRORS = %w(A E N R W Z)
+ AVS_ERRORS = %w(A E I N R W Z)
AVS_REASON_CODES = %w(27 45)
TRACKS = {
1 => /^%(?<format_code>.)(?<pan>[\d]{1,19}+)\^(?<name>.{2,26})\^(?<expiration>[\d]{0,4}|\^)(?<service_code>[\d]{0,3}|\^)(?<discretionary_data>.*)\?\Z/,
2 => /\A;(?<pan>[\d]{1,19}+)=(?<expiration>[\d]{0,4}|=)(?<service_code>[\d]{0,3}|=)(?<discretionary_data>.*)\?\Z/
@@ -138,10 +157,11 @@
xml.amount(amount(amount))
add_payment_source(xml, payment)
add_invoice(xml, options)
add_customer_data(xml, payment, options)
+ add_line_items(xml, options)
add_settings(xml, payment, options)
add_user_fields(xml, amount, options)
end
end
end
@@ -211,10 +231,11 @@
xml.amount(amount(amount))
add_payment_source(xml, payment)
add_invoice(xml, options)
add_customer_data(xml, payment, options)
add_market_type_device_type(xml, payment, options)
+ add_line_items(xml, options)
add_settings(xml, payment, options)
add_user_fields(xml, amount, options)
end
end
@@ -324,10 +345,27 @@
else
add_credit_card(xml, source)
end
end
+ def add_line_items(xml, options)
+ return unless options[:line_items]
+ xml.lineItems do
+ options[:line_items].each do |line_item|
+ xml.lineItem do
+ line_item.each do |key, value|
+ xml.send(camel_case_lower(key), value)
+ end
+ end
+ end
+ end
+ end
+
+ def camel_case_lower(key)
+ String(key).split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
+ end
+
def add_settings(xml, source, options)
xml.transactionSettings do
if options[:recurring]
xml.setting do
xml.settingName("recurringBilling")
@@ -344,10 +382,22 @@
set_duplicate_window(xml, options[:duplicate_window])
elsif self.class.duplicate_window
ActiveMerchant.deprecated "Using the duplicate_window class_attribute is deprecated. Use the transaction options hash instead."
set_duplicate_window(xml, self.class.duplicate_window)
end
+ if options[:email_customer]
+ xml.setting do
+ xml.settingName("emailCustomer")
+ xml.settingValue("true")
+ end
+ end
+ if options[:header_email_receipt]
+ xml.setting do
+ xml.settingName("headerEmailReceipt")
+ xml.settingValue(options[:header_email_receipt])
+ end
+ end
end
end
def set_duplicate_window(xml, value)
xml.setting do
@@ -564,11 +614,10 @@
end
end
end
end
-
def names_from(payment_source, address, options)
if payment_source && !payment_source.is_a?(PaymentToken) && !payment_source.is_a?(String)
first_name, last_name = split_names(address[:name])
[(payment_source.first_name || first_name), (payment_source.last_name || last_name)]
else
@@ -594,10 +643,11 @@
def commit(action, &payload)
raw_response = ssl_post(url, post_data(action, &payload), headers)
response = parse(action, raw_response)
- avs_result = AVSResult.new(code: response[:avs_result_code])
+ avs_result_code = response[:avs_result_code].upcase if response[:avs_result_code]
+ avs_result = AVSResult.new(code: STANDARD_AVS_CODE_MAPPING[avs_result_code])
cvv_result = CVVResult.new(response[:card_code])
if using_live_gateway_in_test_mode?(response)
Response.new(false, "Using a live Authorize.net account in Test Mode is not permitted.")
else
Response.new(