lib/offsite_payments/integrations/gestpay.rb
# With help from Giovanni Intini and his code for RGestPay - http://medlar.it/it/progetti/rgestpay
module OffsitePayments #:nodoc:
module Integrations #:nodoc:
module Gestpay
mattr_accessor :service_url
self.service_url = 'https://ecomm.sella.it/pagam/pagam.aspx'
def self.notification(post, options = {})
Notification.new(post)
end
def self.return(query_string, options = {})
Return.new(query_string)
end
module Common
GestpayEncryptionResponseError = Class.new(StandardError)
VERSION = "2.0"
ENCRYPTION_PATH = "/CryptHTTPS/Encrypt.asp"
DECRYPTION_PATH = "/CryptHTTPS/Decrypt.asp"
DELIMITER = '*P1*'
CURRENCY_MAPPING = {
'EUR' => '242',
'ITL' => '18',
'BRL' => '234',
'USD' => '1',
'JPY' => '71',
'HKD' => '103'
}
def parse_response(response)
case response
when /#cryptstring#(.*)#\/cryptstring#/, /#decryptstring#(.*)#\/decryptstring#/
$1
when /#error#(.*)#\/error#/
raise GestpayEncryptionResponseError, "An error occurred retrieving the encrypted string from GestPay: #{$1}"
else
raise GestpayEncryptionResponseError, "No response was received by GestPay"
end
end
def ssl_get(url, path)
uri = URI.parse(url)
site = Net::HTTP.new(uri.host, uri.port)
site.use_ssl = true
site.verify_mode = OpenSSL::SSL::VERIFY_NONE
site.get(path).body
rescue Timeout::Error, Errno::ECONNRESET, Errno::ETIMEDOUT
raise ActionViewHelperError, "Error occured while contacting payment gateway. Please try again."
end
end
class Helper < OffsitePayments::Helper
include Common
# Valid language codes
# Italian => 1
# English => 2
# Spanish => 3
# French => 4
# Tedesco => 5
def initialize(order, account, options = {})
super
add_field('PAY1_IDLANGUAGE', 2)
end
mapping :account, 'ShopLogin'
mapping :amount, 'PAY1_AMOUNT'
mapping :currency, 'PAY1_UICCODE'
mapping :order, 'PAY1_SHOPTRANSACTIONID'
# Buyer name PAY1_CHNAME
mapping :customer, :email => 'PAY1_CHEMAIL'
mapping :credit_card, :number => 'PAY1_CARDNUMBER',
:expiry_month => 'PAY1_EXPMONTH',
:expiry_year => 'PAY1_EXPYEAR',
:verification_value => 'PAY1_CVV'
def customer(params = {})
add_field(mappings[:customer][:email], params[:email])
add_field('PAY1_CHNAME', "#{params[:first_name]} #{params[:last_name]}")
end
def currency=(currency_code)
code = CURRENCY_MAPPING[currency_code]
raise ActionViewHelperError, "Invalid currency code #{currency_code} specified" if code.nil?
add_field(mappings[:currency], code)
end
def form_fields
@encrypted_data ||= get_encrypted_string
{
'a' => @fields['ShopLogin'],
'b' => @encrypted_data
}
end
def get_encrypted_string
response = ssl_get(Gestpay.service_url, encryption_query_string)
parse_response(response)
rescue GestpayEncryptionResponseError => e
raise ActionViewHelperError.new(e)
end
def encryption_query_string
fields = ['PAY1_AMOUNT', 'PAY1_SHOPTRANSACTIONID', 'PAY1_UICCODE']
encoded_params = fields.collect{ |field| "#{field}=#{CGI.escape(@fields[field])}" }.join(DELIMITER)
"#{ENCRYPTION_PATH}?a=" + CGI.escape(@fields['ShopLogin']) + "&b=" + encoded_params + "&c=" + CGI.escape(VERSION)
end
end
class Notification < OffsitePayments::Notification
include Common
def complete?
status == 'Completed'
end
# The important param
def item_id
params['PAY1_SHOPTRANSACTIONID']
end
def transaction_id
params['PAY1_BANKTRANSACTIONID']
end
# the money amount we received in X.2 decimal.
def gross
params['PAY1_AMOUNT']
end
def currency
# Ruby 1.9 compat
method = CURRENCY_MAPPING.respond_to?(:key) ? :key : :index
CURRENCY_MAPPING.send(method, params['PAY1_UICCODE'])
end
def test?
false
end
def status
case params['PAY1_TRANSACTIONRESULT']
when 'OK'
'Completed'
else
'Failed'
end
end
def acknowledge(authcode = nil)
true
end
private
# Take the posted data and move the relevant data into a hash
def parse(query_string)
@raw = query_string
return if query_string.blank?
encrypted_params = parse_delimited_string(query_string)
return if encrypted_params['a'].blank? || encrypted_params['b'].blank?
@params = decrypt_data(encrypted_params['a'], encrypted_params['b'])
end
def parse_delimited_string(string, delimiter = '&', unencode_cgi = false)
result = {}
for line in string.split(delimiter)
key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
result[key] = unencode_cgi ? CGI.unescape(value) : value
end
result
end
def decrypt_data(shop_login, encrypted_string)
response = ssl_get(Gestpay.service_url, decryption_query_string(shop_login, encrypted_string))
encoded_response = parse_response(response)
parse_delimited_string(encoded_response, DELIMITER, true)
rescue GestpayEncryptionResponseError
{ 'PAY1_TRANSACTIONRESULT' => 'Error' }
end
def decryption_query_string(shop_login, encrypted_string)
"#{DECRYPTION_PATH}?a=" + CGI.escape(shop_login) + "&b=" + encrypted_string + "&c=" + CGI.escape(VERSION)
end
end
class Return < OffsitePayments::Return
end
end
end
end