activemerchant 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. data/CHANGELOG +40 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +93 -0
  4. data/lib/active_merchant.rb +59 -0
  5. data/lib/active_merchant/billing/base.rb +52 -0
  6. data/lib/active_merchant/billing/credit_card.rb +217 -0
  7. data/lib/active_merchant/billing/gateway.rb +100 -0
  8. data/lib/active_merchant/billing/gateways.rb +15 -0
  9. data/lib/active_merchant/billing/gateways/authorize_net.rb +236 -0
  10. data/lib/active_merchant/billing/gateways/bogus.rb +92 -0
  11. data/lib/active_merchant/billing/gateways/eway.rb +235 -0
  12. data/lib/active_merchant/billing/gateways/linkpoint.rb +445 -0
  13. data/lib/active_merchant/billing/gateways/moneris.rb +205 -0
  14. data/lib/active_merchant/billing/gateways/payflow.rb +84 -0
  15. data/lib/active_merchant/billing/gateways/payflow/f73e89fd.0 +17 -0
  16. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +190 -0
  17. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +30 -0
  18. data/lib/active_merchant/billing/gateways/payflow_express.rb +123 -0
  19. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +9 -0
  20. data/lib/active_merchant/billing/gateways/payflow_uk.rb +17 -0
  21. data/lib/active_merchant/billing/gateways/paypal.rb +90 -0
  22. data/lib/active_merchant/billing/gateways/paypal/api_cert_chain.crt +35 -0
  23. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +208 -0
  24. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +30 -0
  25. data/lib/active_merchant/billing/gateways/paypal_express.rb +115 -0
  26. data/lib/active_merchant/billing/gateways/psigate.rb +265 -0
  27. data/lib/active_merchant/billing/gateways/trust_commerce.rb +330 -0
  28. data/lib/active_merchant/billing/gateways/usa_epay.rb +189 -0
  29. data/lib/active_merchant/billing/integrations.rb +12 -0
  30. data/lib/active_merchant/billing/integrations/action_view_helper.rb +65 -0
  31. data/lib/active_merchant/billing/integrations/bogus.rb +17 -0
  32. data/lib/active_merchant/billing/integrations/bogus/helper.rb +17 -0
  33. data/lib/active_merchant/billing/integrations/bogus/notification.rb +11 -0
  34. data/lib/active_merchant/billing/integrations/chronopay.rb +17 -0
  35. data/lib/active_merchant/billing/integrations/chronopay/helper.rb +81 -0
  36. data/lib/active_merchant/billing/integrations/chronopay/notification.rb +156 -0
  37. data/lib/active_merchant/billing/integrations/gestpay.rb +21 -0
  38. data/lib/active_merchant/billing/integrations/gestpay/common.rb +42 -0
  39. data/lib/active_merchant/billing/integrations/gestpay/helper.rb +72 -0
  40. data/lib/active_merchant/billing/integrations/gestpay/notification.rb +83 -0
  41. data/lib/active_merchant/billing/integrations/helper.rb +79 -0
  42. data/lib/active_merchant/billing/integrations/nochex.rb +21 -0
  43. data/lib/active_merchant/billing/integrations/nochex/helper.rb +68 -0
  44. data/lib/active_merchant/billing/integrations/nochex/notification.rb +101 -0
  45. data/lib/active_merchant/billing/integrations/notification.rb +52 -0
  46. data/lib/active_merchant/billing/integrations/paypal.rb +35 -0
  47. data/lib/active_merchant/billing/integrations/paypal/helper.rb +103 -0
  48. data/lib/active_merchant/billing/integrations/paypal/notification.rb +187 -0
  49. data/lib/active_merchant/billing/response.rb +28 -0
  50. data/lib/active_merchant/lib/country.rb +297 -0
  51. data/lib/active_merchant/lib/posts_data.rb +21 -0
  52. data/lib/active_merchant/lib/requires_parameters.rb +17 -0
  53. data/lib/active_merchant/lib/validateable.rb +76 -0
  54. data/lib/tasks/cia.rb +90 -0
  55. metadata +129 -0
