lib/active_merchant/billing/gateways/psl_card.rb in jelaniharris-activemerchant-1.24.1 vs lib/active_merchant/billing/gateways/psl_card.rb in jelaniharris-activemerchant-1.29.1

- old
+ new

@@ -1,250 +1,249 @@ module ActiveMerchant module Billing # # ActiveMerchant PSL Card Gateway - # + # # Notes: # -To be able to use the capture function, the IP address of the machine must be # registered with PSL - # -ESALE_KEYED should only be used in situations where the cardholder perceives the - # transaction to be Internet-based, such as purchasing from a web site/on-line store. - # If the Internet is used purely for the transport of information from the merchant - # directly to the gateway then the appropriate cardholder present or not present message + # -ESALE_KEYED should only be used in situations where the cardholder perceives the + # transaction to be Internet-based, such as purchasing from a web site/on-line store. + # If the Internet is used purely for the transport of information from the merchant + # directly to the gateway then the appropriate cardholder present or not present message # type should be used rather than the ā€˜Eā€™ equivalent. # -The CV2 / AVS policies are set up with the account settings when signing up for an account class PslCardGateway < Gateway self.money_format = :cents self.default_currency = 'GBP' - + self.supported_countries = ['GB'] # Visa Credit, Visa Debit, Mastercard, Maestro, Solo, Electron, # American Express, Diners Club, JCB, International Maestro, # Style, Clydesdale Financial Services, Other - + self.supported_cardtypes = [ :visa, :master, :american_express, :diners_club, :jcb, :switch, :solo, :maestro ] self.homepage_url = 'http://www.paymentsolutionsltd.com/' self.display_name = 'PSL Payment Solutions' - + # Default ISO 3166 country code (GB) cattr_accessor :location self.location = 826 - - # PslCard server URL - The url is the same whether testing or live - use + + # PslCard server self.live_url - The url is the same whether testing or live - use # the test account when testing... - URL = 'https://pslcard3.paymentsolutionsltd.com/secure/transact.asp?' - + self.live_url = self.test_url = 'https://pslcard3.paymentsolutionsltd.com/secure/transact.asp?' + # eCommerce sale transaction, details keyed by merchant or cardholder - MESSAGE_TYPE = 'ESALE_KEYED' - + MESSAGE_TYPE = 'ESALE_KEYED' + # The type of response that we want to get from PSL, options are HTML, XML or REDIRECT RESPONSE_ACTION = 'HTML' - + # Currency Codes CURRENCY_CODES = { 'AUD' => 036, 'GBP' => 826, 'USD' => 840 } - + #The terminal used - only for swipe transactions, so hard coded to 32 for online EMV_TERMINAL_TYPE = 32 - + #Different Dispatch types DISPATCH_LATER = 'LATER' DISPATCH_NOW = 'NOW' - + # Return codes APPROVED = '00' - + #Nominal amount to authorize for a 'dispatch later' type #The nominal amount is held straight away, when the goods are ready #to be dispatched, PSL is informed and the full amount is the #taken. NOMINAL_AMOUNT = 101 - + AVS_CODE = { "ALL MATCH" => 'Y', "SECURITY CODE MATCH ONLY" => 'N', "ADDRESS MATCH ONLY" => 'Y', "NO DATA MATCHES" => 'N', "DATA NOT CHECKED" => 'R', "SECURITY CHECKS NOT SUPPORTED" => 'X' } - + CVV_CODE = { "ALL MATCH" => 'M', "SECURITY CODE MATCH ONLY" => 'M', "ADDRESS MATCH ONLY" => 'N', "NO DATA MATCHES" => 'N', "DATA NOT CHECKED" => 'P', "SECURITY CHECKS NOT SUPPORTED" => 'X' } - + # Create a new PslCardGateway - # + # # The gateway requires that a valid :login be passed in the options hash - # + # # Paramaters: # -options: # :login - the PslCard account login (required) def initialize(options = {}) requires!(options, :login) - - @options = options + super end # Purchase the item straight away - # + # # Parameters: # -money: Amount to be charged as an Integer value in cents # -authorization: the PSL cross reference from the previous authorization # -options: # # Returns: # -ActiveRecord::Billing::Response object - # + # def purchase(money, credit_card, options = {}) post = {} - + add_amount(post, money, DISPATCH_NOW, options) add_credit_card(post, credit_card) add_address(post, options) add_invoice(post, options) add_purchase_details(post) - + commit(post) end - + # Authorize the transaction - # - # Reserves the funds on the customer's credit card, but does not + # + # Reserves the funds on the customer's credit card, but does not # charge the card. # # This implementation does not authorize the full amount, rather it checks that the full amount # is available and only 'reserves' the nominal amount (currently a pound and a penny) - # + # # Parameters: # -money: Amount to be charged as an Integer value in cents # -authorization: the PSL cross reference from the previous authorization # -options: # # Returns: # -ActiveRecord::Billing::Response object - # + # def authorize(money, credit_card, options = {}) post = {} - + add_amount(post, money, DISPATCH_LATER, options) add_credit_card(post, credit_card) add_address(post, options) add_invoice(post, options) add_purchase_details(post) - + commit(post) end - - # Post an authorization. + + # Post an authorization. # - # Captures the funds from an authorized transaction. - # + # Captures the funds from an authorized transaction. + # # Parameters: # -money: Amount to be charged as an Integer value in cents # -authorization: The PSL Cross Reference # -options: # # Returns: # -ActiveRecord::Billing::Response object # def capture(money, authorization, options = {}) post = {} - + add_amount(post, money, DISPATCH_NOW, options) add_reference(post, authorization) add_purchase_details(post) commit(post) end private - + def add_credit_card(post, credit_card) post[:QAName] = credit_card.name post[:CardNumber] = credit_card.number post[:EMVTerminalType] = EMV_TERMINAL_TYPE post[:ExpMonth] = credit_card.month post[:ExpYear] = credit_card.year - - if requires_start_date_or_issue_number?(credit_card) + + if requires_start_date_or_issue_number?(credit_card) post[:IssueNumber] = credit_card.issue_number unless credit_card.issue_number.blank? post[:StartMonth] = credit_card.start_month unless credit_card.start_month.blank? post[:StartYear] = credit_card.start_year unless credit_card.start_year.blank? end - + # CV2 check post[:AVSCV2Check] = credit_card.verification_value? ? 'YES' : 'NO' post[:CV2] = credit_card.verification_value if credit_card.verification_value? end - + def add_address(post, options) address = options[:billing_address] || options[:address] return if address.nil? - + post[:QAAddress] = [:address1, :address2, :city, :state].collect{|a| address[a]}.reject{|a| a.blank?}.join(' ') post[:QAPostcode] = address[:zip] end - + def add_invoice(post, options) post[:MerchantName] = options[:merchant] || 'Merchant Name' # May use this as the order_id field post[:OrderID] = options[:order_id] unless options[:order_id].blank? end - + def add_reference(post, authorization) post[:CrossReference] = authorization end - + def add_amount(post, money, dispatch_type, options) post[:CurrencyCode] = currency_code(options[:currency] || currency(money)) - + if dispatch_type == DISPATCH_LATER post[:amount] = amount(NOMINAL_AMOUNT) post[:DispatchLaterAmount] = amount(money) else post[:amount] = amount(money) end - + post[:Dispatch] = dispatch_type end - + def add_purchase_details(post) post[:EchoAmount] = 'YES' post[:SCBI] = 'YES' # Return information about the transaction post[:MessageType] = MESSAGE_TYPE end - + # Get the currency code for the passed money object - # + # # The money class stores the currency as an ISO 4217:2001 Alphanumeric, # however PSL requires the ISO 4217:2001 Numeric code. - # + # # Parameters: # -money: Integer value in cents - # + # # Returns: # -the ISO 4217:2001 Numberic currency code - # + # def currency_code(currency) CURRENCY_CODES[currency] end - + # Parse the PSL response and create a Response object # # Parameters: # -body: The response string returned from PSL, Formatted: # Key=value&key=value... - # + # # Returns: # -a hash with all of the values returned in the PSL response # def parse(body) @@ -253,38 +252,38 @@ key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten fields[key] = CGI.unescape(value) end fields.symbolize_keys end - + # Send the passed data to PSL for processing # # Parameters: # -request: The data that is to be sent to PSL # # Returns: # - ActiveMerchant::Billing::Response object # def commit(request) - response = parse( ssl_post(URL, post_data(request)) ) - - Response.new(response[:ResponseCode] == APPROVED, response[:Message], response, - :test => test?, + response = parse( ssl_post(self.live_url, post_data(request)) ) + + Response.new(response[:ResponseCode] == APPROVED, response[:Message], response, + :test => test?, :authorization => response[:CrossReference], :cvv_result => CVV_CODE[response[:AVSCV2Check]], :avs_result => { :code => AVS_CODE[response[:AVSCV2Check]] } ) end - + # Put the passed data into a format that can be submitted to PSL # Key=Value&Key=Value... # # Any ampersands and equal signs are removed from the data being posted - # as PSL puts them back into the response string which then cannot be parsed. + # as PSL puts them back into the response string which then cannot be parsed. # This is after escaping before sending the request to PSL - this is a work # around for the time being - # + # # Parameters: # -post: Hash of all the data to be sent # # Returns: # -String: the data to be sent @@ -292,10 +291,10 @@ def post_data(post) post[:CountryCode] = self.location post[:MerchantID] = @options[:login] post[:ValidityID] = @options[:password] post[:ResponseAction] = RESPONSE_ACTION - + post.collect { |key, value| "#{key}=#{CGI.escape(value.to_s.tr('&=', ' '))}" }.join("&") end end