class ActiveMerchant::Billing::PslCardGateway

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
 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

Constants

APPROVED

Return codes

AVS_CODE
CURRENCY_CODES

Currency Codes

CVV_CODE
DISPATCH_LATER

Different Dispatch types

DISPATCH_NOW
EMV_TERMINAL_TYPE

The terminal used - only for swipe transactions, so hard coded to 32 for online

MESSAGE_TYPE

eCommerce sale transaction, details keyed by merchant or cardholder

NOMINAL_AMOUNT

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.

RESPONSE_ACTION

The type of response that we want to get from PSL, options are HTML, XML or REDIRECT

Public Class Methods

new(options = {}) click to toggle source

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)
Calls superclass method ActiveMerchant::Billing::Gateway::new
# File lib/active_merchant/billing/gateways/psl_card.rb, line 90
def initialize(options = {})
  requires!(options, :login)

  super
end

Public Instance Methods

authorize(money, credit_card, options = {}) click to toggle source

Authorize the transaction

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
# File lib/active_merchant/billing/gateways/psl_card.rb, line 134
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
capture(money, authorization, options = {}) click to toggle source

Post an authorization.

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
# File lib/active_merchant/billing/gateways/psl_card.rb, line 158
def capture(money, authorization, options = {})
  post = {}

  add_amount(post, money, DISPATCH_NOW, options)
  add_reference(post, authorization)
  add_purchase_details(post)

  commit(post)
end
purchase(money, credit_card, options = {}) click to toggle source

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
# File lib/active_merchant/billing/gateways/psl_card.rb, line 106
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

Private Instance Methods

add_address(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/psl_card.rb, line 188
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
add_amount(post, money, dispatch_type, options) click to toggle source
# File lib/active_merchant/billing/gateways/psl_card.rb, line 205
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
add_credit_card(post, credit_card) click to toggle source
# File lib/active_merchant/billing/gateways/psl_card.rb, line 170
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)
    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
add_invoice(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/psl_card.rb, line 196
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
add_purchase_details(post) click to toggle source
# File lib/active_merchant/billing/gateways/psl_card.rb, line 218
def add_purchase_details(post)
  post[:EchoAmount] = 'YES'
  post[:SCBI] = 'YES'                   # Return information about the transaction
  post[:MessageType] = MESSAGE_TYPE
end
add_reference(post, authorization) click to toggle source
# File lib/active_merchant/billing/gateways/psl_card.rb, line 201
def add_reference(post, authorization)
  post[:CrossReference] = authorization
end
commit(request) click to toggle source

Send the passed data to PSL for processing

Parameters:

-request: The data that is to be sent to PSL

Returns:

- ActiveMerchant::Billing::Response object
# File lib/active_merchant/billing/gateways/psl_card.rb, line 266
def commit(request)
  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
currency_code(currency) click to toggle source

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
# File lib/active_merchant/billing/gateways/psl_card.rb, line 235
def currency_code(currency)
  CURRENCY_CODES[currency]
end
parse(body) click to toggle source

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
# File lib/active_merchant/billing/gateways/psl_card.rb, line 248
def parse(body)

  fields = {}
  for line in body.split('&')
    key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
    fields[key] = CGI.unescape(value)
  end
  fields.symbolize_keys
end
post_data(post) click to toggle source

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. 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
# File lib/active_merchant/billing/gateways/psl_card.rb, line 291
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