activemerchant 1.8.0 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +9 -0
  3. data/CONTRIBUTORS +21 -1
  4. data/README.rdoc +16 -4
  5. data/lib/active_merchant.rb +2 -0
  6. data/lib/active_merchant/billing/gateways/inspire.rb +221 -0
  7. data/lib/active_merchant/billing/gateways/paybox_direct.rb +205 -0
  8. data/lib/active_merchant/billing/gateways/secure_net.rb +330 -0
  9. data/lib/active_merchant/billing/integrations/bogus.rb +1 -1
  10. data/lib/active_merchant/billing/integrations/chronopay.rb +1 -1
  11. data/lib/active_merchant/billing/integrations/direc_pay.rb +37 -0
  12. data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +188 -0
  13. data/lib/active_merchant/billing/integrations/direc_pay/notification.rb +76 -0
  14. data/lib/active_merchant/billing/integrations/direc_pay/return.rb +32 -0
  15. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +37 -0
  16. data/lib/active_merchant/billing/integrations/gestpay.rb +1 -1
  17. data/lib/active_merchant/billing/integrations/helper.rb +8 -5
  18. data/lib/active_merchant/billing/integrations/hi_trust.rb +1 -1
  19. data/lib/active_merchant/billing/integrations/nochex.rb +1 -1
  20. data/lib/active_merchant/billing/integrations/paypal.rb +1 -1
  21. data/lib/active_merchant/billing/integrations/return.rb +4 -2
  22. data/lib/active_merchant/billing/integrations/sage_pay_form.rb +37 -0
  23. data/lib/active_merchant/billing/integrations/sage_pay_form/encryption.rb +33 -0
  24. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +109 -0
  25. data/lib/active_merchant/billing/integrations/sage_pay_form/notification.rb +204 -0
  26. data/lib/active_merchant/billing/integrations/sage_pay_form/return.rb +27 -0
  27. data/lib/active_merchant/billing/integrations/two_checkout.rb +1 -1
  28. data/lib/active_merchant/version.rb +1 -1
  29. metadata +17 -4
  30. metadata.gz.sig +0 -0
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,5 +1,14 @@
1
1
  = ActiveMerchant CHANGELOG
2
2
 
3
+ == Version 1.9.0 (October 14, 2010)
4
+
5
+ * Add support for DirecPay gateway [Soleone]
6
+ * Add SagePay Form integration gateway [Adrian Irving-Beer]
7
+ * Allow Return class to include a Notification for gateways that treat the direct response as a notification [Adrian Irving-Beer]
8
+ * Add support for PayboxDirect gateway [Donald Piret]
9
+ * Add support for SecureNet gateway [Kal]
10
+ * Add support for the Inspire gateway [ryan r. smith]
11
+
3
12
  == Version 1.8.0 (September 24, 2010)
4
13
 
5
14
  * PayPal Express: Add support for billing agreements [Nathaniel Talbott]
@@ -147,4 +147,24 @@ Garanti (May 05, 2010)
147
147
 
148
148
  Braintree Blue Gateway (May 19th, 2010)
149
149
 
