class ActiveMerchant::Billing::RealexGateway

Realex is the leading CC gateway in Ireland see www.realexpayments.com Contributed by John Ward (john@ward.name) see thinedgeofthewedge.blogspot.com

Realex works using the following login - The unique id of the merchant password - The secret is used to digitally sign the request account - This is an optional third part of the authentication process and is used if the merchant wishes do distinguish cc traffic from the different sources by using a different account. This must be created in advance

the Realex team decided to make the orderid unique per request, so if validation fails you can not correct and resend using the same order id

Constants

BANK_ERROR
CARD_MAPPING
DECLINED
ERROR

Public Class Methods

new(options = {}) click to toggle source
Calls superclass method ActiveMerchant::Billing::Gateway::new
# File lib/active_merchant/billing/gateways/realex.rb, line 43
def initialize(options = {})
  requires!(options, :login, :password)
  options[:refund_hash] = Digest::SHA1.hexdigest(options[:rebate_secret]) if options[:rebate_secret].present?
  options[:credit_hash] = Digest::SHA1.hexdigest(options[:refund_secret]) if options[:refund_secret].present?
  super
end

Public Instance Methods

authorize(money, creditcard, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 57
def authorize(money, creditcard, options = {})
  requires!(options, :order_id)

  request = build_purchase_or_authorization_request(:authorization, money, creditcard, options)
  commit(request)
end
capture(money, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 64
def capture(money, authorization, options = {})
  request = build_capture_request(money, authorization, options)
  commit(request)
end
credit(money, creditcard, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 74
def credit(money, creditcard, options = {})
  request = build_credit_request(money, creditcard, options)
  commit(request)
end
purchase(money, credit_card, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 50
def purchase(money, credit_card, options = {})
  requires!(options, :order_id)

  request = build_purchase_or_authorization_request(:purchase, money, credit_card, options)
  commit(request)
end
refund(money, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 69
def refund(money, authorization, options = {})
  request = build_refund_request(money, authorization, options)
  commit(request)
end
scrub(transcript) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 95
def scrub(transcript)
  transcript.
    gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
    gsub(%r((<number>)\d+(</number>))i, '\1[FILTERED]\2')
end
supports_scrubbing() click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 91
def supports_scrubbing
  true
end
verify(credit_card, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 84
def verify(credit_card, options = {})
  requires!(options, :order_id)

  request = build_verify_request(credit_card, options)
  commit(request)
end
void(authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 79
def void(authorization, options = {})
  request = build_void_request(authorization, options)
  commit(request)
end

Private Instance Methods

add_address_and_customer_info(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 230
def add_address_and_customer_info(xml, options)
  billing_address = options[:billing_address] || options[:address]
  shipping_address = options[:shipping_address]

  return unless billing_address || shipping_address || options[:customer] || options[:invoice] || options[:ip]

  xml.tag! 'tssinfo' do
    xml.tag! 'custnum', options[:customer] if options[:customer]
    xml.tag! 'prodid', options[:invoice] if options[:invoice]
    xml.tag! 'custipaddress', options[:ip] if options[:ip]

    if billing_address
      xml.tag! 'address', 'type' => 'billing' do
        xml.tag! 'code', format_address_code(billing_address)
        xml.tag! 'country', billing_address[:country]
      end
    end

    if shipping_address
      xml.tag! 'address', 'type' => 'shipping' do
        xml.tag! 'code', format_address_code(shipping_address)
        xml.tag! 'country', shipping_address[:country]
      end
    end
  end
end
add_amount(xml, money, options) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 278
def add_amount(xml, money, options)
  xml.tag! 'amount', amount(money), 'currency' => options[:currency] || currency(money)
end
add_card(xml, credit_card) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 282
def add_card(xml, credit_card)
  xml.tag! 'card' do
    xml.tag! 'number', credit_card.number
    xml.tag! 'expdate', expiry_date(credit_card)
    xml.tag! 'chname', credit_card.name
    xml.tag! 'type', CARD_MAPPING[card_brand(credit_card).to_s]
    xml.tag! 'issueno', ''
    xml.tag! 'cvn' do
      xml.tag! 'number', credit_card.verification_value
      xml.tag! 'presind', (options['presind'] || (credit_card.verification_value? ? 1 : nil))
    end
  end
end
add_comments(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 271
def add_comments(xml, options)
  return unless options[:description]
  xml.tag! 'comments' do
    xml.tag! 'comment', options[:description], 'id' => 1
  end
end
add_merchant_details(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 257
def add_merchant_details(xml, options)
  xml.tag! 'merchantid', @options[:login]
  if options[:account] || @options[:account]
    xml.tag! 'account', (options[:account] || @options[:account])
  end
end
add_network_tokenization_card(xml, payment) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 296
def add_network_tokenization_card(xml, payment)
  xml.tag! 'mpi' do
    xml.tag! 'cavv', payment.payment_cryptogram
    xml.tag! 'eci', payment.eci
  end
  xml.tag! 'supplementarydata' do
    xml.tag! 'item', 'type' => 'mobile' do
      xml.tag! 'field01', payment.source.to_s.gsub('_', '-')
    end
  end
end
add_signed_digest(xml, *values) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 333
def add_signed_digest(xml, *values)
  string = Digest::SHA1.hexdigest(values.join('.'))
  xml.tag! 'sha1hash', Digest::SHA1.hexdigest([string, @options[:password]].join('.'))
end
add_three_d_secure(xml, options) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 308
def add_three_d_secure(xml, options)
  return unless three_d_secure = options[:three_d_secure]
  version = three_d_secure.fetch(:version, '')
  xml.tag! 'mpi' do
    if version =~ /^2/
      xml.tag! 'authentication_value', three_d_secure[:cavv]
      xml.tag! 'ds_trans_id', three_d_secure[:ds_transaction_id]
    else
      xml.tag! 'cavv', three_d_secure[:cavv]
      xml.tag! 'xid', three_d_secure[:xid]
    end
    xml.tag! 'eci', three_d_secure[:eci]
    xml.tag! 'message_version', version
  end
end
add_transaction_identifiers(xml, authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 264
def add_transaction_identifiers(xml, authorization, options)
  options[:order_id], pasref, authcode = authorization.split(';')
  xml.tag! 'orderid', sanitize_order_id(options[:order_id])
  xml.tag! 'pasref', pasref
  xml.tag! 'authcode', authcode
end
authorization_from(parsed) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 135
def authorization_from(parsed)
  [parsed[:orderid], parsed[:pasref], parsed[:authcode]].join(';')
end
auto_settle_flag(action) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 338
def auto_settle_flag(action)
  action == :authorization ? '0' : '1'
end
build_capture_request(money, authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 160
def build_capture_request(money, authorization, options)
  timestamp = new_timestamp
  xml = Builder::XmlMarkup.new :indent => 2
  xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'settle' do
    add_merchant_details(xml, options)
    add_amount(xml, money, options)
    add_transaction_identifiers(xml, authorization, options)
    add_comments(xml, options)
    add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), amount(money), (options[:currency] || currency(money)), nil)
  end
  xml.target!
end
build_credit_request(money, credit_card, options) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 188
def build_credit_request(money, credit_card, options)
  timestamp = new_timestamp
  xml = Builder::XmlMarkup.new :indent => 2
  xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'credit' do
    add_merchant_details(xml, options)
    xml.tag! 'orderid', sanitize_order_id(options[:order_id])
    add_amount(xml, money, options)
    add_card(xml, credit_card)
    xml.tag! 'refundhash', @options[:credit_hash] if @options[:credit_hash]
    xml.tag! 'autosettle', 'flag' => 1
    add_comments(xml, options)
    add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), amount(money), (options[:currency] || currency(money)), credit_card.number)
  end
  xml.target!
end
build_purchase_or_authorization_request(action, money, credit_card, options) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 139
def build_purchase_or_authorization_request(action, money, credit_card, options)
  timestamp = new_timestamp
  xml = Builder::XmlMarkup.new :indent => 2
  xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'auth' do
    add_merchant_details(xml, options)
    xml.tag! 'orderid', sanitize_order_id(options[:order_id])
    add_amount(xml, money, options)
    add_card(xml, credit_card)
    xml.tag! 'autosettle', 'flag' => auto_settle_flag(action)
    add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), amount(money), (options[:currency] || currency(money)), credit_card.number)
    if credit_card.is_a?(NetworkTokenizationCreditCard)
      add_network_tokenization_card(xml, credit_card)
    else
      add_three_d_secure(xml, options)
    end
    add_comments(xml, options)
    add_address_and_customer_info(xml, options)
  end
  xml.target!
end
build_refund_request(money, authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 173
def build_refund_request(money, authorization, options)
  timestamp = new_timestamp
  xml = Builder::XmlMarkup.new :indent => 2
  xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'rebate' do
    add_merchant_details(xml, options)
    add_transaction_identifiers(xml, authorization, options)
    xml.tag! 'amount', amount(money), 'currency' => options[:currency] || currency(money)
    xml.tag! 'refundhash', @options[:refund_hash] if @options[:refund_hash]
    xml.tag! 'autosettle', 'flag' => 1
    add_comments(xml, options)
    add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), amount(money), (options[:currency] || currency(money)), nil)
  end
  xml.target!
end
build_verify_request(credit_card, options) click to toggle source

Verify initiates an OTB (Open To Buy) request

# File lib/active_merchant/billing/gateways/realex.rb, line 217
def build_verify_request(credit_card, options)
  timestamp = new_timestamp
  xml = Builder::XmlMarkup.new :indent => 2
  xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'otb' do
    add_merchant_details(xml, options)
    xml.tag! 'orderid', sanitize_order_id(options[:order_id])
    add_card(xml, credit_card)
    add_comments(xml, options)
    add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), credit_card.number)
  end
  xml.target!
end
build_void_request(authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 204
def build_void_request(authorization, options)
  timestamp = new_timestamp
  xml = Builder::XmlMarkup.new :indent => 2
  xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'void' do
    add_merchant_details(xml, options)
    add_transaction_identifiers(xml, authorization, options)
    add_comments(xml, options)
    add_signed_digest(xml, timestamp, @options[:login], sanitize_order_id(options[:order_id]), nil, nil, nil)
  end
  xml.target!
end
commit(request) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 103
def commit(request)
  response = parse(ssl_post(self.live_url, request))

  Response.new(
    (response[:result] == '00'),
    message_from(response),
    response,
    :test => (response[:message] =~ %r{\[ test system \]}),
    :authorization => authorization_from(response),
    avs_result: AVSResult.new(code: response[:avspostcoderesponse]),
    cvv_result: CVVResult.new(response[:cvnresult])
  )
end
expiry_date(credit_card) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 342
def expiry_date(credit_card)
  "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
end
format_address_code(address) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 324
def format_address_code(address)
  code = [address[:zip].to_s, address[:address1].to_s + address[:address2].to_s]
  code.collect { |e| e.gsub(/\D/, '') }.reject(&:empty?).join('|')
end
message_from(response) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 346
def message_from(response)
  case response[:result]
  when '00'
    SUCCESS
  when '101'
    response[:message]
  when '102', '103'
    DECLINED
  when /^2[0-9][0-9]/
    BANK_ERROR
  when /^3[0-9][0-9]/
    REALEX_ERROR
  when /^5[0-9][0-9]/
    response[:message]
  when '600', '601', '603'
    ERROR
  when '666'
    CLIENT_DEACTIVATED
  else
    DECLINED
  end
end
new_timestamp() click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 329
def new_timestamp
  Time.now.strftime('%Y%m%d%H%M%S')
end
parse(xml) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 117
def parse(xml)
  response = {}

  doc = Nokogiri::XML(xml)
  doc.xpath('//response/*').each do |node|
    if node.elements.size == 0
      response[node.name.downcase.to_sym] = normalize(node.text)
    else
      node.elements.each do |childnode|
        name = "#{node.name.downcase}_#{childnode.name.downcase}"
        response[name.to_sym] = normalize(childnode.text)
      end
    end
  end unless doc.root.nil?

  response
end
sanitize_order_id(order_id) click to toggle source
# File lib/active_merchant/billing/gateways/realex.rb, line 369
def sanitize_order_id(order_id)
  order_id.to_s.gsub(/[^a-zA-Z0-9\-_]/, '')
end