@@ -0,0 +1,21 @@
1
+ # With help from Giovanni Intini and his code for RGestPay - http://medlar.it/it/progetti/rgestpay
2
+
3
+ require File.dirname(__FILE__) + '/gestpay/common.rb'
4
+ require File.dirname(__FILE__) + '/gestpay/helper.rb'
5
+ require File.dirname(__FILE__) + '/gestpay/notification.rb'
6
+
7
+ module ActiveMerchant #:nodoc:
8
+ module Billing #:nodoc:
9
+ module Integrations #:nodoc:
10
+ module Gestpay
11
+
12
+ mattr_accessor :service_url
13
+ self.service_url = 'https://ecomm.sella.it/gestpay/pagam.asp'
14
+
15
+ def self.notification(post)
16
+ Notification.new(post)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,42 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module Gestpay
5
+ module Common
6
+ VERSION = "2.0"
7
+ ENCRYPTION_PATH = "/CryptHTTPS/Encrypt.asp"
8
+ DECRYPTION_PATH = "/CryptHTTPS/Decrypt.asp"
9
+ DELIMITER = '*P1*'
10
+
11
+ CURRENCY_MAPPING = {
12
+ 'EUR' => '242',
13
+ 'ITL' => '18',
14
+ 'BRL' => '234',
15
+ 'USD' => '1',
16
+ 'JPY' => '71',
17
+ 'HKD' => '103'
18
+ }
19
+
20
+ def parse_response(response)
21
+ case response
22
+ when /#cryptstring#(.*)#\/cryptstring#/, /#decryptstring#(.*)#\/decryptstring#/
23
+ $1
24
+ when /#error#(.*)#\/error#/
25
+ raise StandardError, "An error occurred retrieving the encrypted string from GestPay: #{$1}"
26
+ else
27
+ raise StandardError, "No response was received by GestPay"
28
+ end
29
+ end
30
+
31
+ def ssl_get(url, path)
32
+ uri = URI.parse(url)
33
+ site = Net::HTTP.new(uri.host, uri.port)
34
+ site.use_ssl = true
35
+ site.verify_mode = OpenSSL::SSL::VERIFY_NONE
36
+ site.get(path).body
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,72 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module Gestpay
5
+ class Helper < ActiveMerchant::Billing::Integrations::Helper
6
+ include Common
7
+ # Valid language codes
8
+ # Italian => 1
9
+ # English => 2
10
+ # Spanish => 3
11
+ # French => 4
12
+ # Tedesco => 5
13
+ def initialize(order, account, options = {})
14
+ super
15
+ add_field('PAY1_IDLANGUAGE', 2)
16
+ end
17
+
18
+ mapping :account, 'ShopLogin'
19
+
20
+ mapping :amount, 'PAY1_AMOUNT'
21
+ mapping :currency, 'PAY1_UICCODE'
22
+
23
+ mapping :order, 'PAY1_SHOPTRANSACTIONID'
24
+
25
+ # Buyer name PAY1_CHNAME
26
+ mapping :customer, :email => 'PAY1_CHEMAIL'
27
+
28
+ mapping :credit_card, :number => 'PAY1_CARDNUMBER',
29
+ :expiry_month => 'PAY1_EXPMONTH',
30
+ :expiry_year => 'PAY1_EXPYEAR',
31
+ :verification_value => 'PAY1_CVV'
32
+
33
+ mapping :billing_address, {}
34
+
35
+ def customer(params = {})
36
+ add_field(mappings[:customer][:email], params[:email])
37
+ add_field('PAY1_CHNAME', "#{params[:first_name]} #{params[:last_name]}")
38
+ end
39
+
40
+ def currency=(currency_code)
41
+ code = CURRENCY_MAPPING[currency_code]
42
+ raise StandardError, "Invalid currency code #{currency_code} specified" if code.nil?
43
+
44
+ add_field(mappings[:currency], code)
45
+ end
46
+
47
+ def form_fields
48
+ @encrypted_data ||= get_encrypted_string
49
+
50
+ {
51
+ 'a' => @fields['ShopLogin'],
52
+ 'b' => @encrypted_data
53
+ }
54
+ end
55
+
56
+ def get_encrypted_string
57
+ response = ssl_get(Gestpay.service_url, encryption_query_string)
58
+ parse_response(response)
59
+ end
60
+
61
+ def encryption_query_string
62
+ fields = ['PAY1_AMOUNT', 'PAY1_SHOPTRANSACTIONID', 'PAY1_UICCODE']
63
+
64
+ encoded_params = fields.collect{ |field| "#{field}=#{CGI.escape(@fields[field])}" }.join(DELIMITER)
65
+
66
+ "#{ENCRYPTION_PATH}?a=" + CGI.escape(@fields['ShopLogin']) + "&b=" + encoded_params + "&c=" + CGI.escape(VERSION)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,83 @@
1
+ require 'net/http'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ module Integrations #:nodoc:
6
+ module Gestpay
7
+ class Notification < ActiveMerchant::Billing::Integrations::Notification
8
+ include Common
9
+
10
+ def complete?
11
+ status == 'Completed'
12
+ end
13
+
14
+ # The important param
15
+ def item_id
16
+ params['PAY1_SHOPTRANSACTIONID']
17
+ end
18
+
19
+ def transaction_id
20
+ params['PAY1_BANKTRANSACTIONID']
21
+ end
22
+
23
+ # the money amount we received in X.2 decimal.
24
+ def gross
25
+ params['PAY1_AMOUNT']
26
+ end
27
+
28
+ def currency
29
+ CURRENCY_MAPPING.index(params['PAY1_UICCODE'])
30
+ end
31
+
32
+ def test?
33
+ false
34
+ end
35
+
36
+ def status
37
+ case params['PAY1_TRANSACTIONRESULT']
38
+ when 'OK'
39
+ 'Completed'
40
+ else
41
+ 'Failed'
42
+ end
43
+ end
44
+
45
+ def acknowledge
46
+ true
47
+ end
48
+
49
+ private
50
+ # Take the posted data and move the relevant data into a hash
51
+ def parse(query_string)
52
+ @raw = query_string
53
+
54
+ return if query_string.blank?
55
+ encrypted_params = parse_delimited_string(query_string)
56
+
57
+ return if encrypted_params['a'].blank? || encrypted_params['b'].blank?
58
+ @params = decrypt_data(encrypted_params['a'], encrypted_params['b'])
59
+ end
60
+
61
+ def parse_delimited_string(string, delimiter = '&', unencode_cgi = false)
62
+ result = {}
63
+ for line in string.split(delimiter)
64
+ key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
65
+ result[key] = unencode_cgi ? CGI.unescape(value) : value
66
+ end
67
+ result
68
+ end
69
+
70
+ def decrypt_data(shop_login, encrypted_string)
71
+ response = ssl_get(Gestpay.service_url, decryption_query_string(shop_login, encrypted_string))
72
+ encoded_response = parse_response(response)
73
+ parse_delimited_string(encoded_response, DELIMITER, true)
74
+ end
75
+
76
+ def decryption_query_string(shop_login, encrypted_string)
77
+ "#{DECRYPTION_PATH}?a=" + CGI.escape(shop_login) + "&b=" + encrypted_string + "&c=" + CGI.escape(VERSION)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,79 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ class Helper #:nodoc:
5
+ attr_reader :fields
6
+ class_inheritable_accessor :service_url
7
+ class_inheritable_hash :mappings
8
+ class_inheritable_accessor :country_format
9
+ self.country_format = :alpha2
10
+
11
+ def initialize(order, account, options = {})
12
+ valid_keys = [:amount, :currency]
13
+ options.assert_valid_keys(valid_keys)
14
+ @fields = {}
15
+ self.order = order
16
+ self.account = account
17
+ self.amount = options[:amount]
18
+ self.currency = options[:currency]
19
+ end
20
+
21
+ def self.mapping(attribute, options = {})
22
+ self.mappings ||= {}
23
+ self.mappings[attribute] = options
24
+ end
25
+
26
+ def add_field(name, value)
27
+ return if name.blank? || value.blank?
28
+ @fields[name.to_s] = value.to_s
29
+ end
30
+
31
+ def add_fields(subkey, params = {})
32
+ params.each do |k, v|
33
+ field = mappings[subkey][k]
34
+ add_field(field, v) unless field.blank?
35
+ end
36
+ end
37
+
38
+ def billing_address(params = {})
39
+ code = lookup_country_code(params.delete(:country))
40
+ add_field(mappings[:billing_address][:country], code) if mappings[:billing_address]
41
+ add_fields(:billing_address, params)
42
+ end
43
+
44
+ def form_fields
45
+ @fields
46
+ end
47
+
48
+ private
49
+
50
+ def lookup_country_code(name_or_code)
51
+ country = Country.find(name_or_code)
52
+ country.code(country_format).to_s
53
+ rescue InvalidCountryCodeError
54
+ name_or_code
55
+ end
56
+
57
+ def method_missing(method_id, *args)
58
+ method_id = method_id.to_s.gsub(/=$/, '').to_sym
59
+ # Return and do nothing if the mapping was not found. This allows
60
+ # For easy substitution of the different integrations
61
+ return if mappings[method_id].nil?
62
+
63
+ mapping = mappings[method_id]
64
+
65
+ case mapping
66
+ when Array
67
+ mapping.each{ |field| add_field(field, args.last) }
68
+ when Hash
69
+ options = args.last.is_a?(Hash) ? args.pop : {}
70
+
71
+ mapping.each{ |key, field| add_field(field, options[key]) }
72
+ else
73
+ add_field(mapping, args.last)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/nochex/helper.rb'
2
+ require File.dirname(__FILE__) + '/nochex/notification.rb'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ module Integrations #:nodoc:
7
+ module Nochex
8
+
9
+ mattr_accessor :service_url
10
+ self.service_url = 'https://www.nochex.com/nochex.dll/checkout'
11
+
12
+ mattr_accessor :notification_confirmation_url
13
+ self.notification_confirmation_url = 'https://www.nochex.com/nochex.dll/apc/apc'
14
+
15
+ def self.notification(post)
16
+ Notification.new(post)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,68 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module Nochex
5
+ class Helper < ActiveMerchant::Billing::Integrations::Helper
6
+ # Required Parameters
7
+ # email
8
+ # amount
9
+ mapping :account, 'email'
10
+ mapping :amount, 'amount'
11
+
12
+ # Set the field status = test for testing with accounts:
13
+ # Account Password
14
+ # test1@nochex.com 123456
15
+ # test2@nochex.com 123456
16
+ # def initialize(order, account, options = {})
17
+ # super
18
+ # add_field('status', 'test')
19
+ # end
20
+
21
+ # Need to format the amount to have 2 decimal places
22
+ def amount=(money)
23
+ cents = money.respond_to?(:cents) ? money.cents : money
24
+ if money.is_a?(String) or cents.to_i <= 0
25
+ raise ArgumentError, 'money amount must be either a Money object or a positive integer in cents.'
26
+ end
27
+ add_field mappings[:amount], sprintf("%.2f", cents.to_f/100)
28
+ end
29
+
30
+ # Optional Parameters
31
+ # ordernumber
32
+ mapping :order, 'ordernumber'
33
+
34
+ # firstname
35
+ # lastname
36
+ # email_address_sender
37
+ mapping :customer, :first_name => 'firstname',
38
+ :last_name => 'lastname',
39
+ :email => 'email_address_sender'
40
+
41
+ # town
42
+ # firstline
43
+ # county
44
+ # postcode
45
+ mapping :billing_address, :city => 'town',
46
+ :address1 => 'firstline',
47
+ :state => 'county',
48
+ :zip => 'postcode'
49
+
50
+ # responderurl
51
+ mapping :notify_url, 'responderurl'
52
+
53
+ # returnurl
54
+ mapping :return_url, 'returnurl'
55
+
56
+ # cancelurl
57
+ mapping :cancel_return_url, 'cancelurl'
58
+
59
+ # description
60
+ mapping :description, 'description'
61
+
62
+ # Currently unmapped
63
+ # logo
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,101 @@
1
+ require 'net/http'
2
+ require 'date'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ module Integrations #:nodoc:
7
+ module Nochex
8
+ # Parser and handler for incoming Automatic Payment Confirmations from Nochex.
9
+ class Notification < ActiveMerchant::Billing::Integrations::Notification
10
+ include ActiveMerchant::PostsData
11
+
12
+ def complete?
13
+ status == 'Completed'
14
+ end
15
+
16
+ # Id of the order we passed to Nochex
17
+ def item_id
18
+ params['order_id']
19
+ end
20
+
21
+ def transaction_id
22
+ params['transaction_id']
23
+ end
24
+
25
+ def currency
26
+ 'GBP'
27
+ end
28
+
29
+ # When was this payment received by the client.
30
+ def received_at
31
+ # U.K. Format: 27/09/2006 22:30:54
32
+ return if params['transaction_date'].blank?
33
+ time = params['transaction_date'].scan(/\d+/)
34
+ Time.utc(time[2], time[1], time[0], time[3], time[4], time[5])
35
+ end
36
+
37
+ def payer_email
38
+ params['from_email']
39
+ end
40
+
41
+ def receiver_email
42
+ params['to_email']
43
+ end
44
+
45
+ def security_key
46
+ params['security_key']
47
+ end
48
+
49
+ # the money amount we received in X.2 decimal.
50
+ def gross
51
+ params['amount']
52
+ end
53
+
54
+ # Was this a test transaction?
55
+ def test?
56
+ params['status'] == 'test'
57
+ end
58
+
59
+ def status
60
+ 'Completed'
61
+ end
62
+
63
+ # Acknowledge the transaction to Nochex. This method has to be called after a new
64
+ # apc arrives. Nochex will verify that all the information we received are correct and will return a
65
+ # ok or a fail. This is very similar to the PayPal IPN scheme.
66
+ #
67
+ # Example:
68
+ #
69
+ # def nochex_ipn
70
+ # notify = NochexNotification.new(request.raw_post)
71
+ #
72
+ # if notify.acknowledge
73
+ # ... process order ... if notify.complete?
74
+ # else
75
+ # ... log possible hacking attempt ...
76
+ # end
77
+ def acknowledge
78
+ payload = raw
79
+
80
+ uri = URI.parse(Nochex.notification_confirmation_url)
81
+
82
+ request = Net::HTTP::Post.new(uri.path)
83
+
84
+ request['Content-Length'] = "#{payload.size}"
85
+ request['User-Agent'] = "Active Merchant -- http://home.leetsoft.com/am"
86
+ request['Content-Type'] = "application/x-www-form-urlencoded"
87
+
88
+ http = Net::HTTP.new(uri.host, uri.port)
89
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @ssl_strict
90
+ http.use_ssl = true
91
+
92
+ response = http.request(request, payload)
93
+
94
+ raise StandardError.new("Faulty Nochex result: #{response.body}") unless ["AUTHORISED", "DECLINED"].include?(response.body)
95
+ response.body == "AUTHORISED"
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end