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 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 [Adrian Irving-Beer]
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 [Adrian Irving-Beer]
33
- * Allow Return class to include a Notification for gateways that treat the direct response as a notification [Adrian Irving-Beer]
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
@@ -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][0..-2]
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
@@ -30,7 +30,7 @@ module ActiveMerchant #:nodoc:
30
30
  'state' => @params['state_or_province'],
31
31
  'country' => @params['country'],
32
32
  'zip' => @params['postal_code'],
33
- 'phone' => nil
33
+ 'phone' => @params['contact_phone']
34
34
  }
35
35
  end
36
36
  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)
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = "1.9.4"
2
+ VERSION = "1.10.0"
3
3
  end
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: 59
4
+ hash: 63
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 9
9
- - 4
10
- version: 1.9.4
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-05 00:00:00 +01:00
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