require 'rexml/document' module ActiveMerchant #:nodoc: module Billing #:nodoc: # Public: For more information on the Eway Gateway please visit their # {Developers Area}[http://www.eway.com.au/developers/api/direct-payments] class EwayGateway < Gateway self.live_url = 'https://www.eway.com.au' self.money_format = :cents self.supported_countries = ['AU'] self.supported_cardtypes = [:visa, :master, :american_express, :diners_club] self.homepage_url = 'http://www.eway.com.au/' self.display_name = 'eWAY' # Public: Create a new Eway Gateway. # options - A hash of options: # :login - Your Customer ID. # :password - Your XML Refund Password that you # specified on the Eway site. (optional) def initialize(options = {}) requires!(options, :login) super end def purchase(money, creditcard, options = {}) requires_address!(options) post = {} add_creditcard(post, creditcard) add_address(post, options) add_customer_id(post) add_invoice_data(post, options) add_non_optional_data(post) add_amount(post, money) post[:CustomerEmail] = options[:email] commit(purchase_url(post[:CVN]), money, post) end def refund(money, authorization, options={}) post = {} add_customer_id(post) add_amount(post, money) add_non_optional_data(post) post[:OriginalTrxnNumber] = authorization post[:RefundPassword] = @options[:password] post[:CardExpiryMonth] = nil post[:CardExpiryYear] = nil commit(refund_url, money, post) end def supports_scrubbing true end def scrub(transcript) transcript. gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). gsub(%r(()\d+())i, '\1[FILTERED]\2'). gsub(%r(()\d+())i, '\1[FILTERED]\2') end private def requires_address!(options) raise ArgumentError.new('Missing eWay required parameters: address or billing_address') unless options.has_key?(:address) or options.has_key?(:billing_address) end def add_creditcard(post, creditcard) post[:CardNumber] = creditcard.number post[:CardExpiryMonth] = sprintf('%.2i', creditcard.month) post[:CardExpiryYear] = sprintf('%.4i', creditcard.year)[-2..-1] post[:CustomerFirstName] = creditcard.first_name post[:CustomerLastName] = creditcard.last_name post[:CardHoldersName] = creditcard.name post[:CVN] = creditcard.verification_value if creditcard.verification_value? end def add_address(post, options) if address = options[:billing_address] || options[:address] post[:CustomerAddress] = [address[:address1], address[:address2], address[:city], address[:state], address[:country]].compact.join(', ') post[:CustomerPostcode] = address[:zip] end end def add_customer_id(post) post[:CustomerID] = @options[:login] end def add_invoice_data(post, options) post[:CustomerInvoiceRef] = options[:order_id] post[:CustomerInvoiceDescription] = options[:description] end def add_amount(post, money) post[:TotalAmount] = amount(money) end def add_non_optional_data(post) post[:Option1] = nil post[:Option2] = nil post[:Option3] = nil post[:TrxnNumber] = nil end def commit(url, money, parameters) raw_response = ssl_post(url, post_data(parameters)) response = parse(raw_response) Response.new(success?(response), message_from(response[:ewaytrxnerror]), response, :authorization => response[:ewaytrxnnumber], :test => test? ) end def success?(response) response[:ewaytrxnstatus] == 'True' end def parse(xml) response = {} xml = REXML::Document.new(xml) xml.elements.each('//ewayResponse/*') do |node| response[node.name.downcase.to_sym] = normalize(node.text) end unless xml.root.nil? response end def post_data(parameters = {}) xml = REXML::Document.new root = xml.add_element('ewaygateway') parameters.each do |key, value| root.add_element("eway#{key}").text = value end xml.to_s end def message_from(message) return '' if message.blank? MESSAGES[message[0, 2]] || message end def purchase_url(cvn) suffix = test? ? 'xmltest/testpage.asp' : 'xmlpayment.asp' gateway_part = cvn ? 'gateway_cvn' : 'gateway' "#{live_url}/#{gateway_part}/#{suffix}" end def refund_url suffix = test? ? 'xmltest/refund_test.asp' : 'xmlpaymentrefund.asp' "#{live_url}/gateway/#{suffix}" end MESSAGES = { '00' => 'Transaction Approved', '01' => 'Refer to Issuer', '02' => 'Refer to Issuer, special', '03' => 'No Merchant', '04' => 'Pick Up Card', '05' => 'Do Not Honour', '06' => 'Error', '07' => 'Pick Up Card, Special', '08' => 'Honour With Identification', '09' => 'Request In Progress', '10' => 'Approved For Partial Amount', '11' => 'Approved, VIP', '12' => 'Invalid Transaction', '13' => 'Invalid Amount', '14' => 'Invalid Card Number', '15' => 'No Issuer', '16' => 'Approved, Update Track 3', '19' => 'Re-enter Last Transaction', '21' => 'No Action Taken', '22' => 'Suspected Malfunction', '23' => 'Unacceptable Transaction Fee', '25' => 'Unable to Locate Record On File', '30' => 'Format Error', '31' => 'Bank Not Supported By Switch', '33' => 'Expired Card, Capture', '34' => 'Suspected Fraud, Retain Card', '35' => 'Card Acceptor, Contact Acquirer, Retain Card', '36' => 'Restricted Card, Retain Card', '37' => 'Contact Acquirer Security Department, Retain Card', '38' => 'PIN Tries Exceeded, Capture', '39' => 'No Credit Account', '40' => 'Function Not Supported', '41' => 'Lost Card', '42' => 'No Universal Account', '43' => 'Stolen Card', '44' => 'No Investment Account', '51' => 'Insufficient Funds', '52' => 'No Cheque Account', '53' => 'No Savings Account', '54' => 'Expired Card', '55' => 'Incorrect PIN', '56' => 'No Card Record', '57' => 'Function Not Permitted to Cardholder', '58' => 'Function Not Permitted to Terminal', '59' => 'Suspected Fraud', '60' => 'Acceptor Contact Acquirer', '61' => 'Exceeds Withdrawal Limit', '62' => 'Restricted Card', '63' => 'Security Violation', '64' => 'Original Amount Incorrect', '66' => 'Acceptor Contact Acquirer, Security', '67' => 'Capture Card', '75' => 'PIN Tries Exceeded', '82' => 'CVV Validation Error', '90' => 'Cutoff In Progress', '91' => 'Card Issuer Unavailable', '92' => 'Unable To Route Transaction', '93' => 'Cannot Complete, Violation Of The Law', '94' => 'Duplicate Transaction', '96' => 'System Error' } end end end