150
- * Braintree (code@getbraintree.com)
150
+ * Braintree (code@getbraintree.com)
151
+
152
+ Inspire Gateway (September 27, 2010)
153
+
154
+ * ryan r. smith
155
+
156
+ SecureNet Gateway (September 27, 2010)
157
+
158
+ * Kal
159
+
160
+ PayboxDirect Gateway (September 27, 2010)
161
+
162
+ * Donald Piret <donald@donaldpiret.com>
163
+
164
+ SagePay Form Offsite Gateway (October 14, 2010)
165
+
166
+ * Adrian Irving-Beer
167
+
168
+ DirecPay Gateway (October 14, 2010)
169
+
170
+ * Soleone
@@ -19,17 +19,26 @@ The {ActiveMerchant Wiki}[http://github.com/Shopify/active_merchant/wikis] conta
19
19
  * {CyberSource}[http://www.cybersource.com] - US
20
20
  * {DataCash}[http://www.datacash.com/] - GB
21
21
  * {Efsnet}[http://www.concordefsnet.com/] - US
22
+ * {Elavon MyVirtualMerchant}[http://www.elavon.com] - US, CA
22
23
  * {eWAY}[http://www.eway.com.au/] - AU
23
24
  * {E-xact}[http://www.e-xact.com] - CA, US
25
+ * {FirstPay}[http://www.first-pay.com] - US
26
+ * {Garanti Sanal POS}[https://ccpos.garanti.com.tr/ccRaporlar/garanti/ccReports] - US, TR
27
+ * {Inspire}[http://www.inspiregateway.com] - US
28
+ * {InstaPay}[http://www.instapayllc.com] - US
24
29
  * {Iridium}[http://www.iridiumcorp.co.uk/] - UK, ES
30
+ * {JetPay}[http://www.jetpay.com] - US
25
31
  * {LinkPoint}[http://www.linkpoint.com/] - US
26
32
  * {Merchant e-Solutions}[http://merchante-solutions.com/] - US
33
+ * {MerchantWare}[http://merchantwarehouse.com/merchantware] - US
27
34
  * {Modern Payments}[http://www.modpay.com] - US
28
35
  * {Moneris}[http://www.moneris.com/] - CA
29
36
  * {Netaxept}[http://www.betalingsterminal.no/Netthandel-forside] - NO, DK, SE, FI
30
37
  * {NetRegistry}[http://www.netregistry.com.au] - AU
31
38
  * {NELiX TransaX Gateway}[http://www.nelixtransax.com] - US
32
39
  * {NETbilling}[http://www.netbilling.com] - US
40
+ * {Ogone DirectLink}[http://www.ogone.com] - BE, DE, FR, NL, AT, CH
41
+ * {PayBox Direct}[http://www.paybox.com] - FR
33
42
  * {PayJunction}[http://www.payjunction.com/] - US
34
43
  * {PaySecure}[http://www.commsecure.com.au/paysecure.shtml] - AU
35
44
  * {PayPal Express Checkout}[https://www.paypal.com/cgi-bin/webscr?cmd=xpt/merchant/ExpressCheckoutIntro-outside] - US, CA, SG, AU
@@ -47,6 +56,7 @@ The {ActiveMerchant Wiki}[http://github.com/Shopify/active_merchant/wikis] conta
47
56
  * {Realex}[http://www.realexpayments.com/] - IE, GB
48
57
  * {Sage Payment Solutions}[http://www.sagepayments.com] - US, CA
49
58
  * {Sallie Mae}[http://www.salliemae.com] - US
59
+ * {SecureNet}[http://www.securenet.com] - US
50
60
  * {SecurePay}[http://securepay.com.au] - AU
51
61
  * {SecurePay}[http://www.securepay.com/] - US
52
62
  * {SecurePayTech}[http://www.securepaytech.com/] - NZ
@@ -60,12 +70,14 @@ The {ActiveMerchant Wiki}[http://github.com/Shopify/active_merchant/wikis] conta
60
70
 
61
71
  == Supported Offsite Payment Gateways
62
72
 
63
- * {PayPal Website Payments Standard}[https://www.paypal.com/cgi-bin/webscr?cmd=_wp-standard-overview-outside]
64
- * {Chronopay}[http://www.chronopay.com]
65
- * {Nochex}[http://www.nochex.com]
66
- * {Banca Sella GestPay}[https://www.sella.it/banca/ecommerce/gestpay/gestpay.jsp]
67
73
  * {2 Checkout}[http://www.2checkout.com]
74
+ * {Banca Sella GestPay}[https://www.sella.it/banca/ecommerce/gestpay/gestpay.jsp]
75
+ * {Chronopay}[http://www.chronopay.com]
76
+ * {DirecPay}[http://www.timesofmoney.com/direcpay/jsp/home.jsp]
68
77
  * {HiTRUST}[http://www.hitrust.com.hk/]
78
+ * {Nochex}[http://www.nochex.com]
79
+ * {PayPal Website Payments Standard}[https://www.paypal.com/cgi-bin/webscr?cmd=_wp-standard-overview-outside]
80
+ * {SagePay Form}[http://www.sagepay.com/products_services/sage_pay_go/integration/form]
69
81
 
70
82
  == Download
71
83
 
@@ -31,6 +31,8 @@ require 'active_support/core_ext/class/attribute_accessors'
31
31
  require 'active_support/core_ext/class/delegating_attributes'
32
32
  require 'active_support/core_ext/module/attribute_accessors'
33
33
  require 'active_support/core_ext/kernel/requires'
34
+ require 'active_support/base64'
35
+ require 'active_support/secure_random'
34
36
 
35
37
  require 'builder'
36
38
  require 'cgi'
@@ -0,0 +1,221 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'check.rb')
2
+ module ActiveMerchant #:nodoc:
3
+ module Billing #:nodoc:
4
+ class InspireGateway < Gateway
5
+ URL = 'https://secure.inspiregateway.net/api/transact.php'
6
+
7
+ self.supported_countries = ['US']
8
+ self.supported_cardtypes = [:visa, :master, :american_express]
9
+ self.homepage_url = 'http://www.inspiregateway.com'
10
+ self.display_name = 'Inspire Commerce'
11
+ # Creates a new InspireGateway
12
+ #
13
+ # The gateway requires that a valid login and password be passed
14
+ # in the +options+ hash.
15
+ #
16
+ # ==== Options
17
+ #
18
+ # * <tt>:login</tt> -- The Inspire Username.
19
+ # * <tt>:password</tt> -- The Inspire Passowrd.
20
+ # See the Inspire Integration Guide for details. (default: +false+)
21
+ def initialize(options = {})
22
+ requires!(options, :login, :password)
23
+ @options = options
24
+ super
25
+ end
26
+
27
+ # Pass :store => true in the options to store the
28
+ # payment info at Inspire Gateway and get a generated
29
+ # customer_vault_id in the response.
30
+ # Pass :store => some_number_or_string to specify the
31
+ # customer_vault_id InspireGateway should use (make sure it's
32
+ # unique).
33
+ def authorize(money, creditcard, options = {})
34
+ post = {}
35
+ add_invoice(post, options)
36
+ add_payment_source(post, creditcard,options)
37
+ add_address(post, creditcard, options)
38
+ add_customer_data(post, options)
39
+
40
+ commit('auth', money, post)
41
+ end
42
+
43
+ def purchase(money, payment_source, options = {})
44
+ post = {}
45
+ add_invoice(post, options)
46
+ add_payment_source(post, payment_source, options)
47
+ add_address(post, payment_source, options)
48
+ add_customer_data(post, options)
49
+
50
+ commit('sale', money, post)
51
+ end
52
+
53
+ def capture(money, authorization, options = {})
54
+ post ={}
55
+ post[:transactionid] = authorization
56
+ commit('capture', money, post)
57
+ end
58
+
59
+ def void(authorization, options = {})
60
+ post ={}
61
+ post[:transactionid] = authorization
62
+ commit('void', nil, post)
63
+ end
64
+
65
+ # Update the values (such as CC expiration) stored at
66
+ # InspireGateway. The CC number must be supplied in the
67
+ # CreditCard object.
68
+ def update(vault_id, creditcard, options = {})
69
+ post = {}
70
+ post[:customer_vault] = "update_customer"
71
+ add_customer_vault_id(post, vault_id)
72
+ add_creditcard(post, creditcard, options)
73
+ add_address(post, creditcard, options)
74
+ add_customer_data(post, options)
75
+
76
+ commit(nil, nil, post)
77
+ end
78
+
79
+ def delete(vault_id)
80
+ post = {}
81
+ post[:customer_vault] = "delete_customer"
82
+ add_customer_vault_id(post, vault_id)
83
+ commit(nil, nil, post)
84
+ end
85
+
86
+ # To match the other stored-value gateways, like TrustCommerce,
87
+ # store and unstore need to be defined
88
+ def store(creditcard, options = {})
89
+ billing_id = options.delete(:billing_id).to_s || true
90
+ authorize(100, creditcard, options.merge(:store => billing_id))
91
+ end
92
+
93
+ alias_method :unstore, :delete
94
+
95
+ private
96
+ def add_customer_data(post, options)
97
+ if options.has_key? :email
98
+ post[:email] = options[:email]
99
+ end
100
+
101
+ if options.has_key? :ip
102
+ post[:ipaddress] = options[:ip]
103
+ end
104
+ end
105
+
106
+ def add_address(post, creditcard, options)
107
+ if address = options[:billing_address] || options[:address]
108
+ post[:address1] = address[:address1].to_s
109
+ post[:address2] = address[:address2].to_s unless address[:address2].blank?
110
+ post[:company] = address[:company].to_s
111
+ post[:phone] = address[:phone].to_s
112
+ post[:zip] = address[:zip].to_s
113
+ post[:city] = address[:city].to_s
114
+ post[:country] = address[:country].to_s
115
+ post[:state] = address[:state].blank? ? 'n/a' : address[:state]
116
+ end
117
+ end
118
+
119
+ def add_invoice(post, options)
120
+ post[:orderid] = options[:order_id].to_s.gsub(/[^\w.]/, '')
121
+ post[:orderdescription] = options[:description]
122
+ end
123
+
124
+ def add_payment_source(params, source, options={})
125
+ case determine_funding_source(source)
126
+ when :vault then add_customer_vault_id(params, source)
127
+ when :credit_card then add_creditcard(params, source, options)
128
+ when :check then add_check(params, source)
129
+ end
130
+ end
131
+
132
+ def add_customer_vault_id(params,vault_id)
133
+ params[:customer_vault_id] = vault_id
134
+ end
135
+
136
+ def add_creditcard(post, creditcard,options)
137
+ if options[:store]
138
+ post[:customer_vault] = "add_customer"
139
+ post[:customer_vault_id] = options[:store] unless options[:store] == true
140
+ end
141
+ post[:ccnumber] = creditcard.number
142
+ post[:cvv] = creditcard.verification_value if creditcard.verification_value?
143
+ post[:ccexp] = expdate(creditcard)
144
+ post[:firstname] = creditcard.first_name
145
+ post[:lastname] = creditcard.last_name
146
+ end
147
+
148
+ def add_check(post, check)
149
+ post[:payment] = 'check' # Set transaction to ACH
150
+ post[:checkname] = check.name # The name on the customer's Checking Account
151
+ post[:checkaba] = check.routing_number # The customer's bank routing number
152
+ post[:checkaccount] = check.account_number # The customer's account number
153
+ post[:account_holder_type] = check.account_holder_type # The customer's type of ACH account
154
+ post[:account_type] = check.account_type # The customer's type of ACH account
155
+ end
156
+
157
+ def parse(body)
158
+ results = {}
159
+ body.split(/&/).each do |pair|
160
+ key,val = pair.split(/=/)
161
+ results[key] = val
162
+ end
163
+
164
+ results
165
+ end
166
+
167
+ def commit(action, money, parameters)
168
+ parameters[:amount] = amount(money) if money
169
+
170
+ response = parse( ssl_post(URL, post_data(action,parameters)) )
171
+
172
+ Response.new(response["response"] == "1", message_from(response), response,
173
+ :authorization => response["transactionid"],
174
+ :test => test?,
175
+ :cvv_result => response["cvvresponse"],
176
+ :avs_result => { :code => response["avsresponse"] }
177
+ )
178
+
179
+ end
180
+
181
+ def expdate(creditcard)
182
+ year = sprintf("%.4i", creditcard.year)
183
+ month = sprintf("%.2i", creditcard.month)
184
+
185
+ "#{month}#{year[-2..-1]}"
186
+ end
187
+
188
+
189
+ def message_from(response)
190
+ case response["responsetext"]
191
+ when "SUCCESS","Approved"
192
+ "This transaction has been approved"
193
+ when "DECLINE"
194
+ "This transaction has been declined"
195
+ else
196
+ response["responsetext"]
197
+ end
198
+ end
199
+
200
+ def post_data(action, parameters = {})
201
+ post = {}
202
+ post[:username] = @options[:login]
203
+ post[:password] = @options[:password]
204
+ post[:type] = action if action
205
+
206
+ request = post.merge(parameters).map {|key,value| "#{key}=#{CGI.escape(value.to_s)}"}.join("&")
207
+ request
208
+ end
209
+
210
+ def determine_funding_source(source)
211
+ case
212
+ when source.is_a?(String) then :vault
213
+ when CreditCard.card_companies.keys.include?(card_brand(source)) then :credit_card
214
+ when card_brand(source) == 'check' then :check
215
+ else raise ArgumentError, "Unsupported funding source provided"
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
221
+
@@ -0,0 +1,205 @@
1
+ require 'iconv'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class PayboxDirectGateway < Gateway
6
+ TEST_URL = 'https://ppps.paybox.com/PPPS.php'
7
+ TEST_URL_BACKUP = 'https://ppps1.paybox.com/PPPS.php'
8
+ LIVE_URL = 'https://ppps.paybox.com/PPPS.php'
9
+ LIVE_URL_BACKUP = 'https://ppps1.paybox.com/PPPS.php'
10
+
11
+ # Payment API Version
12
+ API_VERSION = '00104'
13
+
14
+ # Transactions hash
15
+ TRANSACTIONS = {
16
+ :authorization => '00001',
17
+ :capture => '00002',
18
+ :purchase => '00003',
19
+ :unreferenced_credit => '00004',
20
+ :void => '00005',
21
+ :refund => '00014'
22
+ }
23
+
24
+ CURRENCY_CODES = {
25
+ "AUD"=> '036',
26
+ "CAD"=> '124',
27
+ "CZK"=> '203',
28
+ "DKK"=> '208',
29
+ "HKD"=> '344',
30
+ "ICK"=> '352',
31
+ "JPY"=> '392',
32
+ "NOK"=> '578',
33
+ "SGD"=> '702',
34
+ "SEK"=> '752',
35
+ "CHF"=> '756',
36
+ "GBP"=> '826',
37
+ "USD"=> '840',
38
+ "EUR"=> '978'
39
+ }
40
+
41
+ SUCCESS_CODES = ['00000']
42
+ UNAVAILABILITY_CODES = ['00001', '00097', '00098']
43
+ FRAUD_CODES = ['00102','00104','00105','00134','00138','00141','00143','00156','00157','00159']
44
+ SUCCESS_MESSAGE = 'The transaction was approved'
45
+ FAILURE_MESSAGE = 'The transaction failed'
46
+
47
+ # Money is referenced in cents
48
+ self.money_format = :cents
49
+ self.default_currency = 'EUR'
50
+
51
+ # The countries the gateway supports merchants from as 2 digit ISO country codes
52
+ self.supported_countries = ['FR']
53
+
54
+ # The card types supported by the payment gateway
55
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :jcb]
56
+
57
+ # The homepage URL of the gateway
58
+ self.homepage_url = 'http://www.paybox.com/'
59
+
60
+ # The name of the gateway
61
+ self.display_name = 'Paybox Direct'
62
+
63
+ def initialize(options = {})
64
+ requires!(options, :login, :password)
65
+ @options = options
66
+ super
67
+ end
68
+
69
+ def authorize(money, creditcard, options = {})
70
+ post = {}
71
+ add_invoice(post, options)
72
+ add_creditcard(post, creditcard)
73
+ commit('authorization', money, post)
74
+ end
75
+
76
+ def purchase(money, creditcard, options = {})
77
+ post = {}
78
+ add_invoice(post, options)
79
+ add_creditcard(post, creditcard)
80
+ commit('purchase', money, post)
81
+ end
82
+
83
+ def capture(money, authorization, options = {})
84
+ requires!(options, :order_id)
85
+ post = {}
86
+ add_invoice(post, options)
87
+ post[:numappel] = authorization[0,10]
88
+ post[:numtrans] = authorization[10,10]
89
+ commit('capture', money, post)
90
+ end
91
+
92
+ def void(identification, options = {})
93
+ requires!(options, :order_id, :amount)
94
+ post ={}
95
+ add_invoice(post, options)
96
+ add_reference(post, identification)
97
+ post[:porteur] = '000000000000000'
98
+ post[:dateval] = '0000'
99
+ commit('void', options[:amount], post)
100
+ end
101
+
102
+ def credit(money, identification, options = {})
103
+ post = {}
104
+ add_invoice(post, options)
105
+ add_reference(post, identification)
106
+ commit('refund', money, post)
107
+ end
108
+
109
+ def test?
110
+ @options[:test] || Base.gateway_mode == :test
111
+ end
112
+
113
+ private
114
+
115
+ def add_invoice(post, options)
116
+ post[:reference] = options[:order_id]
117
+ end
118
+
119
+ def add_creditcard(post, creditcard)
120
+ post[:porteur] = creditcard.number
121
+ post[:dateval] = expdate(creditcard)
122
+ post[:cvv] = creditcard.verification_value if creditcard.verification_value?
123
+ end
124
+
125
+ def add_reference(post, identification)
126
+ post[:numappel] = identification[0,10]
127
+ post[:numtrans] = identification[10,10]
128
+ end
129
+
130
+ def parse(body)
131
+ body = Iconv.iconv("UTF-8","LATIN1", body.to_s).join
132
+ results = {}
133
+ body.split(/&/).each do |pair|
134
+ key,val = pair.split(/\=/)
135
+ results[key.downcase.to_sym] = CGI.unescape(val) if val
136
+ end
137
+ results
138
+ end
139
+
140
+ def commit(action, money = nil, parameters = nil)
141
+ parameters[:montant] = ('0000000000' + (money ? amount(money) : ''))[-10..-1]
142
+ parameters[:devise] = CURRENCY_CODES[options[:currency] || currency(money)]
143
+ request_data = post_data(action,parameters)
144
+ response = parse(ssl_post(test? ? TEST_URL : LIVE_URL, request_data))
145
+ response = parse(ssl_post(test? ? TEST_URL_BACKUP : LIVE_URL_BACKUP, request_data)) if service_unavailable?(response)
146
+ Response.new(success?(response), message_from(response), response.merge(
147
+ :timestamp => parameters[:dateq]),
148
+ :test => test?,
149
+ :authorization => response[:numappel].to_s + response[:numtrans].to_s,
150
+ :cvv_result => '',
151
+ :avs_result => '',
152
+ :fraud_review => fraud_review?(response),
153
+ :sent_params => parameters.delete_if{|key,value| ['porteur','dateval','cvv'].include?(key.to_s)}
154
+ )
155
+ end
156
+
157
+ def success?(response)
158
+ SUCCESS_CODES.include?(response[:codereponse])
159
+ end
160
+
161
+ def fraud_review?(response)
162
+ FRAUD_CODES.include?(response[:codereponse])
163
+ end
164
+
165
+ def service_unavailable?(response)
166
+ UNAVAILABILITY_CODES.include?(response[:codereponse])
167
+ end
168
+
169
+ def message_from(response)
170
+ success?(response) ? SUCCESS_MESSAGE : (response[:commentaire] || FAILURE_MESSAGE)
171
+ end
172
+
173
+ def post_data(action, parameters = {})
174
+
175
+ parameters.update(
176
+ :version => API_VERSION,
177
+ :type => TRANSACTIONS[action.to_sym],
178
+ :dateq => Time.now.strftime('%d%m%Y%H%M%S'),
179
+ :numquestion => unique_id(parameters[:order_id]),
180
+ :site => @options[:login].to_s[0,7],
181
+ :rang => @options[:login].to_s[7..-1],
182
+ :cle => @options[:password],
183
+ :pays => '',
184
+ :archivage => parameters[:order_id]
185
+ )
186
+
187
+ parameters.collect { |key, value| "#{key.to_s.upcase}=#{CGI.escape(value.to_s)}" }.join("&")
188
+ end
189
+
190
+ def unique_id(seed = 0)
191
+ randkey = "#{seed}#{Time.now.usec}".to_i % 2147483647 # Max paybox value for the question number
192
+
193
+ "0000000000#{randkey}"[-10..-1]
194
+ end
195
+
196
+ def expdate(credit_card)
197
+ year = sprintf("%.4i", credit_card.year)
198
+ month = sprintf("%.2i", credit_card.month)
199
+
200
+ "#{month}#{year[-2..-1]}"
201
+ end
202
+
203
+ end
204
+ end
205
+ end