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