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(