activemerchant 1.9.4 → 1.10.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.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +12 -3
- data/CONTRIBUTORS +15 -0
- data/README.rdoc +3 -0
- data/lib/active_merchant.rb +1 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +1 -1
- data/lib/active_merchant/billing/gateways/blue_pay.rb +11 -0
- data/lib/active_merchant/billing/gateways/epay.rb +3 -3
- data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +250 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
- data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +55 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +1 -1
- data/lib/active_merchant/billing/gateways/quantum.rb +277 -0
- data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +4 -2
- data/lib/active_merchant/version.rb +1 -1
- metadata +11 -5
- 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.10.0 (Jan 20, 2011)
|
4
|
+
|
5
|
+
* PayPal Express: Support returning payer phone number [Soleone]
|
6
|
+
* Fix ePay to correctly send order number [Soleone]
|
7
|
+
* Add BluePay Gateway [Nathaniel Talbott]
|
8
|
+
* Add Quantum Gateway [Joshua Lippiner]
|
9
|
+
* Add iDEAL/Rabobank gateway [Jonathan Rudenberg]
|
10
|
+
* SagePayForm: Added send_email_confirmation (default false) to enable confirmation emails [wisq]
|
11
|
+
|
3
12
|
== Version 1.9.4 (Jan 5, 2011)
|
4
13
|
|
5
14
|
* Update Garanti gateway to integrate with new API [Selem Delul]
|
@@ -11,7 +20,7 @@
|
|
11
20
|
|
12
21
|
== Version 1.9.2 (December 9, 2010)
|
13
22
|
|
14
|
-
* Add support for PayPal mobile payments [
|
23
|
+
* Add support for PayPal mobile payments [wisq]
|
15
24
|
* Add ePay gateway [ePay, Jonathan Rudenberg]
|
16
25
|
* Allow access to the raw HTTP response [Jonathan Rudenberg]
|
17
26
|
|
@@ -29,8 +38,8 @@
|
|
29
38
|
== Version 1.9.0 (October 14, 2010)
|
30
39
|
|
31
40
|
* Add support for DirecPay gateway [Soleone]
|
32
|
-
* Add SagePay Form integration gateway [
|
33
|
-
* Allow Return class to include a Notification for gateways that treat the direct response as a notification [
|
41
|
+
* Add SagePay Form integration gateway [wisq]
|
42
|
+
* Allow Return class to include a Notification for gateways that treat the direct response as a notification [wisq]
|
34
43
|
* Add support for PayboxDirect gateway [Donald Piret]
|
35
44
|
* Add support for SecureNet gateway [Kal]
|
36
45
|
* Add support for the Inspire gateway [ryan r. smith]
|
data/CONTRIBUTORS
CHANGED
@@ -173,3 +173,18 @@ ePay Gateway (November 23, 2010)
|
|
173
173
|
|
174
174
|
* Original code by ePay (epay.dk)
|
175
175
|
* Refactored by Jonathan Rudenberg
|
176
|
+
|
177
|
+
iDEAL/Rabobank Gateway (January 10, 2011)
|
178
|
+
|
179
|
+
* Original code by Soemirno Kartosoewito
|
180
|
+
* Refactored by Cody Fauser
|
181
|
+
* Refactored and updated by Jonathan Rudenberg
|
182
|
+
|
183
|
+
Quantum Gateway
|
184
|
+
|
185
|
+
* Joshua Lippiner
|
186
|
+
* Refactored by Nathaniel Talbott
|
187
|
+
|
188
|
+
BluePay Gateway
|
189
|
+
|
190
|
+
* Nathaniel Talbott
|
data/README.rdoc
CHANGED
@@ -14,6 +14,7 @@ The {ActiveMerchant Wiki}[http://github.com/Shopify/active_merchant/wikis] conta
|
|
14
14
|
* {Authorize.Net CIM}[http://www.authorize.net/] - US
|
15
15
|
* {Authorize.Net}[http://www.authorize.net/] - US
|
16
16
|
* {Beanstream.com}[http://www.beanstream.com/] - CA
|
17
|
+
* {BluePay}[http://www.bluepay.com/] - US
|
17
18
|
* {Braintree}[http://www.braintreepaymentsolutions.com] - US
|
18
19
|
* {CardStream}[http://www.cardstream.com/] - GB
|
19
20
|
* {CyberSource}[http://www.cybersource.com] - US
|
@@ -53,7 +54,9 @@ The {ActiveMerchant Wiki}[http://github.com/Shopify/active_merchant/wikis] conta
|
|
53
54
|
* {Protx}[http://www.protx.com] - GB
|
54
55
|
* {Psigate}[http://www.psigate.com/] - CA
|
55
56
|
* {PSL Payment Solutions}[http://www.paymentsolutionsltd.com/] - GB
|
57
|
+
* {Quantum}[http://www.quantumgateway.com] - US
|
56
58
|
* {Quickpay}[http://quickpay.dk/] - DK
|
59
|
+
* {Rabobank Nederland}[http://www.rabobank.nl/] - NL
|
57
60
|
* {Realex}[http://www.realexpayments.com/] - IE, GB
|
58
61
|
* {Sage Payment Solutions}[http://www.sagepayments.com] - US, CA
|
59
62
|
* {Sallie Mae}[http://www.salliemae.com] - US
|
data/lib/active_merchant.rb
CHANGED
@@ -26,6 +26,7 @@ $:.unshift File.dirname(__FILE__)
|
|
26
26
|
require 'active_support'
|
27
27
|
require 'active_support/core_ext/string/inflections'
|
28
28
|
require 'active_support/core_ext/hash/indifferent_access'
|
29
|
+
require 'active_support/core_ext/hash/conversions'
|
29
30
|
require 'active_support/core_ext/class/inheritable_attributes'
|
30
31
|
require 'active_support/core_ext/class/attribute_accessors'
|
31
32
|
require 'active_support/core_ext/class/delegating_attributes'
|
@@ -373,7 +373,7 @@ module ActiveMerchant #:nodoc:
|
|
373
373
|
return AVSResult.messages[ results[:avs_result_code] ] if AVS_ERRORS.include?(results[:avs_result_code])
|
374
374
|
end
|
375
375
|
|
376
|
-
return results[:response_reason_text].nil? ? '' : results[:response_reason_text]
|
376
|
+
return results[:response_reason_text].nil? ? '' : results[:response_reason_text].chomp('.')
|
377
377
|
end
|
378
378
|
|
379
379
|
def expdate(creditcard)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class BluePayGateway < AuthorizeNetGateway
|
4
|
+
self.test_url = "https://secure.bluepay.com/interfaces/a.net.test"
|
5
|
+
self.live_url = "https://secure.bluepay.com/interfaces/a.net"
|
6
|
+
self.homepage_url = 'http://www.bluepay.com/'
|
7
|
+
self.display_name = 'BluePay'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
@@ -62,7 +62,7 @@ module ActiveMerchant #:nodoc:
|
|
62
62
|
post = {}
|
63
63
|
|
64
64
|
add_amount(post, money, options)
|
65
|
-
add_invoice(post)
|
65
|
+
add_invoice(post, options)
|
66
66
|
add_creditcard_or_reference(post, credit_card_or_reference)
|
67
67
|
add_instant_capture(post, false)
|
68
68
|
|
@@ -74,7 +74,7 @@ module ActiveMerchant #:nodoc:
|
|
74
74
|
|
75
75
|
add_amount(post, money, options)
|
76
76
|
add_creditcard_or_reference(post, credit_card_or_reference)
|
77
|
-
add_invoice(post)
|
77
|
+
add_invoice(post, options)
|
78
78
|
add_instant_capture(post, true)
|
79
79
|
|
80
80
|
commit(:authorize, post)
|
@@ -122,7 +122,7 @@ module ActiveMerchant #:nodoc:
|
|
122
122
|
post[:transaction] = identification
|
123
123
|
end
|
124
124
|
|
125
|
-
def add_invoice(post)
|
125
|
+
def add_invoice(post, options)
|
126
126
|
post[:orderid] = format_order_number(options[:order_id])
|
127
127
|
end
|
128
128
|
|
@@ -0,0 +1,250 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/ideal_response'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
# Implementation contains some simplifications
|
6
|
+
# - does not support multiple subID per merchant
|
7
|
+
# - language is fixed to 'nl'
|
8
|
+
class IdealBaseGateway < Gateway
|
9
|
+
class_inheritable_accessor :test_url, :live_url, :server_pem, :pem_password, :default_expiration_period
|
10
|
+
self.default_expiration_period = 'PT10M'
|
11
|
+
self.default_currency = 'EUR'
|
12
|
+
self.pem_password = true
|
13
|
+
|
14
|
+
# These constants will never change for most users
|
15
|
+
AUTHENTICATION_TYPE = 'SHA1_RSA'
|
16
|
+
LANGUAGE = 'nl'
|
17
|
+
SUB_ID = '0'
|
18
|
+
API_VERSION = '1.1.0'
|
19
|
+
|
20
|
+
attr_reader :url
|
21
|
+
|
22
|
+
def initialize(options = {})
|
23
|
+
requires!(options, :login, :password, :pem)
|
24
|
+
@options = options
|
25
|
+
|
26
|
+
@options[:pem_password] = options[:password]
|
27
|
+
@url = test? ? test_url : live_url
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
# Setup transaction. Get redirect_url from response.service_url
|
32
|
+
def setup_purchase(money, options = {})
|
33
|
+
requires!(options, :issuer_id, :return_url, :order_id, :currency, :description, :entrance_code)
|
34
|
+
|
35
|
+
commit(build_transaction_request(money, options))
|
36
|
+
end
|
37
|
+
|
38
|
+
# Check status of transaction and confirm payment
|
39
|
+
# transaction_id must be a valid transaction_id from a prior setup.
|
40
|
+
def capture(transaction, options = {})
|
41
|
+
options[:transaction_id] = transaction
|
42
|
+
commit(build_status_request(options))
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get list of issuers from response.issuer_list
|
46
|
+
def issuers
|
47
|
+
commit(build_directory_request)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test?
|
51
|
+
@options[:test] || Base.gateway_mode == :test
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def token
|
56
|
+
if @token.nil?
|
57
|
+
@token = create_fingerprint(@options[:pem])
|
58
|
+
end
|
59
|
+
@token
|
60
|
+
end
|
61
|
+
|
62
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
63
|
+
# <AcquirerTrxReq xmlns="http://www.idealdesk.com/Message" version="1.1.0">
|
64
|
+
# <createDateTimeStamp>2001-12-17T09:30:47.0Z</createDateTimeStamp>
|
65
|
+
# <Issuer>
|
66
|
+
# <issuerID>1003</issuerID>
|
67
|
+
# </Issuer>
|
68
|
+
# <Merchant>
|
69
|
+
# <merchantID>000123456</merchantID>
|
70
|
+
# <subID>0</subID>
|
71
|
+
# <authentication>passkey</authentication>
|
72
|
+
# <token>1</token>
|
73
|
+
# <tokenCode>3823ad872eff23</tokenCode>
|
74
|
+
# <merchantReturnURL>https://www.mijnwinkel.nl/betaalafhandeling
|
75
|
+
# </merchantReturnURL>
|
76
|
+
# </Merchant>
|
77
|
+
# <Transaction>
|
78
|
+
# <purchaseID>iDEAL-aankoop 21</purchaseID>
|
79
|
+
# <amount>5999</amount>
|
80
|
+
# <currency>EUR</currency>
|
81
|
+
# <expirationPeriod>PT3M30S</expirationPeriod>
|
82
|
+
# <language>nl</language>
|
83
|
+
# <description>Documentensuite</description>
|
84
|
+
# <entranceCode>D67tyx6rw9IhY71</entranceCode>
|
85
|
+
# </Transaction>
|
86
|
+
# </AcquirerTrxReq>
|
87
|
+
def build_transaction_request(money, options)
|
88
|
+
date_time_stamp = create_time_stamp
|
89
|
+
message = date_time_stamp +
|
90
|
+
options[:issuer_id] +
|
91
|
+
@options[:login] +
|
92
|
+
SUB_ID +
|
93
|
+
options[:return_url] +
|
94
|
+
options[:order_id] +
|
95
|
+
money.to_s +
|
96
|
+
(options[:currency] || currency(money)) +
|
97
|
+
LANGUAGE +
|
98
|
+
options[:description] +
|
99
|
+
options[:entrance_code]
|
100
|
+
token_code = sign_message(@options[:pem], @options[:password], message)
|
101
|
+
|
102
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
103
|
+
xml.instruct!
|
104
|
+
xml.tag! 'AcquirerTrxReq', 'xmlns' => 'http://www.idealdesk.com/Message', 'version' => API_VERSION do
|
105
|
+
xml.tag! 'createDateTimeStamp', date_time_stamp
|
106
|
+
xml.tag! 'Issuer' do
|
107
|
+
xml.tag! 'issuerID', options[:issuer_id]
|
108
|
+
end
|
109
|
+
xml.tag! 'Merchant' do
|
110
|
+
xml.tag! 'merchantID', @options[:login]
|
111
|
+
xml.tag! 'subID', SUB_ID
|
112
|
+
xml.tag! 'authentication', AUTHENTICATION_TYPE
|
113
|
+
xml.tag! 'token', token
|
114
|
+
xml.tag! 'tokenCode', token_code
|
115
|
+
xml.tag! 'merchantReturnURL', options[:return_url]
|
116
|
+
end
|
117
|
+
xml.tag! 'Transaction' do
|
118
|
+
xml.tag! 'purchaseID', options[:order_id]
|
119
|
+
xml.tag! 'amount', money
|
120
|
+
xml.tag! 'currency', options[:currency]
|
121
|
+
xml.tag! 'expirationPeriod', options[:expiration_period] || default_expiration_period
|
122
|
+
xml.tag! 'language', LANGUAGE
|
123
|
+
xml.tag! 'description', options[:description]
|
124
|
+
xml.tag! 'entranceCode', options[:entrance_code]
|
125
|
+
end
|
126
|
+
xml.target!
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
131
|
+
# <AcquirerStatusReq xmlns="http://www.idealdesk.com/Message" version="1.1.0">
|
132
|
+
# <createDateTimeStamp>2001-12-17T09:30:47.0Z</createDateTimeStamp>
|
133
|
+
# <Merchant>
|
134
|
+
# <merchantID>000123456</merchantID>
|
135
|
+
# <subID>0</subID>
|
136
|
+
# <authentication>keyed hash</authentication>
|
137
|
+
# <token>1</token>
|
138
|
+
# <tokenCode>3823ad872eff23</tokenCode>
|
139
|
+
# </Merchant>
|
140
|
+
# <Transaction>
|
141
|
+
# <transactionID>0001023456789112</transactionID>
|
142
|
+
# </Transaction>
|
143
|
+
# </AcquirerStatusReq>
|
144
|
+
def build_status_request(options)
|
145
|
+
datetimestamp = create_time_stamp
|
146
|
+
message = datetimestamp + @options[:login] + SUB_ID + options[:transaction_id]
|
147
|
+
tokenCode = sign_message(@options[:pem], @options[:password], message)
|
148
|
+
|
149
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
150
|
+
xml.instruct!
|
151
|
+
xml.tag! 'AcquirerStatusReq', 'xmlns' => 'http://www.idealdesk.com/Message', 'version' => API_VERSION do
|
152
|
+
xml.tag! 'createDateTimeStamp', datetimestamp
|
153
|
+
xml.tag! 'Merchant' do
|
154
|
+
xml.tag! 'merchantID', @options[:login]
|
155
|
+
xml.tag! 'subID', SUB_ID
|
156
|
+
xml.tag! 'authentication' , AUTHENTICATION_TYPE
|
157
|
+
xml.tag! 'token', token
|
158
|
+
xml.tag! 'tokenCode', tokenCode
|
159
|
+
end
|
160
|
+
xml.tag! 'Transaction' do
|
161
|
+
xml.tag! 'transactionID', options[:transaction_id]
|
162
|
+
end
|
163
|
+
end
|
164
|
+
xml.target!
|
165
|
+
end
|
166
|
+
|
167
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
168
|
+
# <DirectoryReq xmlns="http://www.idealdesk.com/Message" version="1.1.0">
|
169
|
+
# <createDateTimeStamp>2001-12-17T09:30:47.0Z</createDateTimeStamp>
|
170
|
+
# <Merchant>
|
171
|
+
# <merchantID>000000001</merchantID>
|
172
|
+
# <subID>0</subID>
|
173
|
+
# <authentication>1</authentication>
|
174
|
+
# <token>hashkey</token>
|
175
|
+
# <tokenCode>WajqV1a3nDen0be2r196g9FGFF=</tokenCode>
|
176
|
+
# </Merchant>
|
177
|
+
# </DirectoryReq>
|
178
|
+
def build_directory_request
|
179
|
+
datetimestamp = create_time_stamp
|
180
|
+
message = datetimestamp + @options[:login] + SUB_ID
|
181
|
+
tokenCode = sign_message(@options[:pem], @options[:password], message)
|
182
|
+
|
183
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
184
|
+
xml.instruct!
|
185
|
+
xml.tag! 'DirectoryReq', 'xmlns' => 'http://www.idealdesk.com/Message', 'version' => API_VERSION do
|
186
|
+
xml.tag! 'createDateTimeStamp', datetimestamp
|
187
|
+
xml.tag! 'Merchant' do
|
188
|
+
xml.tag! 'merchantID', @options[:login]
|
189
|
+
xml.tag! 'subID', SUB_ID
|
190
|
+
xml.tag! 'authentication', AUTHENTICATION_TYPE
|
191
|
+
xml.tag! 'token', token
|
192
|
+
xml.tag! 'tokenCode', tokenCode
|
193
|
+
end
|
194
|
+
end
|
195
|
+
xml.target!
|
196
|
+
end
|
197
|
+
|
198
|
+
def commit(request)
|
199
|
+
raw_response = ssl_post(url, request)
|
200
|
+
response = Hash.from_xml(raw_response.to_s)
|
201
|
+
response_type = response.keys[0]
|
202
|
+
|
203
|
+
case response_type
|
204
|
+
when 'AcquirerTrxRes', 'DirectoryRes'
|
205
|
+
success = true
|
206
|
+
when 'ErrorRes'
|
207
|
+
success = false
|
208
|
+
when 'AcquirerStatusRes'
|
209
|
+
raise SecurityError, "Message verification failed.", caller unless status_response_verified?(response)
|
210
|
+
success = (response['AcquirerStatusRes']['Transaction']['status'] == 'Success')
|
211
|
+
else
|
212
|
+
raise ArgumentError, "Unknown response type.", caller
|
213
|
+
end
|
214
|
+
|
215
|
+
return IdealResponse.new(success, response.keys[0], response, :test => test?)
|
216
|
+
end
|
217
|
+
|
218
|
+
def create_fingerprint(cert_file)
|
219
|
+
cert_data = OpenSSL::X509::Certificate.new(cert_file).to_s
|
220
|
+
cert_data = cert_data.sub(/-----BEGIN CERTIFICATE-----/, '')
|
221
|
+
cert_data = cert_data.sub(/-----END CERTIFICATE-----/, '')
|
222
|
+
fingerprint = ActiveSupport::Base64.decode64(cert_data)
|
223
|
+
fingerprint = Digest::SHA1.hexdigest(fingerprint)
|
224
|
+
return fingerprint.upcase
|
225
|
+
end
|
226
|
+
|
227
|
+
def sign_message(private_key_data, password, data)
|
228
|
+
private_key = OpenSSL::PKey::RSA.new(private_key_data, password)
|
229
|
+
signature = private_key.sign(OpenSSL::Digest::SHA1.new, data.gsub('\s', ''))
|
230
|
+
return ActiveSupport::Base64.encode64(signature).gsub(/\n/, '')
|
231
|
+
end
|
232
|
+
|
233
|
+
def verify_message(cert_file, data, signature)
|
234
|
+
public_key = OpenSSL::X509::Certificate.new(cert_file).public_key
|
235
|
+
return public_key.verify(OpenSSL::Digest::SHA1.new, ActiveSupport::Base64.decode64(signature), data)
|
236
|
+
end
|
237
|
+
|
238
|
+
def status_response_verified?(response)
|
239
|
+
transaction = response['AcquirerStatusRes']['Transaction']
|
240
|
+
message = response['AcquirerStatusRes']['createDateTimeStamp'] + transaction['transactionID' ] + transaction['status']
|
241
|
+
message << transaction['consumerAccountNumber'].to_s
|
242
|
+
verify_message(server_pem, message, response['AcquirerStatusRes']['Signature']['signatureValue'])
|
243
|
+
end
|
244
|
+
|
245
|
+
def create_time_stamp
|
246
|
+
Time.now.gmtime.strftime('%Y-%m-%dT%H:%M:%S.000Z')
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICQDCCAakCBELvbPYwDQYJKoZIhvcNAQEEBQAwZzELMAkGA1UEBhMCREUxDzANBgNVBAgTBkhl
|
3
|
+
c3NlbjESMBAGA1UEBxMJRnJhbmtmdXJ0MQ4wDAYDVQQKEwVpREVBTDEOMAwGA1UECxMFaURFQUwx
|
4
|
+
EzARBgNVBAMTCmlERUFMIFJhYm8wHhcNMDUwODAyMTI1NDE0WhcNMTUwNzMxMTI1NDE0WjBnMQsw
|
5
|
+
CQYDVQQGEwJERTEPMA0GA1UECBMGSGVzc2VuMRIwEAYDVQQHEwlGcmFua2Z1cnQxDjAMBgNVBAoT
|
6
|
+
BWlERUFMMQ4wDAYDVQQLEwVpREVBTDETMBEGA1UEAxMKaURFQUwgUmFibzCBnzANBgkqhkiG9w0B
|
7
|
+
AQEFAAOBjQAwgYkCgYEA486iIKVhr8RNjxH+PZ3yTWx/8k2fqDFm8XU8I1Z5esRmPFnXmlgA8cG7
|
8
|
+
e9AaBPaLoP7Dc8dRQoUO66KMakzGI/WAVdHIJiiKrz8xOcioIgrzPSqec7aqse3J28UraEHkGESJ
|
9
|
+
7dAW7Pw/shrmpmkzKsunLt6AkXss4W3JUndZUN0CAwEAATANBgkqhkiG9w0BAQQFAAOBgQCGy/FK
|
10
|
+
Lotp2ZOTtuLMgvDy74eicq/Znv4bLfpglzAPHycRHcHsXuer/lNHyvpKf2gdYe+IFalUW3OJZWIM
|
11
|
+
jpm4UniJ16RPdgwWVRJEdPr/P7JXMIqD2IEOgujuuTQ7x0VgCf9XrsPsP9ZR5DIPcDDhbrpSE0yF
|
12
|
+
Do77nwG61xMaGA==
|
13
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class IdealResponse < Response
|
4
|
+
|
5
|
+
def issuer_list
|
6
|
+
list = @params.values[0]['Directory']['Issuer']
|
7
|
+
case list
|
8
|
+
when Hash
|
9
|
+
return [list]
|
10
|
+
when Array
|
11
|
+
return list
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def service_url
|
16
|
+
@params.values[0]['Issuer']['issuerAuthenticationURL']
|
17
|
+
end
|
18
|
+
|
19
|
+
def transaction
|
20
|
+
@params.values[0]['Transaction']
|
21
|
+
end
|
22
|
+
|
23
|
+
def error
|
24
|
+
@params.values[0]['Error']
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/ideal/ideal_base'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
# First, make sure you have everything setup correctly and all of your dependencies in place with:
|
6
|
+
#
|
7
|
+
# require 'rubygems'
|
8
|
+
# require 'active_merchant'
|
9
|
+
#
|
10
|
+
# ActiveMerchant expects the amounts to be given as an Integer in cents. In this case, 10 EUR becomes 1000.
|
11
|
+
#
|
12
|
+
# Configure the gateway using your iDEAL bank account info and security settings:
|
13
|
+
#
|
14
|
+
# Create gateway:
|
15
|
+
# gateway = ActiveMerchant::Billing::IdealRabobankGateway.new(
|
16
|
+
# :login => '123456789', # merchant number
|
17
|
+
# :pem => File.read(RAILS_ROOT + '/config/ideal.pem'), # put certificate and PEM in this file
|
18
|
+
# :password => 'password' # password for the PEM key
|
19
|
+
# )
|
20
|
+
#
|
21
|
+
# Get list of issuers to fill selection list on your payment form:
|
22
|
+
# response = gateway.issuers
|
23
|
+
# list = response.issuer_list
|
24
|
+
#
|
25
|
+
# Request transaction:
|
26
|
+
#
|
27
|
+
# options = {
|
28
|
+
# :issuer_id => '0001',
|
29
|
+
# :expiration_period => 'PT10M',
|
30
|
+
# :return_url => 'http://www.return.url',
|
31
|
+
# :order_id => '1234567890123456',
|
32
|
+
# :currency => 'EUR',
|
33
|
+
# :description => 'Een omschrijving',
|
34
|
+
# :entrance_code => '1234'
|
35
|
+
# }
|
36
|
+
#
|
37
|
+
# response = gateway.setup_purchase(amount, options)
|
38
|
+
# transaction_id = response.transaction['transactionID']
|
39
|
+
# redirect_url = response.service_url
|
40
|
+
#
|
41
|
+
# Mandatory status request will confirm transaction:
|
42
|
+
# response = gateway.capture(transaction_id)
|
43
|
+
#
|
44
|
+
# Implementation contains some simplifications
|
45
|
+
# - does not support multiple subID per merchant
|
46
|
+
# - language is fixed to 'nl'
|
47
|
+
class IdealRabobankGateway < IdealBaseGateway
|
48
|
+
class_inheritable_accessor :test_url, :live_url
|
49
|
+
|
50
|
+
self.test_url = 'https://idealtest.rabobank.nl/ideal/iDeal'
|
51
|
+
self.live_url = 'https://ideal.rabobank.nl/ideal/iDeal'
|
52
|
+
self.server_pem = File.read(File.dirname(__FILE__) + '/ideal/ideal_rabobank.pem')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,277 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
# ActiveMerchant Implementation for Quantum Gateway XML Requester Service
|
4
|
+
# Based on API Doc from 8/6/2009
|
5
|
+
#
|
6
|
+
# Important Notes
|
7
|
+
# * Support is included for a customer id via the :customer option, invoice number via :invoice option, invoice description via :merchant option and memo via :description option
|
8
|
+
# * You can force email of receipt with :email_receipt => true
|
9
|
+
# * You can force email of merchant receipt with :merchant_receipt => true
|
10
|
+
# * You can exclude CVV with :ignore_cvv => true
|
11
|
+
# * All transactions use dollar values.
|
12
|
+
class QuantumGateway < Gateway
|
13
|
+
LIVE_URL = 'https://secure.quantumgateway.com/cgi/xml_requester.php'
|
14
|
+
|
15
|
+
# visa, master, american_express, discover
|
16
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
17
|
+
self.supported_countries = ['US']
|
18
|
+
self.default_currency = 'USD'
|
19
|
+
self.money_format = :dollars
|
20
|
+
self.homepage_url = 'http://www.quantumgateway.com'
|
21
|
+
self.display_name = 'Quantum Gateway'
|
22
|
+
|
23
|
+
# These are the options that can be used when creating a new Quantum Gateway object.
|
24
|
+
#
|
25
|
+
# :login => Your Quantum Gateway Gateway ID
|
26
|
+
#
|
27
|
+
# :password => Your Quantum Gateway Vault Key or Restrict Key
|
28
|
+
#
|
29
|
+
# NOTE: For testing supply your test GatewayLogin and GatewayKey
|
30
|
+
#
|
31
|
+
# :email_receipt => true if you want a receipt sent to the customer (false be default)
|
32
|
+
#
|
33
|
+
# :merchant_receipt => true if you want to override receiving the merchant receipt
|
34
|
+
#
|
35
|
+
# :ignore_avs => true ignore both AVS and CVV verification
|
36
|
+
# :ignore_cvv => true don't want to use CVV so continue processing even if CVV would have failed
|
37
|
+
#
|
38
|
+
def initialize(options = {})
|
39
|
+
requires!(options, :login, :password)
|
40
|
+
@options = options
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
# Should run against the test servers or not?
|
45
|
+
def test?
|
46
|
+
@options[:test] || Base.gateway_mode == :test
|
47
|
+
end
|
48
|
+
|
49
|
+
# Request an authorization for an amount from CyberSource
|
50
|
+
#
|
51
|
+
def authorize(money, creditcard, options = {})
|
52
|
+
setup_address_hash(options)
|
53
|
+
commit(build_auth_request(money, creditcard, options), options )
|
54
|
+
end
|
55
|
+
|
56
|
+
# Capture an authorization that has previously been requested
|
57
|
+
def capture(money, authorization, options = {})
|
58
|
+
setup_address_hash(options)
|
59
|
+
commit(build_capture_request(money, authorization, options), options)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Purchase is an auth followed by a capture
|
63
|
+
# You must supply an order_id in the options hash
|
64
|
+
def purchase(money, creditcard, options = {})
|
65
|
+
setup_address_hash(options)
|
66
|
+
commit(build_purchase_request(money, creditcard, options), options)
|
67
|
+
end
|
68
|
+
|
69
|
+
def void(identification, options = {})
|
70
|
+
commit(build_void_request(identification, options), options)
|
71
|
+
end
|
72
|
+
|
73
|
+
def credit(money, identification, options = {})
|
74
|
+
commit(build_credit_request(money, identification, options), options)
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def setup_address_hash(options)
|
80
|
+
options[:billing_address] = options[:billing_address] || options[:address] || {}
|
81
|
+
end
|
82
|
+
|
83
|
+
def build_auth_request(money, creditcard, options)
|
84
|
+
xml = Builder::XmlMarkup.new
|
85
|
+
add_common_credit_card_info(xml,'AUTH_ONLY')
|
86
|
+
add_purchase_data(xml, money)
|
87
|
+
add_creditcard(xml, creditcard)
|
88
|
+
add_address(xml, creditcard, options[:billing_address], options)
|
89
|
+
add_invoice_details(xml, options)
|
90
|
+
add_customer_details(xml, options)
|
91
|
+
add_memo(xml, options)
|
92
|
+
add_business_rules_data(xml)
|
93
|
+
xml.target!
|
94
|
+
end
|
95
|
+
|
96
|
+
def build_capture_request(money, authorization, options)
|
97
|
+
xml = Builder::XmlMarkup.new
|
98
|
+
add_common_credit_card_info(xml,'PREVIOUS_SALE')
|
99
|
+
transaction_id, _ = authorization_parts_from(authorization)
|
100
|
+
add_transaction_id(xml, transaction_id)
|
101
|
+
xml.target!
|
102
|
+
end
|
103
|
+
|
104
|
+
def build_purchase_request(money, creditcard, options)
|
105
|
+
xml = Builder::XmlMarkup.new
|
106
|
+
add_common_credit_card_info(xml, @options[:ignore_avs] || @options[:ignore_cvv] ? 'SALES' : 'AUTH_CAPTURE')
|
107
|
+
add_address(xml, creditcard, options[:billing_address], options)
|
108
|
+
add_purchase_data(xml, money)
|
109
|
+
add_creditcard(xml, creditcard)
|
110
|
+
add_invoice_details(xml, options)
|
111
|
+
add_customer_details(xml, options)
|
112
|
+
add_memo(xml, options)
|
113
|
+
add_business_rules_data(xml)
|
114
|
+
xml.target!
|
115
|
+
end
|
116
|
+
|
117
|
+
def build_void_request(authorization, options)
|
118
|
+
xml = Builder::XmlMarkup.new
|
119
|
+
add_common_credit_card_info(xml,'VOID')
|
120
|
+
transaction_id, _ = authorization_parts_from(authorization)
|
121
|
+
add_transaction_id(xml, transaction_id)
|
122
|
+
xml.target!
|
123
|
+
end
|
124
|
+
|
125
|
+
def build_credit_request(money, authorization, options)
|
126
|
+
xml = Builder::XmlMarkup.new
|
127
|
+
add_common_credit_card_info(xml,'RETURN')
|
128
|
+
add_purchase_data(xml, money)
|
129
|
+
transaction_id, cc = authorization_parts_from(authorization)
|
130
|
+
add_transaction_id(xml, transaction_id)
|
131
|
+
xml.tag! 'CreditCardNumber', cc
|
132
|
+
xml.target!
|
133
|
+
end
|
134
|
+
|
135
|
+
def add_common_credit_card_info(xml, process_type)
|
136
|
+
xml.tag! 'RequestType', 'ProcessSingleTransaction'
|
137
|
+
xml.tag! 'TransactionType', 'CREDIT'
|
138
|
+
xml.tag! 'PaymentType', 'CC'
|
139
|
+
xml.tag! 'ProcessType', process_type
|
140
|
+
end
|
141
|
+
|
142
|
+
def add_business_rules_data(xml)
|
143
|
+
xml.tag!('CustomerEmail', @options[:email_receipt] ? 'Y' : 'N')
|
144
|
+
xml.tag!('MerchantEmail', @options[:merchant_receipt] ? 'Y' : 'N')
|
145
|
+
end
|
146
|
+
|
147
|
+
def add_invoice_details(xml, options)
|
148
|
+
xml.tag! 'InvoiceNumber', options[:invoice]
|
149
|
+
xml.tag! 'InvoiceDescription', options[:merchant]
|
150
|
+
end
|
151
|
+
|
152
|
+
def add_customer_details(xml, options)
|
153
|
+
xml.tag! 'CustomerID', options[:customer]
|
154
|
+
end
|
155
|
+
|
156
|
+
def add_transaction_id(xml, transaction_id)
|
157
|
+
xml.tag! 'TransactionID', transaction_id
|
158
|
+
end
|
159
|
+
|
160
|
+
def add_memo(xml, options)
|
161
|
+
xml.tag! 'Memo', options[:description]
|
162
|
+
end
|
163
|
+
|
164
|
+
def add_purchase_data(xml, money = 0)
|
165
|
+
xml.tag! 'Amount', amount(money)
|
166
|
+
xml.tag! 'TransactionDate', Time.now
|
167
|
+
end
|
168
|
+
|
169
|
+
def add_address(xml, creditcard, address, options, shipTo = false)
|
170
|
+
xml.tag! 'FirstName', creditcard.first_name
|
171
|
+
xml.tag! 'LastName', creditcard.last_name
|
172
|
+
xml.tag! 'Address', address[:address1] # => there is no support for address2 in quantum
|
173
|
+
xml.tag! 'City', address[:city]
|
174
|
+
xml.tag! 'State', address[:state]
|
175
|
+
xml.tag! 'ZipCode', address[:zip]
|
176
|
+
xml.tag! 'Country', address[:country]
|
177
|
+
xml.tag! 'EmailAddress', options[:email]
|
178
|
+
xml.tag! 'IPAddress', options[:ip]
|
179
|
+
end
|
180
|
+
|
181
|
+
def add_creditcard(xml, creditcard)
|
182
|
+
xml.tag! 'PaymentType', 'CC'
|
183
|
+
xml.tag! 'CreditCardNumber', creditcard.number
|
184
|
+
xml.tag! 'ExpireMonth', format(creditcard.month, :two_digits)
|
185
|
+
xml.tag! 'ExpireYear', format(creditcard.year, :four_digits)
|
186
|
+
xml.tag!('CVV2', creditcard.verification_value) unless (@options[:ignore_cvv] || creditcard.verification_value.blank? )
|
187
|
+
end
|
188
|
+
|
189
|
+
# Where we actually build the full SOAP request using builder
|
190
|
+
def build_request(body, options)
|
191
|
+
xml = Builder::XmlMarkup.new
|
192
|
+
xml.instruct!
|
193
|
+
xml.tag! 'QGWRequest' do
|
194
|
+
xml.tag! 'Authentication' do
|
195
|
+
xml.tag! 'GatewayLogin', @options[:login]
|
196
|
+
xml.tag! 'GatewayKey', @options[:password]
|
197
|
+
end
|
198
|
+
xml.tag! 'Request' do
|
199
|
+
xml << body
|
200
|
+
end
|
201
|
+
end
|
202
|
+
xml.target!
|
203
|
+
end
|
204
|
+
|
205
|
+
# Contact CyberSource, make the SOAP request, and parse the reply into a Response object
|
206
|
+
def commit(request, options)
|
207
|
+
headers = { 'Content-Type' => 'text/xml' }
|
208
|
+
response = parse(ssl_post(LIVE_URL, build_request(request, options), headers))
|
209
|
+
|
210
|
+
success = response[:request_status] == "Success"
|
211
|
+
message = response[:request_message]
|
212
|
+
|
213
|
+
if success # => checking for connectivity success first
|
214
|
+
success = %w(APPROVED FORCED VOIDED).include?(response[:Status])
|
215
|
+
message = response[:StatusDescription]
|
216
|
+
authorization = success ? authorization_for(response) : nil
|
217
|
+
end
|
218
|
+
|
219
|
+
Response.new(success, message, response,
|
220
|
+
:test => test?,
|
221
|
+
:authorization => authorization,
|
222
|
+
:avs_result => { :code => response[:AVSResponseCode] },
|
223
|
+
:cvv_result => response[:CVV2ResponseCode]
|
224
|
+
)
|
225
|
+
end
|
226
|
+
|
227
|
+
# Parse the SOAP response
|
228
|
+
# Technique inspired by the Paypal Gateway
|
229
|
+
def parse(xml)
|
230
|
+
reply = {}
|
231
|
+
|
232
|
+
begin
|
233
|
+
xml = REXML::Document.new(xml)
|
234
|
+
|
235
|
+
root = REXML::XPath.first(xml, "//QGWRequest/ResponseSummary")
|
236
|
+
parse_element(reply, root)
|
237
|
+
reply[:request_status] = reply[:Status]
|
238
|
+
reply[:request_message] = "#{reply[:Status]}: #{reply[:StatusDescription]}"
|
239
|
+
|
240
|
+
if root = REXML::XPath.first(xml, "//QGWRequest/Result")
|
241
|
+
root.elements.to_a.each do |node|
|
242
|
+
parse_element(reply, node)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
rescue Exception => e
|
246
|
+
reply[:request_status] = 'Failure'
|
247
|
+
reply[:request_message] = "Failure: There was a problem parsing the response XML"
|
248
|
+
end
|
249
|
+
|
250
|
+
return reply
|
251
|
+
end
|
252
|
+
|
253
|
+
def parse_element(reply, node)
|
254
|
+
if node.has_elements?
|
255
|
+
node.elements.each{|e| parse_element(reply, e) }
|
256
|
+
else
|
257
|
+
if node.parent.name =~ /item/
|
258
|
+
parent = node.parent.name + (node.parent.attributes["id"] ? "_" + node.parent.attributes["id"] : '')
|
259
|
+
reply[(parent + '_' + node.name).to_sym] = node.text
|
260
|
+
else
|
261
|
+
reply[node.name.to_sym] = node.text
|
262
|
+
end
|
263
|
+
end
|
264
|
+
return reply
|
265
|
+
end
|
266
|
+
|
267
|
+
def authorization_for(reply)
|
268
|
+
"#{reply[:TransactionID]};#{reply[:CreditCardNumber]}"
|
269
|
+
end
|
270
|
+
|
271
|
+
def authorization_parts_from(authorization)
|
272
|
+
authorization.split(/;/)
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
@@ -19,7 +19,8 @@ module ActiveMerchant #:nodoc:
|
|
19
19
|
:first_name => 'BillingFirstnames',
|
20
20
|
:last_name => 'BillingSurname',
|
21
21
|
:email => 'CustomerEMail',
|
22
|
-
:phone => 'BillingPhone'
|
22
|
+
:phone => 'BillingPhone',
|
23
|
+
:send_email_confirmation => 'SendEmail'
|
23
24
|
|
24
25
|
mapping :billing_address,
|
25
26
|
:city => 'BillingCity',
|
@@ -46,9 +47,10 @@ module ActiveMerchant #:nodoc:
|
|
46
47
|
|
47
48
|
fields['FailureURL'] ||= fields['SuccessURL']
|
48
49
|
|
49
|
-
crypt_skip = ['Vendor', 'EncryptKey']
|
50
|
+
crypt_skip = ['Vendor', 'EncryptKey', 'SendEmail']
|
50
51
|
crypt_skip << 'BillingState' unless fields['BillingCountry'] == 'US'
|
51
52
|
crypt_skip << 'DeliveryState' unless fields['DeliveryCountry'] == 'US'
|
53
|
+
crypt_skip << 'CustomerEMail' unless fields['SendEmail']
|
52
54
|
|
53
55
|
key = fields['EncryptKey']
|
54
56
|
@crypt ||= create_crypt_field(fields.except(*crypt_skip), key)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activemerchant
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 63
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
8
|
+
- 10
|
9
|
+
- 0
|
10
|
+
version: 1.10.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tobias Luetke
|
@@ -36,7 +36,7 @@ cert_chain:
|
|
36
36
|
hPaSTyVU0yCSnw==
|
37
37
|
-----END CERTIFICATE-----
|
38
38
|
|
39
|
-
date: 2011-01-
|
39
|
+
date: 2011-01-20 00:00:00 +01:00
|
40
40
|
default_executable:
|
41
41
|
dependencies:
|
42
42
|
- !ruby/object:Gem::Dependency
|
@@ -115,6 +115,7 @@ files:
|
|
115
115
|
- lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb
|
116
116
|
- lib/active_merchant/billing/gateways/beanstream.rb
|
117
117
|
- lib/active_merchant/billing/gateways/beanstream_interac.rb
|
118
|
+
- lib/active_merchant/billing/gateways/blue_pay.rb
|
118
119
|
- lib/active_merchant/billing/gateways/bogus.rb
|
119
120
|
- lib/active_merchant/billing/gateways/braintree/braintree_common.rb
|
120
121
|
- lib/active_merchant/billing/gateways/braintree.rb
|
@@ -130,6 +131,10 @@ files:
|
|
130
131
|
- lib/active_merchant/billing/gateways/exact.rb
|
131
132
|
- lib/active_merchant/billing/gateways/first_pay.rb
|
132
133
|
- lib/active_merchant/billing/gateways/garanti.rb
|
134
|
+
- lib/active_merchant/billing/gateways/ideal/ideal_base.rb
|
135
|
+
- lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem
|
136
|
+
- lib/active_merchant/billing/gateways/ideal/ideal_response.rb
|
137
|
+
- lib/active_merchant/billing/gateways/ideal_rabobank.rb
|
133
138
|
- lib/active_merchant/billing/gateways/inspire.rb
|
134
139
|
- lib/active_merchant/billing/gateways/instapay.rb
|
135
140
|
- lib/active_merchant/billing/gateways/iridium.rb
|
@@ -164,6 +169,7 @@ files:
|
|
164
169
|
- lib/active_merchant/billing/gateways/plugnpay.rb
|
165
170
|
- lib/active_merchant/billing/gateways/psigate.rb
|
166
171
|
- lib/active_merchant/billing/gateways/psl_card.rb
|
172
|
+
- lib/active_merchant/billing/gateways/quantum.rb
|
167
173
|
- lib/active_merchant/billing/gateways/quickpay.rb
|
168
174
|
- lib/active_merchant/billing/gateways/realex.rb
|
169
175
|
- lib/active_merchant/billing/gateways/sage/sage_bankcard.rb
|
metadata.gz.sig
CHANGED
Binary file
|