class ActiveMerchant::Billing::Realex3dsGateway
For more information on the Realex Payment Gateway visit their site realexpayments.com. Realex is the leading gateway in Ireland
Merchant ID and Password¶ ↑
To be able to use this library you will need to obtain an account from Realex, you can find contact them via their website.
Caveats¶ ↑
Realex requires that you specify the account to which your transactions are made.
gateway = ActiveMerchant::Billing::Realex3dsGateway.new(:login => 'xxx', :password => 'xxx', :acction => 'xxx')
If you wish to accept multiple currencies, you need to create an account per currency. This you would need to handle within your application logic. Again, contact Realex for more information.
They also require accepting payment from a Diners card (Mastercard) go through a different account.
Realex also requires that you send several (extra) required identifiers with credit and void methods
-
order_id
-
pasref
-
authorization
The pasref can be accessed from the response params. i.e.
response.params['pasref']
Testing¶ ↑
Realex provide test card numbers on a per-account basis, you will need to request these. Then if you copy the fixtures file that comes with this library to ~/.active_merchant/fixtures.yml you can add in the required card number (and account) fixtures.
Constants
- BANK_ERROR
- CARD_MAPPING
- DECLINED
- ERROR
- RECURRING_PAYMENTS_URL
- THREE_D_SECURE_URL
- URL
Public Class Methods
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 69 def initialize(options = {}) requires!(options, :login, :password) options[:refund_hash] = Digest::SHA1.hexdigest(options[:rebate_secret]) if options.has_key?(:rebate_secret) @options = options super end
Private Class Methods
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 605 def self.timestamp Time.now.strftime('%Y%m%d%H%M%S') end
Public Instance Methods
Captures the funds from an authorized transaction.
Parameters¶ ↑
-
money
– The amount to be captured. Either an Integer value in cents or a Money object. -
authorization
– The authorization returned from the previous authorize request.
Options¶ ↑
-
:order_id
– The application generated order identifier. (REQUIRED) -
:pasref
– The realex payments reference of the original transaction. (REQUIRED)
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 174 def capture(money, authorization, options = {}) requires!(options, :pasref) requires!(options, :order_id) request = build_capture_request(authorization, options) commit(request) end
Credit an account.
This transaction is also referred to as a Refund (or Rebate) and indicates to the gateway that money should flow from the merchant to the customer.
Parameters¶ ↑
-
money
– The amount to be credited to the customer. Either an Integer value in cents or a Money object. -
authorization
- The authorization returned from the previous authorize request. -
options
– A hash of parameters.
Options¶ ↑
-
:order_id
– The application generated order identifier. (REQUIRED) -
:pasref
– The realex payments reference of the original transaction. (REQUIRED)
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 198 def credit(money, authorization, options = {}) requires!(options, :order_id) requires!(options, :pasref) request = build_credit_request(money, authorization, options) commit(request) end
Perform a purchase, which is essentially an authorization and capture in a single operation.
Parameters¶ ↑
-
money
– The amount to be purchased. Either an Integer value in cents or a Money object. -
creditcard
– The CreditCard details for the transaction. -
options
– A hash of optional parameters.
Options¶ ↑
-
:order_id
– The application generated order identifier. (REQUIRED)
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 114 def purchase(money, creditcard, options = {}) requires!(options, :order_id) if options[:three_d_secure_auth] three_d_secure_request = build_3d_secure_verify_signature_or_enrolled_request("3ds-verifysig", money, creditcard, options) three_d_secure_response = commit(three_d_secure_request, :three_d_secure) result = three_d_secure_response.params['result'] if result == '00' status = three_d_secure_response.params['threedsecure_status'] # success if status == 'Y' || status == 'A' # Y: 3d Secure complete. # A: ACS service aknowledges. # not-liable. continue options[:three_d_secure_sig] = {} options[:three_d_secure_sig][:eci] = three_d_secure_response.params['threedsecure_eci'] options[:three_d_secure_sig][:xid] = three_d_secure_response.params['threedsecure_xid'] options[:three_d_secure_sig][:cavv] = three_d_secure_response.params['threedsecure_cavv'] # TODO add option[:accept_liability_authentication_failed] # TODO add option[:accept_liability_acs_failure] elsif status == 'N' # password entered incorrectly # liable. abort? return Response.new(false, "3DSecure password entered incorrectly. Aborting transaction.",{},{}) elsif status == 'U' # Bank ACS service having dificulty. # liable. abort? return Response.new(false, "3DSecure Bank ACS service 500 errors. Aborting transaction.",{},{}) end elsif result == "110" # fail, message tampered with. return Response.new(false, "3DSecure message tampered. Aborting transaction.",{},{}) else return Response.new(false, "Unknown 3DSecure Error.",{},{}) end end if options[:three_d_secure] && !options[:three_d_secure_auth] three_d_secure_request = build_3d_secure_verify_signature_or_enrolled_request("3ds-verifyenrolled", money, creditcard, options) three_d_secure_response = commit(three_d_secure_request, :three_d_secure) return three_d_secure_response if three_d_secure_response.enrolled? end request = build_purchase_or_authorization_request(:purchase, money, creditcard, options) commit(request) end
Recurring Payments
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 227 def recurring(money, credit_card, options = {}) requires!(options, :order_id) request = build_receipt_in_request(money, credit_card, options) commit(request, :recurring) end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 234 def store(credit_card, options = {}) requires!(options, :order_id) request = build_new_card_request(credit_card, options) commit(request, :recurring) end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 245 def store_user(options = {}) requires!(options, :order_id) request = build_new_payee_request(options) commit(request, :recurring) end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 240 def unstore(creditcard, options = {}) request = build_cancel_card_request(creditcard, options) commit(request, :recurring) end
Void a previous transaction
Parameters¶ ↑
-
authorization
- The authorization returned from the previous authorize request.
Options¶ ↑
-
:order_id
– The application generated order identifier. (REQUIRED) -
:pasref
– The realex payments reference of the original transaction. (REQUIRED)
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 217 def void(authorization, options = {}) requires!(options, :order_id) requires!(options, :pasref) request = build_void_request(authorization, options) commit(request) end
Private Instance Methods
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 460 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] # xml.tag! 'varref' if billing_address xml.tag! 'address', 'type' => 'billing' do xml.tag! 'code', avs_input_code_or_zip( billing_address, options ) xml.tag! 'country', billing_address[:country] end end if shipping_address xml.tag! 'address', 'type' => 'shipping' do xml.tag! 'code', shipping_address[:zip] xml.tag! 'country', shipping_address[:country] end end end end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 514 def add_ammount(xml, money, options) xml.tag! 'amount', amount(money), 'currency' => options[:currency] || currency(money) end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 518 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', credit_card.issue_number 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
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 507 def add_comments(xml, options) return unless options[:description] xml.tag! 'comments' do xml.tag! 'comment', options[:description], 'id' => 1 end end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 494 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
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 550 def add_signed_digest(xml, *values) string = stringify_values(values) xml.tag! 'sha1hash', sha1from(string) end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 433 def add_three_d_secure(xml, options) if options[:three_d_secure_sig] xml.tag! 'mpi' do xml.tag! 'cavv', options[:three_d_secure_sig][:cavv] xml.tag! 'xid', options[:three_d_secure_sig][:xid] xml.tag! 'eci', options[:three_d_secure_sig][:eci] end end end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 501 def add_transaction_identifiers(xml, authorization, options) xml.tag! 'orderid', sanitize_order_id(options[:order_id]) xml.tag! 'pasref', options[:pasref] xml.tag! 'authcode', authorization end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 555 def auto_settle_flag(action) action == :authorization ? '0' : '1' end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 532 def avs_input_code(address) address.values_at(:zip, :address1).map{ |v| extract_digits(v) }.join('|') end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 490 def avs_input_code_or_zip(address, options) options[ :skip_avs_check ] ? address[ :zip ] : avs_input_code( address ) end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 418 def build_3d_secure_verify_signature_or_enrolled_request(action, money, credit_card, options) timestamp = self.class.timestamp xml = Builder::XmlMarkup.new :indent => 2 xml.tag! 'request', 'timestamp' => timestamp, 'type' => action do add_merchant_details(xml, options) xml.tag! 'orderid', sanitize_order_id(options[:order_id]) add_ammount(xml, money, options) add_card(xml, credit_card) xml.tag!('pares', options[:three_d_secure_auth][:pa_res]) if(action == '3ds-verifysig' && options[:three_d_secure_auth] ) add_signed_digest(xml, timestamp, @options[:login], options[:order_id], amount(money), (options[:currency] || currency(money)), credit_card.number) add_comments(xml, options) end xml.target! end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 363 def build_cancel_card_request(creditcard, options = {}) timestamp = self.class.timestamp xml = Builder::XmlMarkup.new :indent => 2 xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'card-cancel-card' do add_merchant_details(xml, options) xml.tag! 'card' do xml.tag! 'ref', options[:payment_method] xml.tag! 'payerref', options[:user][:id] xml.tag! 'expdate', expiry_date(creditcard) end # TODO userid . card ref . expiry date add_signed_digest(xml, timestamp, @options[:login], options[:user][:id], options[:payment_method]) end end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 324 def build_capture_request(authorization, options) timestamp = self.class.timestamp xml = Builder::XmlMarkup.new :indent => 2 xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'settle' do add_merchant_details(xml, options) add_transaction_identifiers(xml, authorization, options) add_comments(xml, options) add_signed_digest(xml, timestamp, @options[:login], options[:order_id], '', '', '') end xml.target! end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 336 def build_credit_request(money, authorization, options) timestamp = self.class.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], options[:order_id], amount(money), (options[:currency] || currency(money)), '') end xml.target! end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 378 def build_new_card_request(credit_card, options = {}) timestamp = self.class.timestamp xml = Builder::XmlMarkup.new :indent => 2 xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'card-new' do add_merchant_details(xml, options) xml.tag! 'orderid', sanitize_order_id(options[:order_id]) xml.tag! 'card' do xml.tag! 'ref', options[:payment_method] xml.tag! 'payerref', options[:user][:id] 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', credit_card.issue_number xml.tag! 'cvn' do xml.tag! 'number', credit_card.verification_value xml.tag! 'presind', (options['presind'] || (credit_card.verification_value? ? 1 : nil)) end end # timestamp.merchantid.orderid.amount.currency.payerref.chname.(card)number add_signed_digest(xml, timestamp, @options[:login], options[:order_id], '', '', options[:user][:id], credit_card.name, credit_card.number) end xml.target! end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 403 def build_new_payee_request(options) timestamp = self.class.timestamp xml = Builder::XmlMarkup.new :indent => 2 xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'payer-new' do add_merchant_details(xml, options) xml.tag! 'orderid', sanitize_order_id(options[:order_id]) xml.tag! 'payer', 'type' => 'Business', 'ref' => options[:user][:id] do xml.tag! 'firstname', options[:user][:first_name] xml.tag! 'surname', options[:user][:last_name] end add_signed_digest(xml, timestamp, @options[:login], options[:order_id], '', '', options[:user][:id]) end xml.target! end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 443 def build_receipt_in_request(money, credit_card, options) timestamp = self.class.timestamp xml = Builder::XmlMarkup.new :indent => 2 xml.tag! 'request', 'timestamp' => timestamp, 'type' => 'receipt-in' do add_merchant_details(xml, options) xml.tag! 'orderid', sanitize_order_id(options[:order_id]) add_ammount(xml, money, options) xml.tag! 'payerref', options[:user][:id] xml.tag! 'paymentmethod', options[:payment_method] xml.tag! 'autosettle', 'flag' => '1' add_signed_digest(xml, timestamp, @options[:login], options[:order_id], amount(money), (options[:currency] || currency(money)), options[:user][:id]) add_comments(xml, options) add_address_and_customer_info(xml, options) end xml.target! end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 351 def build_void_request(authorization, options) timestamp = self.class.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], options[:order_id], '', '', '') end xml.target! end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 252 def commit(request, endpoint=:default) url = URL url = THREE_D_SECURE_URL if endpoint == :three_d_secure url = RECURRING_PAYMENTS_URL if endpoint == :recurring response = ssl_post(url, request) parsed = parse(response) options = { :test => parsed[:message] =~ /\[ test system \]/, :authorization => parsed[:authcode], :cvv_result => parsed[:cvnresult], :body => response, :avs_result => { :street_match => parsed[:avsaddressresponse], :postal_match => parsed[:avspostcoderesponse] } } if endpoint == :three_d_secure options.merge!({ :pa_req => parsed[:pareq], :acs_url => parsed[:url], :three_d_secure => true, :xid => parsed[:xid], :three_d_secure_enrolled => parsed[:enrolled] == "Y" ? true : false }) end Response.new(parsed[:result] == "00", message_from(parsed), parsed, options) end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 559 def expiry_date(credit_card) "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}" end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 536 def extract_digits(string) return "" if string.nil? string.gsub(/[\D]/,'') end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 577 def message_from(response) message = nil case response[:result] when "00" message = SUCCESS when "101" message = response[:message] when "102", "103" message = DECLINED when /^2[0-9][0-9]/ message = BANK_ERROR when /^3[0-9][0-9]/ message = REALEX_ERROR when /^5[0-9][0-9]/ message = response[:message] when "600", "601", "603" message = ERROR when "666" message = CLIENT_DEACTIVATED else message = DECLINED end end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 567 def normalize(field) case field when "true" then true when "false" then false when "" then nil when "null" then nil else field end end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 284 def parse(xml) response = {} xml = REXML::Document.new(xml) return response unless xml.root xml.elements.each('//response/*') 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 response end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 601 def sanitize_order_id(order_id) order_id.to_s.gsub(/[^a-zA-Z0-9\-_]/, '') end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 563 def sha1from(string) Digest::SHA1.hexdigest("#{Digest::SHA1.hexdigest(string)}.#{@options[:password]}") end
# File lib/active_merchant/billing/gateways/realex3ds.rb, line 541 def stringify_values(values) string = "" values.each do |val| string << "#{val}" string << "." unless val.equal?(values.last) end string end