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,189 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+
4
+ class UsaEpayGateway < Gateway
5
+ GATEWAY_URL = 'https://www.usaepay.com/gate.php'
6
+
7
+ attr_reader :url
8
+ attr_reader :response
9
+ attr_reader :options
10
+
11
+ def initialize(options = {})
12
+ requires!(options, :login)
13
+ @options = options
14
+ super
15
+ end
16
+
17
+ def authorize(money, creditcard, options = {})
18
+ post = {}
19
+ add_invoice(post, options)
20
+ add_creditcard(post, creditcard)
21
+ add_address(post, creditcard, options)
22
+ add_customer_data(post, options)
23
+
24
+ commit('authonly', money, post)
25
+ end
26
+
27
+ def purchase(money, creditcard, options = {})
28
+ post = {}
29
+ add_invoice(post, options)
30
+ add_creditcard(post, creditcard)
31
+ add_address(post, creditcard, options)
32
+ add_customer_data(post, options)
33
+
34
+ commit('sale', money, post)
35
+ end
36
+
37
+ def capture(money, authorization, options = {})
38
+ post = {:refNum => authorization}
39
+ commit('capture', money, post)
40
+ end
41
+
42
+ def self.supported_cardtypes
43
+ [:visa, :master, :american_express]
44
+ end
45
+
46
+ private
47
+
48
+ def expdate(creditcard)
49
+ year = sprintf("%.4i", creditcard.year)
50
+ month = sprintf("%.2i", creditcard.month)
51
+
52
+ "#{year[-2..-1]}#{month}"
53
+ end
54
+
55
+ def add_customer_data(post, options)
56
+ address = options[:billing_address] || options[:address] || {}
57
+ post[:street] = address[:address1]
58
+ post[:zip] = address[:zip]
59
+
60
+ if options.has_key? :email
61
+ post[:custemail] = options[:email]
62
+ post[:custreceipt] = 'No'
63
+ end
64
+
65
+ if options.has_key? :customer
66
+ post[:custid] = options[:customer]
67
+ end
68
+
69
+ if options.has_key? :ip
70
+ post[:ip] = options[:ip]
71
+ end
72
+ end
73
+
74
+ def add_address(post, creditcard, options)
75
+ billing_address = options[:billing_address] || options[:address]
76
+ shipping_address = options[:shipping_address] || billing_address
77
+
78
+ add_address_for_type(:billing, post, creditcard, billing_address) unless billing_address.nil?
79
+ add_address_for_type(:shipping, post, creditcard, shipping_address) unless shipping_address.nil?
80
+ end
81
+
82
+ def add_address_for_type(type, post, creditcard, address)
83
+ prefix = address_key_prefix(type)
84
+
85
+ post[address_key(prefix, 'fname')] = creditcard.first_name
86
+ post[address_key(prefix, 'lname')] = creditcard.last_name
87
+ post[address_key(prefix, 'company')] = address[:company] unless address[:company].blank?
88
+ post[address_key(prefix, 'street')] = address[:address1] unless address[:address1].blank?
89
+ post[address_key(prefix, 'street2')] = address[:address2] unless address[:address2].blank?
90
+ post[address_key(prefix, 'city')] = address[:city] unless address[:city].blank?
91
+ post[address_key(prefix, 'state')] = address[:state] unless address[:state].blank?
92
+ post[address_key(prefix, 'zip')] = address[:zip] unless address[:zip].blank?
93
+ post[address_key(prefix, 'country')] = address[:country] unless address[:country].blank?
94
+ post[address_key(prefix, 'phone')] = address[:phone] unless address[:phone].blank?
95
+ end
96
+
97
+ def address_key_prefix(type)
98
+ case type
99
+ when :shipping then 'ship'
100
+ when :billing then 'bill'
101
+ end
102
+ end
103
+
104
+ def address_key(prefix, key)
105
+ "#{prefix}#{key}".to_sym
106
+ end
107
+
108
+ def add_invoice(post, options)
109
+ post[:invoice] = options[:order_id]
110
+ end
111
+
112
+ def add_creditcard(post, creditcard)
113
+ post[:card] = creditcard.number
114
+ post[:cvv2] = creditcard.verification_value if creditcard.verification_value?
115
+ post[:expir] = expdate(creditcard)
116
+ post[:name] = creditcard.name
117
+ end
118
+
119
+ def parse(body)
120
+ fields = {}
121
+ for line in body.split('&')
122
+ key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
123
+ fields[key] = CGI.unescape(value)
124
+ end
125
+
126
+ {
127
+ :status => fields['UMstatus'],
128
+ :auth_code => fields['UMauthCode'],
129
+ :ref_num => fields['UMrefNum'],
130
+ :batch => fields['UMbatch'],
131
+ :avs_result => fields['UMavsResult'],
132
+ :avs_result_code => fields['UMavsResultCode'],
133
+ :cvv2_result => fields['UMcvv2Result'],
134
+ :cvv2_result_code => fields['UMcvv2ResultCode'],
135
+ :vpas_result_code => fields['UMvpasResultCode'],
136
+ :result => fields['UMresult'],
137
+ :error => fields['UMerror'],
138
+ :error_code => fields['UMerrorcode'],
139
+ :acs_url => fields['UMacsurl'],
140
+ :payload => fields['UMpayload']
141
+ }.delete_if{|k, v| v.nil?}
142
+ end
143
+
144
+
145
+ def commit(action, money, parameters)
146
+ parameters[:software] = 'Active Merchant'
147
+ parameters[:amount] = amount(money)
148
+ parameters[:testmode] = test? ? 1 : 0
149
+
150
+ if result = test_result_from_cc_number(parameters[:card])
151
+ return result
152
+ end
153
+
154
+ data = ssl_post GATEWAY_URL,
155
+ post_data(action, parameters),
156
+ { 'Content-Type' => 'application/x-www-form-urlencoded' }
157
+
158
+ @response = parse(data)
159
+ success = @response[:status] == 'Approved'
160
+ message = message_from(@response)
161
+
162
+ Response.new(success, message, @response,
163
+ :test => test?,
164
+ :authorization => @response[:ref_num]
165
+ )
166
+ end
167
+
168
+ def message_from(response)
169
+ if response[:status] == "Approved"
170
+ return 'Success'
171
+ else
172
+ return 'Unspecified error' if response[:error].blank?
173
+ return response[:error]
174
+ end
175
+ end
176
+
177
+ def post_data(action, parameters = {})
178
+ post = {}
179
+
180
+ post[:command] = action
181
+ post[:key] = @options[:login]
182
+
183
+ request = post.merge(parameters).collect { |key, value| "UM#{key}=#{CGI.escape(value.to_s)}" }.join("&")
184
+ request
185
+ end
186
+ end
187
+ end
188
+ end
189
+
@@ -0,0 +1,12 @@
1
+ require 'active_merchant/billing/integrations/notification'
2
+ require 'active_merchant/billing/integrations/helper'
3
+ require 'active_merchant/billing/integrations/bogus'
4
+ require 'active_merchant/billing/integrations/chronopay'
5
+ require 'active_merchant/billing/integrations/paypal'
6
+ require 'active_merchant/billing/integrations/nochex'
7
+ require 'active_merchant/billing/integrations/gestpay'
8
+
9
+ # make the bogus gateway be classified correctly by the inflector
10
+ Inflector.inflections do |inflect|
11
+ inflect.uncountable 'bogus'
12
+ end
@@ -0,0 +1,65 @@
1
+ require_library_or_gem 'action_pack'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ module Integrations #:nodoc:
6
+ module ActionViewHelper
7
+ # This helper allows the usage of different payment integrations
8
+ # through a single form helper. Payment integrations are the
9
+ # type of service where the user is redirected to the secure
10
+ # site of the service, like Paypal or Chronopay.
11
+ #
12
+ # The helper creates a scope around a payment service helper
13
+ # which provides the specific mapping for that service.
14
+ #
15
+ # <% payment_service_for 1000, 'paypalemail@mystore.com',
16
+ # :amount => 50.00,
17
+ # :currency => 'CAD',
18
+ # :service => :paypal,
19
+ # :html => { :id => 'payment-form' } do |service| %>
20
+ #
21
+ # <% service.customer :first_name => 'Cody',
22
+ # :last_name => 'Fauser',
23
+ # :phone => '(555)555-5555',
24
+ # :email => 'codyfauser@gmail.com' %>
25
+ #
26
+ # <% service.billing_address :city => 'Ottawa',
27
+ # :address1 => '21 Snowy Brook Lane',
28
+ # :address2 => 'Apt. 36',
29
+ # :state => 'ON',
30
+ # :country => 'CA',
31
+ # :zip => 'K1J1E5' %>
32
+ #
33
+ # <% service.invoice '#1000' %>
34
+ # <% service.shipping '0.00' %>
35
+ # <% service.tax '0.00' %>
36
+ #
37
+ # <% service.notify_url url_for(:only_path => false, :action => 'notify') %>
38
+ # <% service.return_url url_for(:only_path => false, :action => 'done') %>
39
+ # <% service.cancel_return_url 'http://mystore.com' %>
40
+ # <% end %>
41
+ #
42
+ def payment_service_for(order, account, options = {}, &proc)
43
+ raise ArgumentError, "Missing block" unless block_given?
44
+
45
+ integration_module = ActiveMerchant::Billing::Integrations.const_get(Inflector.classify("#{options.delete(:service)}"))
46
+
47
+ concat(form_tag(integration_module.service_url, options.delete(:html) || {}), proc.binding)
48
+ result = "\n"
49
+
50
+ service_class = integration_module.const_get('Helper')
51
+ service = service_class.new(order, account, options)
52
+ yield service
53
+
54
+ result << service.form_fields.collect do |field, value|
55
+ hidden_field_tag(field, value)
56
+ end.join("\n")
57
+
58
+ result << "\n"
59
+ result << '</form>'
60
+ concat(result, proc.binding)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,17 @@
1
+ require 'active_merchant/billing/integrations/bogus/helper.rb'
2
+ require 'active_merchant/billing/integrations/bogus/notification.rb'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ module Integrations #:nodoc:
7
+ module Bogus
8
+ mattr_accessor :service_url
9
+ self.service_url = 'http://www.bogus.com'
10
+
11
+ def self.notification(post)
12
+ Notification.new(post)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module Bogus
5
+ class Helper < ActiveMerchant::Billing::Integrations::Helper
6
+ mapping :account, 'account'
7
+ mapping :order, 'order'
8
+ mapping :amount, 'amount'
9
+ mapping :currency, 'currency'
10
+ mapping :customer, :first_name => 'first_name',
11
+ :last_name => 'last_name'
12
+
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module Bogus
5
+ class Notification < ActiveMerchant::Billing::Integrations::Notification
6
+
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ require 'active_merchant/billing/integrations/chronopay/helper.rb'
2
+ require 'active_merchant/billing/integrations/chronopay/notification.rb'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ module Integrations #:nodoc:
7
+ module Chronopay
8
+ mattr_accessor :service_url
9
+ self.service_url = 'https://secure.chronopay.com/index_shop.cgi'
10
+
11
+ def self.notification(post)
12
+ Notification.new(post)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,81 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module Chronopay
5
+ class Helper < ActiveMerchant::Billing::Integrations::Helper
6
+ self.country_format = :alpha3
7
+
8
+ def initialize(order, account, options = {})
9
+ super
10
+ add_field('cb_type', 'p')
11
+ add_field('language', 'EN')
12
+ end
13
+
14
+ # product_id
15
+ mapping :account, 'product_id'
16
+ # product_name
17
+ mapping :invoice, 'product_name'
18
+ # product_price
19
+ mapping :amount, 'product_price'
20
+ # product_price_currency
21
+ mapping :currency, 'product_price_currency'
22
+
23
+ # f_name
24
+ # s_name
25
+ # email
26
+ mapping :customer, :first_name => 'f_name',
27
+ :last_name => 's_name',
28
+ :phone => 'phone',
29
+ :email => 'email'
30
+
31
+ # city
32
+ # street
33
+ # state
34
+ # zip
35
+ # country - The country must be a 3 digit country code
36
+ # phone
37
+
38
+ mapping :billing_address, :city => 'city',
39
+ :address1 => 'street',
40
+ :state => 'state',
41
+ :zip => 'zip',
42
+ :country => 'country'
43
+
44
+ def billing_address(mapping = {})
45
+ # Gets the country code in the appropriate format or returns what we were given
46
+ # The appropriate format for Chronopay is the alpha 3 country code
47
+ country_code = lookup_country_code(mapping.delete(:country))
48
+ add_field(mappings[:billing_address][:country], country_code)
49
+
50
+ countries_with_supported_states = ['USA', 'CAN']
51
+ if !countries_with_supported_states.include?(country_code)
52
+ mapping.delete(:state)
53
+ add_field(mappings[:billing_address][:state], 'XX')
54
+ end
55
+ mapping.each do |k, v|
56
+ field = mappings[:billing_address][k]
57
+ add_field(field, v) unless field.nil?
58
+ end
59
+ end
60
+
61
+ # card_no
62
+ # exp_month
63
+ # exp_year
64
+ mapping :credit_card, :number => 'card_no',
65
+ :expiry_month => 'exp_month',
66
+ :expiry_year => 'exp_year'
67
+
68
+ # cb_url
69
+ mapping :notify_url, 'cb_url'
70
+
71
+ # cs1
72
+ mapping :order, 'cs1'
73
+
74
+ # cs2
75
+ # cs3
76
+ # decline_url
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,156 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module Chronopay
5
+ class Notification < ActiveMerchant::Billing::Integrations::Notification
6
+ def complete?
7
+ status == 'Completed'
8
+ end
9
+
10
+ # Status of transaction. List of possible values:
11
+ # <tt>onetime – one time payment has been made, no repayment required;</tt>::
12
+ # <tt>initial – first payment has been made, repayment required in corresponding period;</tt>::
13
+ # <tt>decline – charge request has been rejected;</tt>::
14
+ # <tt>rebill – repayment has been made together with initial transaction;</ttt>::
15
+ # <tt>cancel – repayments has been disabled;</tt>::
16
+ # <tt>expire – customer’s access to restricted zone membership has been expired;</tt>::
17
+ # <tt>refund – request to refund has been received;</tt>::
18
+ # <tt>chargeback – request to chargeback has been received.</tt>::
19
+ #
20
+ # This implementation of Chronopay does not support subscriptions.
21
+ # The status codes used are matched to the status codes that Paypal
22
+ # sends. See Paypal::Notification#status for more details
23
+ def status
24
+ case params['transaction_type']
25
+ when 'onetime'
26
+ 'Completed'
27
+ when 'refund'
28
+ 'Refunded'
29
+ when 'chargeback'
30
+ 'Reversed'
31
+ else
32
+ 'Failed'
33
+ end
34
+ end
35
+
36
+ # Unique ID of transaction
37
+ def transaction_id
38
+ params['transaction_id']
39
+ end
40
+
41
+ # Unique ID of customer
42
+ def customer_id
43
+ params['customer_id']
44
+ end
45
+
46
+ # Unique ID of Merchant’s web-site
47
+ def site_id
48
+ params['site_id']
49
+ end
50
+
51
+ # ID of a product that was purchased
52
+ def product_id
53
+ params['product_id']
54
+ end
55
+
56
+ # Language
57
+ def language
58
+ params['language']
59
+ end
60
+
61
+ def received_at
62
+ Time.parse("#{date} #{time}") unless date.blank? || time.blank?
63
+ end
64
+
65
+ # Date of transaction in MM/DD/YYYY format
66
+ def date
67
+ params['date']
68
+ end
69
+
70
+ # Time of transaction in HH:MM:SS format
71
+ def time
72
+ params['time']
73
+ end
74
+
75
+ # The customer's full name
76
+ def name
77
+ params['name']
78
+ end
79
+
80
+ # The customer's email address
81
+ def email
82
+ params['email']
83
+ end
84
+
85
+ # The customer's street address
86
+ def street
87
+ params['street']
88
+ end
89
+
90
+ # The customer's country - 3 digit country code
91
+ def country
92
+ params['country']
93
+ end
94
+
95
+ # The customer's city
96
+ def city
97
+ params['city']
98
+ end
99
+
100
+ # The customer's zip
101
+ def zip
102
+ params['zip']
103
+ end
104
+
105
+ # The customer's state. Only useful for US Customers
106
+ def state
107
+ params['state']
108
+ end
109
+
110
+ # Customer’s login for restricted access zone of Merchant’s Web-site
111
+ def username
112
+ params['username']
113
+ end
114
+
115
+ # Customer's password for restricted access zone of Merchant’s Web-site, as chosen
116
+ def password
117
+ params['password']
118
+ end
119
+
120
+ # The item id passed in the first custom parameter
121
+ def item_id
122
+ params['cs1']
123
+ end
124
+
125
+ # Additional parameter
126
+ def custom2
127
+ params['cs2']
128
+ end
129
+
130
+ # Additional parameter
131
+ def custom3
132
+ params['cs3']
133
+ end
134
+
135
+ # The currency the purchase was made in
136
+ def currency
137
+ params['currency']
138
+ end
139
+
140
+ # the money amount we received in X.2 decimal.
141
+ def gross
142
+ params['total']
143
+ end
144
+
145
+ def test?
146
+ date.blank? && time.blank? && transaction_id.blank?
147
+ end
148
+
149
+ def acknowledge
150
+ true
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end