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 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