class ActiveMerchant::Billing::FirstdataE4Gateway

Constants

BRANDS
E4_BRANDS
POST_HEADERS
SENSITIVE_FIELDS
STANDARD_ERROR_CODE_MAPPING
SUCCESS
TRANSACTIONS

Public Class Methods

new(options = {}) click to toggle source

Create a new FirstdataE4Gateway

The gateway requires that a valid login and password be passed in the options hash.

Options

  • :login – The EXACT ID. Also known as the Gateway ID.

    (Found in your administration terminal settings)
  • :password – The terminal password (not your account password)

Calls superclass method ActiveMerchant::Billing::Gateway::new
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 74
def initialize(options = {})
  requires!(options, :login, :password)
  @options = options

  super
end

Public Instance Methods

authorize(money, credit_card_or_store_authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 81
def authorize(money, credit_card_or_store_authorization, options = {})
  commit(:authorization, build_sale_or_authorization_request(money, credit_card_or_store_authorization, options))
end
capture(money, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 89
def capture(money, authorization, options = {})
  commit(:capture, build_capture_or_credit_request(money, authorization, options))
end
purchase(money, credit_card_or_store_authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 85
def purchase(money, credit_card_or_store_authorization, options = {})
  commit(:sale, build_sale_or_authorization_request(money, credit_card_or_store_authorization, options))
end
refund(money, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 97
def refund(money, authorization, options = {})
  commit(:credit, build_capture_or_credit_request(money, authorization, options))
end
scrub(transcript) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 136
def scrub(transcript)
  transcript.
    gsub(%r((<Card_Number>).+(</Card_Number>)), '\1[FILTERED]\2').
    gsub(%r((<VerificationStr2>).+(</VerificationStr2>)), '\1[FILTERED]\2')
end
store(credit_card, options = {}) click to toggle source

Tokenize a credit card with TransArmor

The TransArmor token and other card data necessary for subsequent transactions is stored in the response's authorization attribute. The authorization string may be passed to authorize and purchase instead of a ActiveMerchant::Billing::CreditCard instance.

TransArmor support must be explicitly activated on your gateway account by FirstData. If your authorization string is empty, contact FirstData support for account setup assistance.

Example

# Generate token
result = gateway.store(credit_card)
if result.success?
  my_record.update_attributes(:authorization => result.authorization)
end

# Use token
result = gateway.purchase(1000, my_record.authorization)

firstdata.zendesk.com/entries/21303361-transarmor-tokenization

# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 128
def store(credit_card, options = {})
  commit(:store, build_store_request(credit_card, options), credit_card)
end
supports_scrubbing?() click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 132
def supports_scrubbing?
  true
end
verify(credit_card, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 101
def verify(credit_card, options = {})
  commit(:verify, build_sale_or_authorization_request(0, credit_card, options))
end
void(authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 93
def void(authorization, options = {})
  commit(:void, build_capture_or_credit_request(money_from_authorization(authorization), authorization, options))
end

Private Instance Methods

add_address(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 289
def add_address(xml, options)
  if address = (options[:billing_address] || options[:address])
    xml.tag! "ZipCode", address[:zip]
  end
end
add_amount(xml, money) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 211
def add_amount(xml, money)
  xml.tag! "DollarAmount", amount(money)
end
add_card_authentication_data(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 262
def add_card_authentication_data(xml, options)
  xml.tag! "CAVV", options[:cavv]
  xml.tag! "XID", options[:xid]
  xml.tag! "Ecommerce_Flag", options[:eci]
end
add_credentials(xml) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 195
def add_credentials(xml)
  xml.tag! "ExactID", @options[:login]
  xml.tag! "Password", @options[:password]
end
add_credit_card(xml, credit_card, options) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 215
def add_credit_card(xml, credit_card, options)

  if credit_card.respond_to?(:track_data) && credit_card.track_data.present?
    xml.tag! "Track1", credit_card.track_data
  else
    xml.tag! "Card_Number", credit_card.number
    xml.tag! "Expiry_Date", expdate(credit_card)
    xml.tag! "CardHoldersName", credit_card.name
    xml.tag! "CardType", card_type(credit_card.brand)

    add_credit_card_verification_strings(xml, credit_card, options)
  end
end
add_credit_card_token(xml, store_authorization) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 268
def add_credit_card_token(xml, store_authorization)
  params = store_authorization.split(";")
  credit_card = CreditCard.new(
    :brand      => params[1],
    :first_name => params[2],
    :last_name  => params[3],
    :month      => params[4],
    :year       => params[5])

  xml.tag! "TransarmorToken", params[0]
  xml.tag! "Expiry_Date", expdate(credit_card)
  xml.tag! "CardHoldersName", credit_card.name
  xml.tag! "CardType", card_type(credit_card.brand)
end
add_credit_card_verification_strings(xml, credit_card, options) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 229
def add_credit_card_verification_strings(xml, credit_card, options)
  address = options[:billing_address] || options[:address]
  if address
    address_values = []
    [:address1, :zip, :city, :state, :country].each { |part| address_values << address[part].to_s }
    xml.tag! "VerificationStr1", address_values.join("|")
  end

  if credit_card.is_a?(NetworkTokenizationCreditCard)
    add_network_tokenization_credit_card(xml, credit_card)
  elsif credit_card.verification_value?
    xml.tag! "CVD_Presence_Ind", "1"
    xml.tag! "VerificationStr2", credit_card.verification_value
  end
end
add_customer_data(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 283
def add_customer_data(xml, options)
  xml.tag! "Customer_Ref", options[:customer] if options[:customer]
  xml.tag! "Client_IP", options[:ip] if options[:ip]
  xml.tag! "Client_Email", options[:email] if options[:email]
end
add_identification(xml, identification) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 204
def add_identification(xml, identification)
  authorization_num, transaction_tag, _ = identification.split(";")

  xml.tag! "Authorization_Num", authorization_num
  xml.tag! "Transaction_Tag", transaction_tag
end
add_invoice(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 295
def add_invoice(xml, options)
  xml.tag! "Reference_No", options[:order_id]
  xml.tag! "Reference_3",  options[:description] if options[:description]
end
add_network_tokenization_credit_card(xml, credit_card) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 245
def add_network_tokenization_credit_card(xml, credit_card)
  xml.tag!("Ecommerce_Flag", credit_card.eci)

  case card_brand(credit_card).to_sym
  when :visa
    xml.tag!("XID", credit_card.transaction_id) if credit_card.transaction_id
    xml.tag!("CAVV", credit_card.payment_cryptogram)
  when :mastercard
    xml.tag!("XID", credit_card.transaction_id) if credit_card.transaction_id
    xml.tag!("CAVV", credit_card.payment_cryptogram)
  when :american_express
    cryptogram = Base64.decode64(credit_card.payment_cryptogram)
    xml.tag!("XID", Base64.encode64(cryptogram[20...40]))
    xml.tag!("CAVV", Base64.encode64(cryptogram[0...20]))
  end
end
add_transaction_type(xml, action) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 200
def add_transaction_type(xml, action)
  xml.tag! "Transaction_Type", TRANSACTIONS[action]
end
authorization_from(response) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 337
def authorization_from(response)
  if response[:authorization_num] && response[:transaction_tag]
    [
      response[:authorization_num],
      response[:transaction_tag],
      (response[:dollar_amount].to_f * 100).to_i
    ].join(";")
  else
    ""
  end
end
build_capture_or_credit_request(money, identification, options) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 175
def build_capture_or_credit_request(money, identification, options)
  xml = Builder::XmlMarkup.new

  add_identification(xml, identification)
  add_amount(xml, money)
  add_customer_data(xml, options)
  add_card_authentication_data(xml, options)

  xml.target!
end
build_request(action, body) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 144
def build_request(action, body)
  xml = Builder::XmlMarkup.new

  xml.instruct!
  xml.tag! "Transaction" do
    add_credentials(xml)
    add_transaction_type(xml, action)
    xml << body
  end

  xml.target!
end
build_sale_or_authorization_request(money, credit_card_or_store_authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 157
def build_sale_or_authorization_request(money, credit_card_or_store_authorization, options)
  xml = Builder::XmlMarkup.new

  add_amount(xml, money)

  if credit_card_or_store_authorization.is_a? String
    add_credit_card_token(xml, credit_card_or_store_authorization)
  else
    add_credit_card(xml, credit_card_or_store_authorization, options)
  end

  add_customer_data(xml, options)
  add_invoice(xml, options)
  add_card_authentication_data(xml, options)

  xml.target!
end
build_store_request(credit_card, options) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 186
def build_store_request(credit_card, options)
  xml = Builder::XmlMarkup.new

  add_credit_card(xml, credit_card, options)
  add_customer_data(xml, options)

  xml.target!
end
card_type(credit_card_brand) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 304
def card_type(credit_card_brand)
  E4_BRANDS[credit_card_brand.to_sym] if credit_card_brand
end
commit(action, request, credit_card = nil) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 308
def commit(action, request, credit_card = nil)
  url = (test? ? self.test_url : self.live_url)
  begin
    response = parse(ssl_post(url, build_request(action, request), POST_HEADERS))
  rescue ResponseError => e
    response = parse_error(e.response)
  end

  Response.new(successful?(response), message_from(response), response,
    :test => test?,
    :authorization => successful?(response) ? response_authorization(action, response, credit_card) : '',
    :avs_result => {:code => response[:avs]},
    :cvv_result => response[:cvv2],
    :error_code => standard_error_code(response)
  )
end
expdate(credit_card) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 300
def expdate(credit_card)
  "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
end
message_from(response) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 369
def message_from(response)
  if(response[:faultcode] && response[:faultstring])
    response[:faultstring]
  elsif(response[:error_number] && response[:error_number] != "0")
    response[:error_description]
  else
    result = (response[:exact_message] || "")
    result << " - #{response[:bank_message]}" if response[:bank_message].present?
    result
  end
end
money_from_authorization(auth) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 364
def money_from_authorization(auth)
  _, _, amount = auth.split(/;/, 3)
  amount.to_i # return the # of cents, no need to divide
end
parse(xml) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 394
def parse(xml)
  response = {}
  xml = REXML::Document.new(xml)

  if root = REXML::XPath.first(xml, "//TransactionResult")
    parse_elements(response, root)
  end

  response.delete_if{ |k,v| SENSITIVE_FIELDS.include?(k) }
end
parse_elements(response, root) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 405
def parse_elements(response, root)
  root.elements.to_a.each do |node|
    response[node.name.gsub(/EXact/, "Exact").underscore.to_sym] = (node.text || "").strip
  end
end
parse_error(error) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 381
def parse_error(error)
  {
    :transaction_approved => "false",
    :error_number => error.code,
    :error_description => error.body,
    :ecommerce_error_code => error.body.gsub(/[^\d]/, '')
  }
end
response_authorization(action, response, credit_card) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 329
def response_authorization(action, response, credit_card)
  if action == :store
    store_authorization_from(response, credit_card)
  else
    authorization_from(response)
  end
end
standard_error_code(response) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 390
def standard_error_code(response)
  STANDARD_ERROR_CODE_MAPPING[response[:bank_resp_code] || response[:ecommerce_error_code]]
end
store_authorization_from(response, credit_card) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 349
def store_authorization_from(response, credit_card)
  if response[:transarmor_token].present?
    [
      response[:transarmor_token],
      credit_card.brand,
      credit_card.first_name,
      credit_card.last_name,
      credit_card.month,
      credit_card.year
      ].map { |value| value.to_s.gsub(/;/, "") }.join(";")
  else
    raise StandardError, "TransArmor support is not enabled on your #{display_name} account"
  end
end
successful?(response) click to toggle source
# File lib/active_merchant/billing/gateways/firstdata_e4.rb, line 325
def successful?(response)
  response[:transaction_approved] == SUCCESS
end