class ActiveMerchant::Billing::AuthorizeNetGateway

Constants

AVS_ERRORS
AVS_REASON_CODES
CARD_CODE_ERRORS
DEVICE_TYPE
FRAUD_REVIEW
INELIGIBLE_FOR_ISSUING_CREDIT_ERROR
MARKET_TYPE
PAYMENT_METHOD_NOT_SUPPORTED_ERROR
STANDARD_AVS_CODE_MAPPING

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_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 95
def initialize(options = {})
  requires!(options, :login, :password)
  super
end

Public Instance Methods

amount_for_verify(options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 188
def amount_for_verify(options)
  return 100 unless options[:verify_amount].present?

  amount = options[:verify_amount]
  raise ArgumentError.new 'verify_amount value must be an integer' unless amount.is_a?(Integer) && !amount.negative? || amount.is_a?(String) && amount.match?(/^\d+$/) && !amount.to_i.negative?
  raise ArgumentError.new 'Billing address including zip code is required for a 0 amount verify' if amount.to_i.zero? && !validate_billing_address_values?(options)

  amount.to_i
end
authorize(amount, payment, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 112
def authorize(amount, payment, options = {})
  if payment.is_a?(String)
    commit(:cim_authorize, options) do |xml|
      add_cim_auth_purchase(xml, 'profileTransAuthOnly', amount, payment, options)
    end
  else
    commit(:authorize) do |xml|
      add_auth_purchase(xml, 'authOnlyTransaction', amount, payment, options)
    end
  end
end
capture(amount, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 124
def capture(amount, authorization, options = {})
  if auth_was_for_cim?(authorization)
    cim_capture(amount, authorization, options)
  else
    normal_capture(amount, authorization, options)
  end
end
credit(amount, payment, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 158
def credit(amount, payment, options = {})
  raise ArgumentError, 'Reference credits are not supported. Please supply the original credit card or use the #refund method.' if payment.is_a?(String)

  commit(:credit) do |xml|
    add_order_id(xml, options)
    xml.transactionRequest do
      xml.transactionType('refundTransaction')
      xml.amount(amount(amount))

      add_payment_method(xml, payment, options, :credit)
      xml.refTransId(transaction_id_from(options[:transaction_id])) if options[:transaction_id]
      add_invoice(xml, 'refundTransaction', 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 100
def purchase(amount, payment, options = {})
  if payment.is_a?(String)
    commit(:cim_purchase, options) do |xml|
      add_cim_auth_purchase(xml, 'profileTransAuthCapture', amount, payment, options)
    end
  else
    commit(:purchase) do |xml|
      add_auth_purchase(xml, 'authCaptureTransaction', amount, payment, options)
    end
  end
end
refund(amount, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 132
def refund(amount, authorization, options = {})
  response =
    if auth_was_for_cim?(authorization)
      cim_refund(amount, authorization, options)
    else
      normal_refund(amount, authorization, options)
    end

  return response if response.success?
  return response unless options[:force_full_refund_if_unsettled]

  if response.params['response_reason_code'] == INELIGIBLE_FOR_ISSUING_CREDIT_ERROR
    void(authorization, options)
  else
    response
  end
end
scrub(transcript) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 225
def scrub(transcript)
  transcript.
    gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
    gsub(%r((<transactionKey>).+(</transactionKey>)), '\1[FILTERED]\2').
    gsub(%r((<cardNumber>).+(</cardNumber>)), '\1[FILTERED]\2').
    gsub(%r((<cardCode>).+(</cardCode>)), '\1[FILTERED]\2').
    gsub(%r((<track1>).+(</track1>)), '\1[FILTERED]\2').
    gsub(%r((<track2>).+(</track2>)), '\1[FILTERED]\2').
    gsub(/(<routingNumber>).+(<\/routingNumber>)/, '\1[FILTERED]\2').
    gsub(/(<accountNumber>).+(<\/accountNumber>)/, '\1[FILTERED]\2').
    gsub(%r((<cryptogram>).+(</cryptogram>)), '\1[FILTERED]\2')
end
store(credit_card, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 202
def store(credit_card, options = {})
  if options[:customer_profile_id]
    create_customer_payment_profile(credit_card, options)
  else
    create_customer_profile(credit_card, options)
  end
end
supports_network_tokenization?() click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 238
def supports_network_tokenization?
  card = Billing::NetworkTokenizationCreditCard.new({
    number: '4111111111111111',
    month: 12,
    year: 20,
    first_name: 'John',
    last_name: 'Smith',
    brand: 'visa',
    payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk='
  })

  request = post_data(:authorize) do |xml|
    add_auth_purchase(xml, 'authOnlyTransaction', 1, card, {})
  end
  raw_response = ssl_post(url, request, headers)
  response = parse(:authorize, raw_response)
  response[:response_reason_code].to_s != PAYMENT_METHOD_NOT_SUPPORTED_ERROR
end
supports_scrubbing?() click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 221
def supports_scrubbing?
  true
end
unstore(authorization) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 210
def unstore(authorization)
  customer_profile_id, = split_authorization(authorization)

  delete_customer_profile(customer_profile_id)
end
validate_billing_address_values?(options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 198
def validate_billing_address_values?(options)
  options.dig(:billing_address, :zip).present? && options.dig(:billing_address, :address1).present?
end
verify(payment_method, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 177
def verify(payment_method, options = {})
  amount = amount_for_verify(options)

  MultiResponse.run(:use_first_response) do |r|
    r.process { authorize(amount, payment_method, options) }
    r.process(:ignore_result) { void(r.authorization, options) } unless amount == 0
  end
rescue ArgumentError => e
  Response.new(false, e.message)
end
verify_credentials() click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 216
def verify_credentials
  response = commit(:verify_credentials) {}
  response.success?
end
void(authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 150
def void(authorization, options = {})
  if auth_was_for_cim?(authorization)
    cim_void(authorization, options)
  else
    normal_void(authorization, options)
  end
end

Private Instance Methods

add_auth_purchase(xml, transaction_type, amount, payment, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 259
def add_auth_purchase(xml, transaction_type, amount, payment, options)
  add_order_id(xml, options)
  xml.transactionRequest do
    xml.transactionType(transaction_type)
    xml.amount(amount(amount))
    add_payment_method(xml, payment, options)
    add_invoice(xml, transaction_type, options)
    add_tax_fields(xml, options)
    add_duty_fields(xml, options)
    add_shipping_fields(xml, options)
    add_tax_exempt_status(xml, options)
    add_po_number(xml, options)
    add_customer_data(xml, payment, options)
    add_market_type_device_type(xml, payment, options)
    add_settings(xml, payment, options)
    add_user_fields(xml, amount, options)
    add_surcharge_fields(xml, options)
    add_ship_from_address(xml, options)
    add_processing_options(xml, options)
    add_subsequent_auth_information(xml, options)
  end
end
add_authentication(xml) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 895
def add_authentication(xml)
  xml.merchantAuthentication do
    xml.name(@options[:login])
    xml.transactionKey(@options[:password])
  end
end
add_billing_address(xml, payment_source, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 610
def add_billing_address(xml, payment_source, options)
  address = options[:billing_address] || options[:address] || {}

  xml.billTo do
    first_name, last_name = names_from(payment_source, address, options)
    state = state_from(address, options)
    full_address = "#{address[:address1]} #{address[:address2]}".strip
    phone = address[:phone] || address[:phone_number] || ''

    xml.firstName(truncate(first_name, 50)) unless empty?(first_name)
    xml.lastName(truncate(last_name, 50)) unless empty?(last_name)
    xml.company(truncate(address[:company], 50)) unless empty?(address[:company])
    xml.address(truncate(full_address, 60))
    xml.city(truncate(address[:city], 40))
    xml.state(truncate(state, 40))
    xml.zip(truncate((address[:zip] || options[:zip]), 20))
    xml.country(truncate(address[:country], 60))
    xml.phoneNumber(truncate(phone, 25)) unless empty?(phone)
    xml.faxNumber(truncate(address[:fax], 25)) unless empty?(address[:fax])
  end
end
add_check(xml, check) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 573
def add_check(xml, check)
  xml.payment do
    xml.bankAccount do
      xml.accountType(check.account_type)
      xml.routingNumber(check.routing_number)
      xml.accountNumber(check.account_number)
      xml.nameOnAccount(truncate(check.name, 22))
      xml.bankName(check.bank_name)
      xml.checkNumber(check.number)
    end
  end
end
add_cim_auth_purchase(xml, transaction_type, amount, payment, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 282
def add_cim_auth_purchase(xml, transaction_type, amount, payment, options)
  add_order_id(xml, options)
  xml.transaction do
    xml.send(transaction_type) do
      xml.amount(amount(amount))
      add_tax_fields(xml, options)
      add_shipping_fields(xml, options)
      add_duty_fields(xml, options)
      add_payment_method(xml, payment, options)
      add_invoice(xml, transaction_type, options)
      add_surcharge_fields(xml, options)
      add_tax_exempt_status(xml, options)
    end
  end
  add_extra_options_for_cim(xml, options)
end
add_credit_card(xml, credit_card, action) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 501
def add_credit_card(xml, credit_card, action)
  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))
        xml.cardCode(credit_card.verification_value) if credit_card.valid_card_verification_value?(credit_card.verification_value, credit_card.brand)
      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 586
def add_customer_data(xml, payment_source, options)
  xml.customer do
    xml.id(options[:customer]) unless empty?(options[:customer]) || options[:customer] !~ /^\w+$/
    xml.email(options[:email]) unless empty?(options[:email])
  end

  add_billing_address(xml, payment_source, options)
  add_shipping_address(xml, options)

  xml.customerIP(options[:ip]) unless empty?(options[:ip])

  if !empty?(options.fetch(:three_d_secure, {})) || options[:authentication_indicator] || options[:cardholder_authentication_value]
    xml.cardholderAuthentication do
      three_d_secure = options.fetch(:three_d_secure, {})
      xml.authenticationIndicator(
        options[:authentication_indicator] || three_d_secure[:eci]
      )
      xml.cardholderAuthenticationValue(
        options[:cardholder_authentication_value] || three_d_secure[:cavv]
      )
    end
  end
end
add_duty_fields(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 703
def add_duty_fields(xml, options)
  duty = options[:duty]
  if duty.is_a?(Hash)
    xml.duty do
      xml.amount(amount(duty[:amount].to_i))
      xml.name(duty[:name])
      xml.description(duty[:description])
    end
  end
end
add_extra_options_for_cim(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 743
def add_extra_options_for_cim(xml, options)
  xml.extraOptions("x_delim_char=#{options[:delimiter]}") if options[:delimiter]
end
add_invoice(xml, transaction_type, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 670
def add_invoice(xml, transaction_type, options)
  xml.order do
    xml.invoiceNumber(truncate(options[:order_id], 20))
    xml.description(truncate(options[:description], 255))
    xml.purchaseOrderNumber(options[:po_number]) if options[:po_number] && transaction_type.start_with?('profileTrans')
    xml.summaryCommodityCode(truncate(options[:summary_commodity_code], 4)) if options[:summary_commodity_code] && !transaction_type.start_with?('profileTrans')
  end

  # Authorize.net API requires lineItems to be placed directly after order tag
  if 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
end
add_market_type_device_type(xml, payment, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 547
def add_market_type_device_type(xml, payment, options)
  return unless payment.is_a?(CreditCard)
  return if payment.is_a?(NetworkTokenizationCreditCard)

  if valid_track_data
    xml.retail do
      xml.marketType(options[:market_type] || MARKET_TYPE[:retail])
      xml.deviceType(options[:device_type] || DEVICE_TYPE[:wireless_pos])
    end
  elsif payment.manual_entry
    xml.retail do
      xml.marketType(options[:market_type] || MARKET_TYPE[:moto])
    end
  else
    if options[:market_type]
      xml.retail do
        xml.marketType(options[:market_type])
      end
    end
  end
end
add_network_token(xml, payment_method) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 536
def add_network_token(xml, payment_method)
  xml.payment do
    xml.creditCard do
      xml.cardNumber(truncate(payment_method.number, 16))
      xml.expirationDate(format(payment_method.month, :two_digits) + '/' + format(payment_method.year, :four_digits))
      xml.isPaymentToken(true)
      xml.cryptogram(payment_method.payment_cryptogram)
    end
  end
end
add_order_id(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 666
def add_order_id(xml, options)
  xml.refId(truncate(options[:order_id], 20))
end
add_payment_method(xml, payment_method, options, action = nil) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 411
def add_payment_method(xml, payment_method, options, action = nil)
  return unless payment_method

  case payment_method
  when String
    add_token_payment_method(xml, payment_method, options)
  when Check
    add_check(xml, payment_method)
  else
    if network_token?(payment_method, options, action)
      add_network_token(xml, payment_method)
    else
      add_credit_card(xml, payment_method, action)
    end
  end
end
add_po_number(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 739
def add_po_number(xml, options)
  xml.poNumber(options[:po_number]) if options[:po_number]
end
add_processing_options(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 747
def add_processing_options(xml, options)
  return unless options[:stored_credential]

  xml.processingOptions do
    if options[:stored_credential][:initial_transaction] && options[:stored_credential][:reason_type] == 'recurring'
      xml.isFirstRecurringPayment 'true'
    elsif options[:stored_credential][:initial_transaction]
      xml.isFirstSubsequentAuth 'true'
    elsif options[:stored_credential][:initiator] == 'cardholder'
      xml.isStoredCredentials 'true'
    else
      xml.isSubsequentAuth 'true'
    end
  end
end
add_settings(xml, source, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 436
def add_settings(xml, source, options)
  xml.transactionSettings do
    if options[:recurring] || subsequent_recurring_transaction?(options)
      xml.setting do
        xml.settingName('recurringBilling')
        xml.settingValue('true')
      end
    end
    if options[:disable_partial_auth]
      xml.setting do
        xml.settingName('allowPartialAuth')
        xml.settingValue('false')
      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
    if options.key?(:email_customer)
      xml.setting do
        xml.settingName('emailCustomer')
        xml.settingValue(options[:email_customer] ? 'true' : 'false')
      end
    end
    if options[:header_email_receipt]
      xml.setting do
        xml.settingName('headerEmailReceipt')
        xml.settingValue(options[:header_email_receipt])
      end
    end
    if options[:test_request]
      xml.setting do
        xml.settingName('testRequest')
        xml.settingValue('1')
      end
    end
  end
end
add_ship_from_address(xml, options, root_node = 'shipFrom') click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 656
def add_ship_from_address(xml, options, root_node = 'shipFrom')
  address = options[:ship_from_address]
  return unless address

  xml.send(root_node) do
    xml.zip(truncate(address[:zip], 20)) unless empty?(address[:zip])
    xml.country(truncate(address[:country], 60)) unless empty?(address[:country])
  end
end
add_shipping_address(xml, options, root_node = 'shipTo') click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 632
def add_shipping_address(xml, options, root_node = 'shipTo')
  address = options[:shipping_address] || options[:address]
  return unless address

  xml.send(root_node) do
    first_name, last_name =
      if address[:name]
        split_names(address[:name])
      else
        [address[:first_name], address[:last_name]]
      end
    full_address = "#{address[:address1]} #{address[:address2]}".strip

    xml.firstName(truncate(first_name, 50)) unless empty?(first_name)
    xml.lastName(truncate(last_name, 50)) unless empty?(last_name)
    xml.company(truncate(address[:company], 50)) unless empty?(address[:company])
    xml.address(truncate(full_address, 60))
    xml.city(truncate(address[:city], 40))
    xml.state(truncate(address[:state], 40))
    xml.zip(truncate(address[:zip], 20))
    xml.country(truncate(address[:country], 60))
  end
end
add_shipping_fields(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 724
def add_shipping_fields(xml, options)
  shipping = options[:shipping]
  if shipping.is_a?(Hash)
    xml.shipping do
      xml.amount(amount(shipping[:amount].to_i))
      xml.name(shipping[:name])
      xml.description(shipping[:description])
    end
  end
end
add_subsequent_auth_information(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 763
def add_subsequent_auth_information(xml, options)
  return unless options.dig(:stored_credential, :initiator) == 'merchant'

  xml.subsequentAuthInformation do
    xml.reason options[:stored_credential_reason_type_override] if options[:stored_credential_reason_type_override]
    xml.originalNetworkTransId options[:stored_credential][:network_transaction_id] if options[:stored_credential][:network_transaction_id]
  end
end
add_surcharge_fields(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 714
def add_surcharge_fields(xml, options)
  surcharge = options[:surcharge] if options[:surcharge]
  if surcharge.is_a?(Hash)
    xml.surcharge do
      xml.amount(amount(surcharge[:amount].to_i)) if surcharge[:amount]
      xml.description(surcharge[:description]) if surcharge[:description]
    end
  end
end
add_swipe_data(xml, credit_card) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 515
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_tax_exempt_status(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 735
def add_tax_exempt_status(xml, options)
  xml.taxExempt(options[:tax_exempt]) if options[:tax_exempt]
end
add_tax_fields(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 692
def add_tax_fields(xml, options)
  tax = options[:tax]
  if tax.is_a?(Hash)
    xml.tax do
      xml.amount(amount(tax[:amount].to_i))
      xml.name(tax[:name])
      xml.description(tax[:description])
    end
  end
end
add_token_payment_method(xml, token, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 528
def add_token_payment_method(xml, token, options)
  customer_profile_id, customer_payment_profile_id, = split_authorization(token)
  customer_profile_id = options[:customer_profile_id] if options[:customer_profile_id]
  customer_payment_profile_id = options[:customer_payment_profile_id] if options[:customer_payment_profile_id]
  xml.customerProfileId(customer_profile_id)
  xml.customerPaymentProfileId(customer_payment_profile_id)
end
add_user_fields(xml, amount, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 484
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?
      xml.userField do
        xml.name('x_solution_id')
        xml.value(application_id)
      end
    end
  end
end
auth_was_for_cim?(authorization) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 1073
def auth_was_for_cim?(authorization)
  _, _, action = split_authorization(authorization)
  action && cim_action?(action)
end
authorization_from(action, response) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 1040
def authorization_from(action, response)
  if cim?(action)
    [response[:customer_profile_id], response[:customer_payment_profile_id], action].join('#')
  else
    [response[:transaction_id], response[:account_number], action].join('#')
  end
end
camel_case_lower(key) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 432
def camel_case_lower(key)
  String(key).split('_').inject([]) { |buffer, e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
end
cim?(action) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 1052
def cim?(action)
  (action == :cim_store) || (action == :cim_store_update) || (action == :cim_store_delete_customer)
end
cim_action?(action) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 866
def cim_action?(action)
  action.to_s.start_with?('cim')
end
cim_capture(amount, authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 299
def cim_capture(amount, authorization, options)
  commit(:cim_capture, options) do |xml|
    add_order_id(xml, options)
    xml.transaction do
      xml.profileTransPriorAuthCapture do
        xml.amount(amount(amount))
        add_tax_fields(xml, options)
        add_shipping_fields(xml, options)
        add_duty_fields(xml, options)
        xml.transId(transaction_id_from(authorization))
      end
    end
    add_extra_options_for_cim(xml, options)
  end
end
cim_refund(amount, authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 333
def cim_refund(amount, authorization, options)
  transaction_id, card_number, = split_authorization(authorization)

  commit(:cim_refund, options) do |xml|
    add_order_id(xml, options)
    xml.transaction do
      xml.profileTransRefund do
        xml.amount(amount(amount))
        add_tax_fields(xml, options)
        add_shipping_fields(xml, options)
        add_duty_fields(xml, options)
        xml.creditCardNumberMasked(card_number)
        add_invoice(xml, 'profileTransRefund', options)
        xml.transId(transaction_id)
      end
    end
    add_extra_options_for_cim(xml, options)
  end
end
cim_void(authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 389
def cim_void(authorization, options)
  commit(:cim_void, options) do |xml|
    add_order_id(xml, options)
    xml.transaction do
      xml.profileTransVoid do
        xml.transId(transaction_id_from(authorization))
      end
    end
    add_extra_options_for_cim(xml, options)
  end
end
commit(action, options = {}, &payload) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 842
def commit(action, options = {}, &payload)
  raw_response = ssl_post(url, post_data(action, &payload), headers)
  response = parse(action, raw_response, options)

  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(
      success_from(action, response),
      message_from(action, response, avs_result, cvv_result),
      response,
      authorization: authorization_from(action, 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
create_customer_payment_profile(credit_card, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 772
def create_customer_payment_profile(credit_card, options)
  commit(:cim_store_update, options) do |xml|
    xml.customerProfileId options[:customer_profile_id]
    xml.paymentProfile do
      add_billing_address(xml, credit_card, options)
      add_credit_card(xml, credit_card, :cim_store_update)
    end
  end
end
create_customer_profile(credit_card, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 782
def create_customer_profile(credit_card, options)
  commit(:cim_store, options) do |xml|
    xml.profile do
      xml.merchantCustomerId(truncate(options[:merchant_customer_id], 20) || SecureRandom.hex(10))
      xml.description(truncate(options[:description], 255)) unless empty?(options[:description])
      xml.email(options[:email]) unless empty?(options[:email])

      xml.paymentProfiles do
        xml.customerType('individual')
        add_billing_address(xml, credit_card, options)
        add_shipping_address(xml, options, 'shipToList')
        add_credit_card(xml, credit_card, :cim_store)
      end
    end
  end
end
delete_customer_profile(customer_profile_id) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 799
def delete_customer_profile(customer_profile_id)
  commit(:cim_store_delete_customer, options) do |xml|
    xml.customerProfileId(customer_profile_id)
  end
end
fraud_review?(response) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 1061
def fraud_review?(response)
  (response[:response_code] == FRAUD_REVIEW)
end
headers() click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 826
def headers
  { 'Content-Type' => 'text/xml' }
end
map_error_code(response_code, response_reason_code) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 1069
def map_error_code(response_code, response_reason_code)
  STANDARD_ERROR_CODE_MAPPING["#{response_code}#{response_reason_code}"]
end
message_from(action, response, avs_result, cvv_result) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 1028
def message_from(action, 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] || response[:message_text]
end
names_from(payment_source, address, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 805
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
    [options[:first_name], options[:last_name]]
  end
end
network_token?(payment_method, options, action) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 428
def network_token?(payment_method, options, action)
  payment_method.instance_of?(NetworkTokenizationCreditCard) && action != :credit
end
normal_capture(amount, authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 315
def normal_capture(amount, authorization, options)
  commit(:capture) do |xml|
    add_order_id(xml, options)
    xml.transactionRequest do
      xml.transactionType('priorAuthCaptureTransaction')
      xml.amount(amount(amount))
      add_tax_fields(xml, options)
      add_duty_fields(xml, options)
      add_shipping_fields(xml, options)
      add_tax_exempt_status(xml, options)
      add_po_number(xml, options)
      xml.refTransId(transaction_id_from(authorization))
      add_invoice(xml, 'capture', options)
      add_user_fields(xml, amount, options)
    end
  end
end
normal_refund(amount, authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 353
def normal_refund(amount, authorization, options)
  transaction_id, card_number, = split_authorization(authorization)

  commit(:refund) do |xml|
    xml.transactionRequest do
      xml.transactionType('refundTransaction')
      xml.amount(amount.nil? ? 0 : amount(amount))
      xml.payment do
        if options[:routing_number]
          xml.bankAccount do
            xml.accountType(options[:account_type])
            xml.routingNumber(options[:routing_number])
            xml.accountNumber(options[:account_number])
            xml.nameOnAccount(truncate("#{options[:first_name]} #{options[:last_name]}", 22))
          end
        else
          xml.creditCard do
            xml.cardNumber(card_number || options[:card_number])
            xml.expirationDate('XXXX')
          end
        end
      end
      xml.refTransId(transaction_id)

      add_invoice(xml, 'refundTransaction', options)
      add_tax_fields(xml, options)
      add_duty_fields(xml, options)
      add_shipping_fields(xml, options)
      add_tax_exempt_status(xml, options)
      add_po_number(xml, options)
      add_customer_data(xml, nil, options)
      add_user_fields(xml, amount, options)
    end
  end
end
normal_void(authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 401
def normal_void(authorization, options)
  commit(:void) do |xml|
    add_order_id(xml, options)
    xml.transactionRequest do
      xml.transactionType('voidTransaction')
      xml.refTransId(transaction_id_from(authorization))
    end
  end
end
parse(action, raw_response, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 834
def parse(action, raw_response, options = {})
  if cim_action?(action) || action == :verify_credentials
    parse_cim(raw_response, options)
  else
    parse_normal(action, raw_response)
  end
end
parse_cim(body, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 974
def parse_cim(body, options)
  response = {}

  doc = Nokogiri::XML(body).remove_namespaces!

  if element = doc.at_xpath('//messages/message')
    response[:message_code] = element.at_xpath('code').content[/0*(\d+)$/, 1]
    response[:message_text] = element.at_xpath('text').content.chomp('.')
  end

  response[:result_code] =
    if element = doc.at_xpath('//messages/resultCode')
      empty?(element.content) ? nil : element.content
    end

  response[:test_request] =
    if element = doc.at_xpath('//testRequest')
      empty?(element.content) ? nil : element.content
    end

  response[:customer_profile_id] =
    if element = doc.at_xpath('//customerProfileId')
      empty?(element.content) ? nil : element.content
    end

  response[:customer_payment_profile_id] =
    if element = doc.at_xpath('//customerPaymentProfileIdList/numericString')
      empty?(element.content) ? nil : element.content
    end

  response[:customer_payment_profile_id] =
    if element = doc.at_xpath('//customerPaymentProfileIdList/numericString') ||
                 doc.at_xpath('//customerPaymentProfileId')
      empty?(element.content) ? nil : element.content
    end

  response[:direct_response] =
    if element = doc.at_xpath('//directResponse')
      empty?(element.content) ? nil : element.content
    end

  response.merge!(parse_direct_response_elements(response, options))

  response
end
parse_direct_response_elements(response, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 1078
def parse_direct_response_elements(response, options)
  params = response[:direct_response]&.tr('"', '')
  return {} unless params

  parts = params.split(options[:delimiter] || ',')
  {
    response_code: parts[0].to_i,
    response_subcode: parts[1],
    response_reason_code: parts[2],
    response_reason_text: parts[3],
    approval_code: parts[4],
    avs_result_code: parts[5],
    transaction_id: parts[6],
    invoice_number: parts[7],
    order_description: parts[8],
    amount: parts[9],
    method: parts[10],
    transaction_type: parts[11],
    customer_id: parts[12],
    first_name: parts[13],
    last_name: parts[14],
    company: parts[15],
    address: parts[16],
    city: parts[17],
    state: parts[18],
    zip_code: parts[19],
    country: parts[20],
    phone: parts[21],
    fax: parts[22],
    email_address: parts[23],
    ship_to_first_name: parts[24],
    ship_to_last_name: parts[25],
    ship_to_company: parts[26],
    ship_to_address: parts[27],
    ship_to_city: parts[28],
    ship_to_state: parts[29],
    ship_to_zip_code: parts[30],
    ship_to_country: parts[31],
    tax: parts[32],
    duty: parts[33],
    freight: parts[34],
    tax_exempt: parts[35],
    purchase_order_number: parts[36],
    md5_hash: parts[37],
    card_code: parts[38],
    cardholder_authentication_verification_response: parts[39],
    account_number: parts[50] || '',
    card_type: parts[51] || '',
    split_tender_id: parts[52] || '',
    requested_amount: parts[53] || '',
    balance_on_card: parts[54] || ''
  }
end
parse_normal(action, body) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 902
def parse_normal(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[:full_response_code] =
    if element = doc.at_xpath('//messages/message/code')
      empty?(element.content) ? nil : element.content
    end

  response[:network_trans_id] =
    if element = doc.at_xpath('//networkTransId')
      empty?(element.content) ? nil : element.content
    end

  response
end
post_data(action) { |xml| ... } click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 870
def post_data(action)
  Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
    xml.send(root_for(action), 'xmlns' => 'AnetApi/xml/v1/schema/AnetApiSchema.xsd') do
      add_authentication(xml)
      yield(xml)
    end
  end.to_xml(indent: 0)
end
root_for(action) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 879
def root_for(action)
  if action == :cim_store
    'createCustomerProfileRequest'
  elsif action == :cim_store_update
    'createCustomerPaymentProfileRequest'
  elsif action == :cim_store_delete_customer
    'deleteCustomerProfileRequest'
  elsif action == :verify_credentials
    'authenticateTestRequest'
  elsif cim_action?(action)
    'createCustomerProfileTransactionRequest'
  else
    'createTransactionRequest'
  end
end
set_duplicate_window(xml, value) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 477
def set_duplicate_window(xml, value)
  xml.setting do
    xml.settingName('duplicateWindow')
    xml.settingValue(value)
  end
end
split_authorization(authorization) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 1048
def split_authorization(authorization)
  authorization.split('#')
end
state_from(address, options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 814
def state_from(address, options)
  if %w[US CA].include?(address[:country])
    address[:state] || 'NC'
  else
    address[:state] || 'n/a'
  end
end
subsequent_recurring_transaction?(options) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 822
def subsequent_recurring_transaction?(options)
  options.dig(:stored_credential, :reason_type) == 'recurring' && !options.dig(:stored_credential, :initial_transaction)
end
success_from(action, response) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 1020
def success_from(action, response)
  if cim?(action) || (action == :verify_credentials)
    response[:result_code] == 'Ok'
  else
    [APPROVED, FRAUD_REVIEW].include?(response[:response_code]) && TRANSACTION_ALREADY_ACTIONED.exclude?(response[:response_reason_code])
  end
end
transaction_id_from(authorization) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 1056
def transaction_id_from(authorization)
  transaction_id, = split_authorization(authorization)
  transaction_id
end
url() click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 830
def url
  test? ? test_url : live_url
end
using_live_gateway_in_test_mode?(response) click to toggle source
# File lib/active_merchant/billing/gateways/authorize_net.rb, line 1065
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 569
def valid_track_data
  @valid_track_data ||= false
end