require 'rexml/document' module ActiveMerchant #:nodoc: module Billing #:nodoc: # This class implements the Psigate gateway for the ActiveMerchant module. # # Modifications by Sean O'Hara ( sohara at sohara dot com ) # # Usage for a PreAuth (authorize) is as follows: # # gateway = PsigateGateway.new( # :login => 'teststore', # :password => 'psigate1234' # ) # # creditcard = CreditCard.new( # :number => '4242424242424242', # :month => 8, # :year => 2006, # :first_name => 'Longbob', # :last_name => 'Longsen' # ) # # twenty = 2000 # response = @gateway.authorize(twenty, creditcard, # :order_id => 1234, # :billing_address => { # :address1 => '123 fairweather Lane', # :address2 => 'Apt B', # :city => 'New York', # :state => 'NY', # :country => 'U.S.A.', # :zip => '10010' # }, # :email => 'jack@yahoo.com' # ) class PsigateGateway < Gateway self.test_url = 'https://realtimestaging.psigate.com/xml' self.live_url = 'https://realtime.psigate.com/xml' self.supported_cardtypes = [:visa, :master, :american_express] self.supported_countries = ['CA'] self.homepage_url = 'http://www.psigate.com/' self.display_name = 'Psigate' SUCCESS_MESSAGE = 'Success' FAILURE_MESSAGE = 'The transaction was declined' def initialize(options = {}) requires!(options, :login, :password) super end def authorize(money, creditcard, options = {}) requires!(options, :order_id) options[:CardAction] = '1' commit(money, creditcard, options) end def purchase(money, creditcard, options = {}) requires!(options, :order_id) options[:CardAction] = '0' commit(money, creditcard, options) end def capture(money, authorization, options = {}) options[:CardAction] = '2' options[:order_id], options[:trans_ref_number] = split_authorization(authorization) commit(money, nil, options) end def credit(money, authorization, options = {}) ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE refund(money, authorization, options) end def refund(money, authorization, options = {}) options[:CardAction] = '3' options[:order_id], options[:trans_ref_number] = split_authorization(authorization) commit(money, nil, options) end def void(authorization, options = {}) options[:CardAction] = '9' options[:order_id], options[:trans_ref_number] = split_authorization(authorization) commit(nil, nil, options) end def supports_scrubbing? true end def scrub(transcript) transcript. gsub(%r(()[^<]*())i, '\1[FILTERED]\2'). gsub(%r(()[^<]*())i, '\1[FILTERED]\2'). gsub(%r(()[^<]*())i, '\1[FILTERED]\2') end private def commit(money, creditcard, options = {}) response = parse(ssl_post(url, post_data(money, creditcard, options))) Response.new(successful?(response), message_from(response), response, :test => test?, :authorization => build_authorization(response), :avs_result => { :code => response[:avsresult] }, :cvv_result => response[:cardidresult] ) end def url (test? ? self.test_url : self.live_url) end def successful?(response) response[:approved] == 'APPROVED' end def parse(xml) response = {:message => 'Global Error Receipt', :complete => false} xml = REXML::Document.new(xml) xml.elements.each('//Result/*') do |node| response[node.name.downcase.to_sym] = normalize(node.text) end unless xml.root.nil? response end def post_data(money, creditcard, options) xml = REXML::Document.new xml << REXML::XMLDecl.new root = xml.add_element('Order') parameters(money, creditcard, options).each do |key, value| root.add_element(key.to_s).text = value if value end xml.to_s end def parameters(money, creditcard, options = {}) params = { # General order parameters :StoreID => @options[:login], :Passphrase => @options[:password], :TestResult => options[:test_result], :OrderID => options[:order_id], :UserID => options[:user_id], :Phone => options[:phone], :Fax => options[:fax], :Email => options[:email], :TransRefNumber => options[:trans_ref_number], # Credit Card parameters :PaymentType => 'CC', :CardAction => options[:CardAction], # Financial parameters :CustomerIP => options[:ip], :SubTotal => amount(money), :Tax1 => options[:tax1], :Tax2 => options[:tax2], :ShippingTotal => options[:shipping_total], } if creditcard exp_month = sprintf('%.2i', creditcard.month) unless creditcard.month.blank? exp_year = creditcard.year.to_s[2, 2] unless creditcard.year.blank? card_id_code = (creditcard.verification_value.blank? ? nil : '1') params.update( :CardNumber => creditcard.number, :CardExpMonth => exp_month, :CardExpYear => exp_year, :CardIDCode => card_id_code, :CardIDNumber => creditcard.verification_value ) end if(address = (options[:billing_address] || options[:address])) params[:Bname] = address[:name] || creditcard.name params[:Baddress1] = address[:address1] unless address[:address1].blank? params[:Baddress2] = address[:address2] unless address[:address2].blank? params[:Bcity] = address[:city] unless address[:city].blank? params[:Bprovince] = address[:state] unless address[:state].blank? params[:Bpostalcode] = address[:zip] unless address[:zip].blank? params[:Bcountry] = address[:country] unless address[:country].blank? params[:Bcompany] = address[:company] unless address[:company].blank? end if address = options[:shipping_address] params[:Sname] = address[:name] || creditcard.name params[:Saddress1] = address[:address1] unless address[:address1].blank? params[:Saddress2] = address[:address2] unless address[:address2].blank? params[:Scity] = address[:city] unless address[:city].blank? params[:Sprovince] = address[:state] unless address[:state].blank? params[:Spostalcode] = address[:zip] unless address[:zip].blank? params[:Scountry] = address[:country] unless address[:country].blank? params[:Scompany] = address[:company] unless address[:company].blank? end params end def message_from(response) if response[:approved] == 'APPROVED' return SUCCESS_MESSAGE else return FAILURE_MESSAGE if response[:errmsg].blank? return response[:errmsg].gsub(/[^\w]/, ' ').split.join(' ').capitalize end end def split_authorization(authorization) order_id, trans_ref_number = authorization.split(';') [order_id, trans_ref_number] end def build_authorization(response) [response[:orderid], response[:transrefnumber]].join(';') end end end end