activemerchant 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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