class ActiveMerchant::Billing::AuthorizeNetGateway
Constants
- APPLE_PAY_DATA_DESCRIPTOR
- AVS_ERRORS
- AVS_REASON_CODES
- CARD_CODE_ERRORS
- FRAUD_REVIEW
- MARKET_TYPE
- STANDARD_ERROR_CODE_MAPPING
- TRACKS
- TRANSACTION_ALREADY_ACTIONED
Public Class Methods
new(options={})
click to toggle source
Calls superclass method
ActiveMerchant::Billing::Gateway::new
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 59 def initialize(options={}) requires!(options, :login, :password) super end
Public Instance Methods
capture(amount, authorization, options={})
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 98 def capture(amount, authorization, options={}) commit("PRIOR_AUTH_CAPTURE") do |xml| add_order_id(xml, options) xml.transactionRequest do xml.transactionType('priorAuthCaptureTransaction') xml.amount(amount(amount)) xml.refTransId(split_authorization(authorization)[0]) add_invoice(xml, options) add_user_fields(xml, amount, options) end end end
credit(amount, payment, options={})
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 144 def credit(amount, payment, options={}) if payment.is_a?(String) raise ArgumentError, "Reference credits are not supported. Please supply the original credit card or use the #refund method." end commit("CREDIT") do |xml| add_order_id(xml, options) xml.transactionRequest do xml.transactionType('refundTransaction') xml.amount(amount(amount)) add_payment_source(xml, payment) add_invoice(xml, options) add_customer_data(xml, payment, options) add_settings(xml, payment, options) add_user_fields(xml, amount, options) end end end
purchase(amount, payment, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 64 def purchase(amount, payment, options = {}) commit("AUTH_CAPTURE") do |xml| add_order_id(xml, options) xml.transactionRequest do xml.transactionType('authCaptureTransaction') xml.amount(amount(amount)) add_payment_source(xml, payment) add_invoice(xml, options) add_customer_data(xml, payment, options) add_market_type(xml, payment) add_settings(xml, payment, options) add_user_fields(xml, amount, options) end end end
refund(amount, authorization, options={})
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 112 def refund(amount, authorization, options={}) transaction_id, card_number = split_authorization(authorization) commit("CREDIT") do |xml| xml.transactionRequest do xml.transactionType('refundTransaction') xml.amount(amount.nil? ? 0 : amount(amount)) xml.payment do xml.creditCard do xml.cardNumber(card_number || options[:card_number]) xml.expirationDate('XXXX') end end xml.refTransId(transaction_id) add_customer_data(xml, nil, options) add_user_fields(xml, amount, options) end end end
scrub(transcript)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 175 def scrub(transcript) transcript. gsub(%r((<cardNumber>).+(</cardNumber>)), '\1[FILTERED]\2'). gsub(%r((<cardCode>).+(</cardCode>)), '\1[FILTERED]\2') end
supports_scrubbing?()
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 171 def supports_scrubbing? true end
verify(credit_card, options = {})
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 164 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
void(authorization, options={})
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 132 def void(authorization, options={}) commit("VOID") do |xml| add_order_id(xml, options) xml.transactionRequest do xml.transactionType('voidTransaction') xml.refTransId(split_authorization(authorization)[0]) add_user_fields(xml, nil, options) end end end
Private Instance Methods
add_apple_pay_payment_token(xml, apple_pay_payment_token)
click to toggle source
developer.authorize.net/api/reference/#apple-pay-transactions
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 268 def add_apple_pay_payment_token(xml, apple_pay_payment_token) xml.payment do xml.opaqueData do xml.dataDescriptor(APPLE_PAY_DATA_DESCRIPTOR) xml.dataValue(Base64.strict_encode64(apple_pay_payment_token.payment_data.to_json)) end end end
add_check(xml, check)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 294 def add_check(xml, check) xml.payment do xml.bankAccount do xml.routingNumber(check.routing_number) xml.accountNumber(check.account_number) xml.nameOnAccount(check.name) xml.echeckType("WEB") xml.bankName(check.bank_name) xml.checkNumber(check.number) end end end
add_credit_card(xml, credit_card)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 235 def add_credit_card(xml, credit_card) if credit_card.track_data add_swipe_data(xml, credit_card) else xml.payment do xml.creditCard do xml.cardNumber(truncate(credit_card.number, 16)) xml.expirationDate(format(credit_card.month, :two_digits) + '/' + format(credit_card.year, :four_digits)) if credit_card.valid_card_verification_value?(credit_card.verification_value, credit_card.brand) xml.cardCode(credit_card.verification_value) end if credit_card.is_a?(NetworkTokenizationCreditCard) xml.cryptogram(credit_card.payment_cryptogram) end end end end end
add_customer_data(xml, payment_source, options)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 307 def add_customer_data(xml, payment_source, options) billing_address = options[:billing_address] || options[:address] || {} shipping_address = options[:shipping_address] || options[:address] || {} xml.customer do xml.id(options[:customer]) unless empty?(options[:customer]) || options[:customer] !~ /^\d+$/ xml.email(options[:email]) unless empty?(options[:email]) end xml.billTo do first_name, last_name = names_from(payment_source, billing_address, options) xml.firstName(truncate(first_name, 50)) unless empty?(first_name) xml.lastName(truncate(last_name, 50)) unless empty?(last_name) xml.company(truncate(billing_address[:company], 50)) unless empty?(billing_address[:company]) xml.address(truncate(billing_address[:address1], 60)) xml.city(truncate(billing_address[:city], 40)) xml.state(empty?(billing_address[:state]) ? 'n/a' : truncate(billing_address[:state], 40)) xml.zip(truncate((billing_address[:zip] || options[:zip]), 20)) xml.country(truncate(billing_address[:country], 60)) xml.phoneNumber(truncate(billing_address[:phone], 25)) unless empty?(billing_address[:phone]) xml.faxNumber(truncate(billing_address[:fax], 25)) unless empty?(billing_address[:fax]) end unless shipping_address.blank? xml.shipTo do (first_name, last_name) = if shipping_address[:name] shipping_address[:name].split else [shipping_address[:first_name], shipping_address[:last_name]] end xml.firstName(truncate(first_name, 50)) unless empty?(first_name) xml.lastName(truncate(last_name, 50)) unless empty?(last_name) xml.company(truncate(shipping_address[:company], 50)) unless empty?(shipping_address[:company]) xml.address(truncate(shipping_address[:address1], 60)) xml.city(truncate(shipping_address[:city], 40)) xml.state(truncate(shipping_address[:state], 40)) xml.zip(truncate(shipping_address[:zip], 20)) xml.country(truncate(shipping_address[:country], 60)) end end xml.customerIP(options[:ip]) unless empty?(options[:ip]) xml.cardholderAuthentication do xml.authenticationIndicator(options[:authentication_indicator]) xml.cardholderAuthenticationValue(options[:cardholder_authentication_value]) end end
add_invoice(xml, options)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 362 def add_invoice(xml, options) xml.order do xml.invoiceNumber(truncate(options[:order_id], 20)) xml.description(truncate(options[:description], 255)) end end
add_market_type(xml, payment)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 277 def add_market_type(xml, payment) return if card_brand(payment) == 'check' or card_brand(payment) == 'apple_pay' if valid_track_data xml.retail do xml.marketType(MARKET_TYPE[:retail]) end elsif payment.manual_entry xml.retail do xml.marketType(MARKET_TYPE[:moto]) end end end
add_order_id(xml, options)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 358 def add_order_id(xml, options) xml.refId(truncate(options[:order_id], 20)) end
add_payment_source(xml, source)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 183 def add_payment_source(xml, source) return unless source if card_brand(source) == 'check' add_check(xml, source) elsif card_brand(source) == 'apple_pay' add_apple_pay_payment_token(xml, source) else add_credit_card(xml, source) end end
add_settings(xml, source, options)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 194 def add_settings(xml, source, options) xml.transactionSettings do if card_brand(source) == "check" && options[:recurring] xml.setting do xml.settingName("recurringBilling") xml.settingValue("true") end end if options[:duplicate_window] 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 end end
add_swipe_data(xml, credit_card)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 254 def add_swipe_data(xml, credit_card) TRACKS.each do |key, regex| if regex.match(credit_card.track_data) @valid_track_data = true xml.payment do xml.trackData do xml.public_send(:"track#{key}", credit_card.track_data) end end end end end
add_user_fields(xml, amount, options)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 218 def add_user_fields(xml, amount, options) xml.userFields do if currency = (options[:currency] || currency(amount)) xml.userField do xml.name("x_currency_code") xml.value(currency) end end if application_id.present? && application_id != "ActiveMerchant" xml.userField do xml.name("x_solution_id") xml.value(application_id) end end end end
commit(action, &payload)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 378 def commit(action, &payload) url = (test? ? test_url : live_url) response = parse(action, ssl_post(url, post_data(&payload), 'Content-Type' => 'text/xml')) avs_result = AVSResult.new(code: response[: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( success_from(response), message_from(response, avs_result, cvv_result), response, authorization: authorization_from(response), test: test?, avs_result: avs_result, cvv_result: cvv_result, fraud_review: fraud_review?(response), error_code: map_error_code(response[:response_code], response[:response_reason_code]) ) end end
fraud_review?(response)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 496 def fraud_review?(response) (response[:response_code] == FRAUD_REVIEW) end
map_error_code(response_code, response_reason_code)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 505 def map_error_code(response_code, response_reason_code) STANDARD_ERROR_CODE_MAPPING[response_code.to_s << response_reason_code.to_s] end
message_from(response, avs_result, cvv_result)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 475 def message_from(response, avs_result, cvv_result) if response[:response_code] == DECLINED if CARD_CODE_ERRORS.include?(cvv_result.code) return cvv_result.message elsif(AVS_REASON_CODES.include?(response[:response_reason_code]) && AVS_ERRORS.include?(avs_result.code)) return avs_result.message end end response[:response_reason_text] end
names_from(payment_source, address, options)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 369 def names_from(payment_source, address, options) if payment_source && !payment_source.is_a?(PaymentToken) first_name, last_name = (address[:name] || "").split [(payment_source.first_name || first_name), (payment_source.last_name || last_name)] else [options[:first_name], options[:last_name]] end end
parse(action, body)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 413 def parse(action, body) doc = Nokogiri::XML(body) doc.remove_namespaces! response = {action: action} response[:response_code] = if(element = doc.at_xpath("//transactionResponse/responseCode")) (empty?(element.content) ? nil : element.content.to_i) end if(element = doc.at_xpath("//errors/error")) response[:response_reason_code] = element.at_xpath("errorCode").content[/0*(\d+)$/, 1] response[:response_reason_text] = element.at_xpath("errorText").content.chomp('.') elsif(element = doc.at_xpath("//transactionResponse/messages/message")) response[:response_reason_code] = element.at_xpath("code").content[/0*(\d+)$/, 1] response[:response_reason_text] = element.at_xpath("description").content.chomp('.') elsif(element = doc.at_xpath("//messages/message")) response[:response_reason_code] = element.at_xpath("code").content[/0*(\d+)$/, 1] response[:response_reason_text] = element.at_xpath("text").content.chomp('.') else response[:response_reason_code] = nil response[:response_reason_text] = "" end response[:avs_result_code] = if(element = doc.at_xpath("//avsResultCode")) (empty?(element.content) ? nil : element.content) end response[:transaction_id] = if(element = doc.at_xpath("//transId")) (empty?(element.content) ? nil : element.content) end response[:card_code] = if(element = doc.at_xpath("//cvvResultCode")) (empty?(element.content) ? nil : element.content) end response[:authorization_code] = if(element = doc.at_xpath("//authCode")) (empty?(element.content) ? nil : element.content) end response[:cardholder_authentication_code] = if(element = doc.at_xpath("//cavvResultCode")) (empty?(element.content) ? nil : element.content) end response[:account_number] = if(element = doc.at_xpath("//accountNumber")) (empty?(element.content) ? nil : element.content[-4..-1]) end response[:test_request] = if(element = doc.at_xpath("//testRequest")) (empty?(element.content) ? nil : element.content) end response end
post_data() { |xml| ... }
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 401 def post_data Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml| xml.createTransactionRequest('xmlns' => 'AnetApi/xml/v1/schema/AnetApiSchema.xsd') do xml.merchantAuthentication do xml.name(@options[:login]) xml.transactionKey(@options[:password]) end yield(xml) end end.to_xml(indent: 0) end
set_duplicate_window(xml, value)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 211 def set_duplicate_window(xml, value) xml.setting do xml.settingName("duplicateWindow") xml.settingValue(value) end end
success_from(response)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 468 def success_from(response) ( response[:response_code] == APPROVED && TRANSACTION_ALREADY_ACTIONED.exclude?(response[:response_reason_code]) ) end
using_live_gateway_in_test_mode?(response)
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 501 def using_live_gateway_in_test_mode?(response) !test? && response[:test_request] == "1" end
valid_track_data()
click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 290 def valid_track_data @valid_track_data ||= false end