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