activemerchant 1.49.0 → 1.50.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +47 -0
  3. data/CONTRIBUTORS +4 -0
  4. data/README.md +5 -1
  5. data/lib/active_merchant/billing/credit_card.rb +9 -0
  6. data/lib/active_merchant/billing/gateways/allied_wallet.rb +203 -0
  7. data/lib/active_merchant/billing/gateways/authorize_net.rb +17 -6
  8. data/lib/active_merchant/billing/gateways/beanstream.rb +4 -0
  9. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +0 -4
  10. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +4 -0
  11. data/lib/active_merchant/billing/gateways/bpoint.rb +277 -0
  12. data/lib/active_merchant/billing/gateways/cashnet.rb +19 -8
  13. data/lib/active_merchant/billing/gateways/cenpos.rb +15 -29
  14. data/lib/active_merchant/billing/gateways/conekta.rb +3 -2
  15. data/lib/active_merchant/billing/gateways/dibs.rb +206 -0
  16. data/lib/active_merchant/billing/gateways/fat_zebra.rb +19 -12
  17. data/lib/active_merchant/billing/gateways/merchant_partners.rb +245 -0
  18. data/lib/active_merchant/billing/gateways/netbilling.rb +1 -0
  19. data/lib/active_merchant/billing/gateways/omise.rb +319 -0
  20. data/lib/active_merchant/billing/gateways/optimal_payment.rb +5 -4
  21. data/lib/active_merchant/billing/gateways/orbital.rb +7 -0
  22. data/lib/active_merchant/billing/gateways/payu_in.rb +243 -0
  23. data/lib/active_merchant/billing/gateways/quickpay.rb +11 -357
  24. data/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +188 -0
  25. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +240 -0
  26. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +227 -0
  27. data/lib/active_merchant/billing/gateways/s5.rb +226 -0
  28. data/lib/active_merchant/billing/gateways/sage_pay.rb +7 -1
  29. data/lib/active_merchant/billing/gateways/secure_net.rb +1 -1
  30. data/lib/active_merchant/billing/gateways/stripe.rb +8 -5
  31. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +2 -2
  32. data/lib/active_merchant/billing/gateways/vanco.rb +280 -0
  33. data/lib/active_merchant/connection.rb +3 -0
  34. data/lib/active_merchant/version.rb +1 -1
  35. metadata +15 -27
  36. checksums.yaml.gz.sig +0 -2
  37. data.tar.gz.sig +0 -0
  38. data/lib/active_merchant/billing/gateways/adyen.rb +0 -209
  39. metadata.gz.sig +0 -1
@@ -0,0 +1,188 @@
1
+
2
+ module QuickpayCommon
3
+
4
+ MD5_CHECK_FIELDS = {
5
+ 3 => {
6
+ :authorize => %w(protocol msgtype merchant ordernumber amount
7
+ currency autocapture cardnumber expirationdate
8
+ cvd cardtypelock testmode),
9
+
10
+ :capture => %w(protocol msgtype merchant amount finalize transaction),
11
+
12
+ :cancel => %w(protocol msgtype merchant transaction),
13
+
14
+ :refund => %w(protocol msgtype merchant amount transaction),
15
+
16
+ :subscribe => %w(protocol msgtype merchant ordernumber cardnumber
17
+ expirationdate cvd cardtypelock description testmode),
18
+
19
+ :recurring => %w(protocol msgtype merchant ordernumber amount
20
+ currency autocapture transaction),
21
+
22
+ :status => %w(protocol msgtype merchant transaction),
23
+
24
+ :chstatus => %w(protocol msgtype merchant)
25
+ },
26
+
27
+ 4 => {
28
+ :authorize => %w(protocol msgtype merchant ordernumber amount
29
+ currency autocapture cardnumber expirationdate cvd
30
+ cardtypelock testmode fraud_remote_addr
31
+ fraud_http_accept fraud_http_accept_language
32
+ fraud_http_accept_encoding fraud_http_accept_charset
33
+ fraud_http_referer fraud_http_user_agent apikey),
34
+
35
+ :capture => %w(protocol msgtype merchant amount finalize transaction apikey),
36
+
37
+ :cancel => %w(protocol msgtype merchant transaction apikey),
38
+
39
+ :refund => %w(protocol msgtype merchant amount transaction apikey),
40
+
41
+ :subscribe => %w(protocol msgtype merchant ordernumber cardnumber
42
+ expirationdate cvd cardtypelock description testmode
43
+ fraud_remote_addr fraud_http_accept fraud_http_accept_language
44
+ fraud_http_accept_encoding fraud_http_accept_charset
45
+ fraud_http_referer fraud_http_user_agent apikey),
46
+
47
+ :recurring => %w(protocol msgtype merchant ordernumber amount currency
48
+ autocapture transaction apikey),
49
+
50
+ :status => %w(protocol msgtype merchant transaction apikey),
51
+
52
+ :chstatus => %w(protocol msgtype merchant apikey)
53
+ },
54
+
55
+ 5 => {
56
+ :authorize => %w(protocol msgtype merchant ordernumber amount
57
+ currency autocapture cardnumber expirationdate cvd
58
+ cardtypelock testmode fraud_remote_addr
59
+ fraud_http_accept fraud_http_accept_language
60
+ fraud_http_accept_encoding fraud_http_accept_charset
61
+ fraud_http_referer fraud_http_user_agent apikey),
62
+
63
+ :capture => %w(protocol msgtype merchant amount finalize transaction apikey),
64
+
65
+ :cancel => %w(protocol msgtype merchant transaction apikey),
66
+
67
+ :refund => %w(protocol msgtype merchant amount transaction apikey),
68
+
69
+ :subscribe => %w(protocol msgtype merchant ordernumber cardnumber
70
+ expirationdate cvd cardtypelock description testmode
71
+ fraud_remote_addr fraud_http_accept fraud_http_accept_language
72
+ fraud_http_accept_encoding fraud_http_accept_charset
73
+ fraud_http_referer fraud_http_user_agent apikey),
74
+
75
+ :recurring => %w(protocol msgtype merchant ordernumber amount currency
76
+ autocapture transaction apikey),
77
+
78
+ :status => %w(protocol msgtype merchant transaction apikey),
79
+
80
+ :chstatus => %w(protocol msgtype merchant apikey)
81
+ },
82
+
83
+ 6 => {
84
+ :authorize => %w(protocol msgtype merchant ordernumber amount
85
+ currency autocapture cardnumber expirationdate cvd
86
+ cardtypelock testmode fraud_remote_addr
87
+ fraud_http_accept fraud_http_accept_language
88
+ fraud_http_accept_encoding fraud_http_accept_charset
89
+ fraud_http_referer fraud_http_user_agent apikey),
90
+
91
+ :capture => %w(protocol msgtype merchant amount finalize transaction
92
+ apikey),
93
+
94
+ :cancel => %w(protocol msgtype merchant transaction apikey),
95
+
96
+ :refund => %w(protocol msgtype merchant amount transaction apikey),
97
+
98
+ :subscribe => %w(protocol msgtype merchant ordernumber cardnumber
99
+ expirationdate cvd cardtypelock description testmode
100
+ fraud_remote_addr fraud_http_accept fraud_http_accept_language
101
+ fraud_http_accept_encoding fraud_http_accept_charset
102
+ fraud_http_referer fraud_http_user_agent apikey),
103
+
104
+ :recurring => %w(protocol msgtype merchant ordernumber amount currency
105
+ autocapture transaction apikey),
106
+
107
+ :status => %w(protocol msgtype merchant transaction apikey),
108
+
109
+ :chstatus => %w(protocol msgtype merchant apikey)
110
+ },
111
+
112
+ 7 => {
113
+ :authorize => %w(protocol msgtype merchant ordernumber amount
114
+ currency autocapture cardnumber expirationdate cvd
115
+ acquirers cardtypelock testmode fraud_remote_addr
116
+ fraud_http_accept fraud_http_accept_language
117
+ fraud_http_accept_encoding fraud_http_accept_charset
118
+ fraud_http_referer fraud_http_user_agent apikey),
119
+
120
+ :capture => %w(protocol msgtype merchant amount finalize transaction
121
+ apikey),
122
+
123
+ :cancel => %w(protocol msgtype merchant transaction apikey),
124
+
125
+ :refund => %w(protocol msgtype merchant amount transaction apikey),
126
+
127
+ :subscribe => %w(protocol msgtype merchant ordernumber amount currency
128
+ cardnumber expirationdate cvd acquirers cardtypelock
129
+ description testmode fraud_remote_addr fraud_http_accept
130
+ fraud_http_accept_language fraud_http_accept_encoding
131
+ fraud_http_accept_charset fraud_http_referer
132
+ fraud_http_user_agent apikey),
133
+
134
+ :recurring => %w(protocol msgtype merchant ordernumber amount currency
135
+ autocapture transaction apikey),
136
+
137
+ :status => %w(protocol msgtype merchant transaction apikey),
138
+
139
+ :chstatus => %w(protocol msgtype merchant apikey)
140
+ },
141
+
142
+ 10 => {
143
+ :authorize => %w(mobile_number acquirer autofee customer_id extras
144
+ zero_auth),
145
+ :capture => %w( extras ),
146
+ :cancel => %w( extras ),
147
+ :refund => %w( extras ),
148
+ :subscribe => %w( variables branding_id),
149
+ :authorize_subscription => %w( mobile_number acquirer customer_ip),
150
+ :recurring => %w(auto_capture autofee zero_auth)
151
+ }
152
+ }
153
+
154
+ RESPONSE_CODES = {
155
+ 200 => 'OK',
156
+ 201 => 'Created',
157
+ 202 => 'Accepted',
158
+ 400 => 'Bad Request',
159
+ 401 => 'UnAuthorized',
160
+ 402 => 'Payment Required',
161
+ 403 => 'Forbidden',
162
+ 404 => 'Not Found',
163
+ 405 => 'Method Not Allowed',
164
+ 406 => 'Not Acceptable',
165
+ 409 => 'Conflict',
166
+ 500 => 'Internal Server Error'
167
+ }
168
+
169
+ def self.included(base)
170
+ base.default_currency = 'DKK'
171
+ base.money_format = :cents
172
+
173
+ base.supported_cardtypes = [:dankort, :forbrugsforeningen, :visa, :master,
174
+ :american_express, :diners_club, :jcb, :maestro]
175
+ base.supported_countries = ['DE', 'DK', 'ES', 'FI', 'FR', 'FO', 'GB', 'IS', 'NO', 'SE']
176
+ base.homepage_url = 'http://quickpay.net/'
177
+ base.display_name = 'QuickPay'
178
+
179
+ end
180
+
181
+ def expdate(credit_card)
182
+ year = format(credit_card.year, :two_digits)
183
+ month = format(credit_card.month, :two_digits)
184
+
185
+ "#{year}#{month}"
186
+ end
187
+
188
+ end
@@ -0,0 +1,240 @@
1
+ require 'json'
2
+ require 'active_merchant/billing/gateways/quickpay/quickpay_common'
3
+
4
+ module ActiveMerchant
5
+ module Billing
6
+ class QuickpayV10Gateway < Gateway
7
+ include QuickpayCommon
8
+ API_VERSION = 10
9
+
10
+ self.live_url = self.test_url = 'https://api.quickpay.net'
11
+
12
+ def initialize(options = {})
13
+ requires!(options, :api_key)
14
+ super
15
+ end
16
+
17
+ def purchase(money, credit_card, options = {})
18
+ MultiResponse.run(true) do |r|
19
+ r.process { create_payment(money, options) }
20
+ r.process {
21
+ post = authorization_params(money, credit_card, options)
22
+ add_autocapture(post, true)
23
+ commit(synchronized_path("/payments/#{r.authorization}/authorize"), post)
24
+ }
25
+ end
26
+ end
27
+
28
+ def authorize(money, credit_card, options = {})
29
+ MultiResponse.run(true) do |r|
30
+ r.process { create_payment(money, options) }
31
+ r.process {
32
+ post = authorization_params(money, credit_card, options)
33
+ commit(synchronized_path("/payments/#{r.authorization}/authorize"), post)
34
+ }
35
+ end
36
+ end
37
+
38
+ def void(identification)
39
+ commit(synchronized_path "/payments/#{identification}/cancel")
40
+ end
41
+
42
+ def credit(money, identification, options = {})
43
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
44
+ refund(money, identification, options)
45
+ end
46
+
47
+ def capture(money, identification, options = {})
48
+ post = {}
49
+ add_amount(post, money, options)
50
+ add_additional_params(:capture, post, options)
51
+ commit(synchronized_path("/payments/#{identification}/capture"), post)
52
+ end
53
+
54
+ def refund(money, identification, options = {})
55
+ post = {}
56
+ add_amount(post, money, options)
57
+ add_additional_params(:refund, post, options)
58
+ commit(synchronized_path("/payments/#{identification}/refund"), post)
59
+ end
60
+
61
+ def store(credit_card, options = {})
62
+ MultiResponse.run(true) do |r|
63
+ r.process { create_subscription(options) }
64
+ r.process {
65
+ authorize_subscription(r.authorization, credit_card, options)
66
+ }
67
+ end
68
+ end
69
+
70
+ def unstore(identification)
71
+ commit(synchronized_path "/subscriptions/#{identification}/cancel")
72
+ end
73
+
74
+ private
75
+
76
+ def authorization_params(money, credit_card, options = {})
77
+ post = {}
78
+
79
+ add_amount(post, money, options)
80
+ add_credit_card(post, credit_card)
81
+ add_additional_params(:authorize, post, options)
82
+
83
+ post
84
+ end
85
+
86
+ def create_subscription(options = {})
87
+ post = {}
88
+
89
+ add_subscription_invoice(post, options)
90
+ commit('/subscriptions', post)
91
+ end
92
+
93
+ def authorize_subscription(identification, credit_card, options = {})
94
+ post = {}
95
+
96
+ add_credit_card(post, credit_card, options)
97
+ add_additional_params(:authorize_subscription, post, options)
98
+ commit(synchronized_path("/subscriptions/#{identification}/authorize"), post)
99
+ end
100
+
101
+ def create_payment(money, options = {})
102
+ post = {}
103
+ add_currency(post, money, options)
104
+ add_invoice(post, options)
105
+ commit('/payments', post)
106
+ end
107
+
108
+ def commit(action, params = {})
109
+ success = false
110
+ begin
111
+ response = parse(ssl_post(self.live_url + action, params.to_json, headers))
112
+ success = successful?(response)
113
+ rescue ResponseError => e
114
+ response = response_error(e.response.body)
115
+ rescue JSON::ParserError
116
+ response = json_error(response)
117
+ end
118
+
119
+ Response.new(success, message_from(success, response), response,
120
+ :test => test?,
121
+ :authorization => response['id']
122
+ )
123
+ end
124
+
125
+ def add_subscription_invoice(post, options = {})
126
+ requires!(options, :order_id, :description)
127
+ post[:order_id] = options[:order_id]
128
+ post[:description] = options[:description]
129
+ end
130
+
131
+ def add_currency(post, money, options)
132
+ post[:currency] = options[:currency] || currency(money)
133
+ end
134
+
135
+ def add_amount(post, money, options)
136
+ post[:amount] = amount(money)
137
+ end
138
+
139
+ def add_autocapture(post, value)
140
+ post[:auto_capture] = value
141
+ end
142
+
143
+ def add_order_id(post, options)
144
+ requires!(options, :order_id)
145
+ post[:order_id] = options[:order_id]
146
+ end
147
+
148
+ def add_invoice(post, options)
149
+ add_order_id(post, options)
150
+
151
+ if options[:billing_address]
152
+ post[:invoice_address] = map_address(options[:billing_address])
153
+ end
154
+
155
+ if options[:shipping_address]
156
+ post[:shipping_address] = map_address(options[:shipping_address])
157
+ end
158
+
159
+ [:metadata, :brading_id, :variables].each do |field|
160
+ post[field] = options[field] if options[field]
161
+ end
162
+ end
163
+
164
+ def add_additional_params(action, post, options = {})
165
+ MD5_CHECK_FIELDS[API_VERSION][action].each do |key|
166
+ key = key.to_sym
167
+ post[key] = options[key] if options[key]
168
+ end
169
+ end
170
+
171
+ def add_credit_card(post, credit_card, options = {})
172
+ post[:card] ||= {}
173
+ post[:card][:number] = credit_card.number
174
+ post[:card][:cvd] = credit_card.verification_value
175
+ post[:card][:expiration] = expdate(credit_card)
176
+ post[:card][:issued_to] = credit_card.name
177
+ end
178
+
179
+ def parse(body)
180
+ JSON.parse(body)
181
+ end
182
+
183
+ def successful?(response)
184
+ has_error = response['errors']
185
+ invalid_code = (response.key?('qp_status_code') and response['qp_status_code'] != "20000")
186
+
187
+ !(has_error || invalid_code)
188
+ end
189
+
190
+ def message_from(success, response)
191
+ success ? 'OK' : (response['message'] || response['qp_status_msg'])
192
+ end
193
+
194
+ def map_address(address)
195
+ return {} if address.nil?
196
+ requires!(address, :name, :address1, :city, :zip, :country)
197
+ mapped = {
198
+ :name => address[:name],
199
+ :street => address[:address1],
200
+ :city => address[:city],
201
+ :region => address[:address2],
202
+ :zip_code => address[:zip],
203
+ :country_code => address[:country]
204
+ }
205
+ mapped
206
+ end
207
+
208
+ def headers
209
+ auth = Base64.strict_encode64(":#{@options[:api_key]}")
210
+ {
211
+ "Authorization" => "Basic " + auth,
212
+ "User-Agent" => "Quickpay-v#{API_VERSION} ActiveMerchantBindings/#{ActiveMerchant::VERSION}",
213
+ "Accept" => "application/json",
214
+ "Accept-Version" => "v#{API_VERSION}",
215
+ "Content-Type" => "application/json"
216
+ }
217
+ end
218
+
219
+ def response_error(raw_response)
220
+ begin
221
+ parse(raw_response)
222
+ rescue JSON::ParserError
223
+ json_error(raw_response)
224
+ end
225
+ end
226
+
227
+ def json_error(raw_response)
228
+ msg = 'Invalid response received from the Quickpay API.'
229
+ msg += " (The raw response returned by the API was #{raw_response.inspect})"
230
+ { "message" => msg }
231
+ end
232
+
233
+ def synchronized_path(path)
234
+ "#{path}?synchronized"
235
+ end
236
+
237
+ end
238
+
239
+ end
240
+ end
@@ -0,0 +1,227 @@
1
+ require 'rexml/document'
2
+ require 'digest/md5'
3
+ require 'active_merchant/billing/gateways/quickpay/quickpay_common'
4
+
5
+ module ActiveMerchant #:nodoc:
6
+ module Billing #:nodoc:
7
+ class QuickpayV4to7Gateway < Gateway
8
+ include QuickpayCommon
9
+ self.live_url = self.test_url = 'https://secure.quickpay.dk/api'
10
+ APPROVED = '000'
11
+
12
+ # The login is the QuickpayId
13
+ # The password is the md5checkword from the Quickpay manager
14
+ # To use the API-key from the Quickpay manager, specify :api-key
15
+ # Using the API-key, requires that you use version 4+. Specify :version => 4/5/6/7 in options.
16
+ def initialize(options = {})
17
+ requires!(options, :login, :password)
18
+ @protocol = options.delete(:version) || 7 # default to protocol version 7
19
+ super
20
+ end
21
+
22
+ def authorize(money, credit_card_or_reference, options = {})
23
+ post = {}
24
+
25
+ action = recurring_or_authorize(credit_card_or_reference)
26
+
27
+ add_amount(post, money, options)
28
+ add_invoice(post, options)
29
+ add_creditcard_or_reference(post, credit_card_or_reference, options)
30
+ add_autocapture(post, false)
31
+ add_fraud_parameters(post, options) if action.eql?(:authorize)
32
+ add_testmode(post)
33
+
34
+ commit(action, post)
35
+ end
36
+
37
+ def purchase(money, credit_card_or_reference, options = {})
38
+ post = {}
39
+
40
+ action = recurring_or_authorize(credit_card_or_reference)
41
+
42
+ add_amount(post, money, options)
43
+ add_creditcard_or_reference(post, credit_card_or_reference, options)
44
+ add_invoice(post, options)
45
+ add_fraud_parameters(post, options) if action.eql?(:authorize)
46
+ add_autocapture(post, true)
47
+
48
+ commit(action, post)
49
+ end
50
+
51
+ def capture(money, authorization, options = {})
52
+ post = {}
53
+
54
+ add_finalize(post, options)
55
+ add_reference(post, authorization)
56
+ add_amount_without_currency(post, money)
57
+ commit(:capture, post)
58
+ end
59
+
60
+ def void(identification, options = {})
61
+ post = {}
62
+
63
+ add_reference(post, identification)
64
+
65
+ commit(:cancel, post)
66
+ end
67
+
68
+ def refund(money, identification, options = {})
69
+ post = {}
70
+
71
+ add_amount_without_currency(post, money)
72
+ add_reference(post, identification)
73
+
74
+ commit(:refund, post)
75
+ end
76
+
77
+ def credit(money, identification, options = {})
78
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
79
+ refund(money, identification, options)
80
+ end
81
+
82
+ def store(creditcard, options = {})
83
+ post = {}
84
+
85
+ add_creditcard(post, creditcard, options)
86
+ add_amount(post, 0, options) if @protocol >= 7
87
+ add_invoice(post, options)
88
+ add_description(post, options)
89
+ add_fraud_parameters(post, options)
90
+ add_testmode(post)
91
+
92
+ commit(:subscribe, post)
93
+ end
94
+
95
+ private
96
+
97
+ def add_amount(post, money, options = {})
98
+ post[:amount] = amount(money)
99
+ post[:currency] = options[:currency] || currency(money)
100
+ end
101
+
102
+ def add_amount_without_currency(post, money, options = {})
103
+ post[:amount] = amount(money)
104
+ end
105
+
106
+ def add_invoice(post, options)
107
+ post[:ordernumber] = format_order_number(options[:order_id])
108
+ end
109
+
110
+ def add_creditcard(post, credit_card, options)
111
+ post[:cardnumber] = credit_card.number
112
+ post[:cvd] = credit_card.verification_value
113
+ post[:expirationdate] = expdate(credit_card)
114
+ post[:cardtypelock] = options[:cardtypelock] unless options[:cardtypelock].blank?
115
+ post[:acquirers] = options[:acquirers] unless options[:acquirers].blank?
116
+ end
117
+
118
+ def add_reference(post, identification)
119
+ post[:transaction] = identification
120
+ end
121
+
122
+ def add_creditcard_or_reference(post, credit_card_or_reference, options)
123
+ if credit_card_or_reference.is_a?(String)
124
+ add_reference(post, credit_card_or_reference)
125
+ else
126
+ add_creditcard(post, credit_card_or_reference, options)
127
+ end
128
+ end
129
+
130
+ def add_autocapture(post, autocapture)
131
+ post[:autocapture] = autocapture ? 1 : 0
132
+ end
133
+
134
+ def recurring_or_authorize(credit_card_or_reference)
135
+ credit_card_or_reference.is_a?(String) ? :recurring : :authorize
136
+ end
137
+
138
+ def add_description(post, options)
139
+ post[:description] = options[:description]
140
+ end
141
+
142
+ def add_testmode(post)
143
+ return if post[:transaction].present?
144
+ post[:testmode] = test? ? '1' : '0'
145
+ end
146
+
147
+ def add_fraud_parameters(post, options)
148
+ if @protocol >= 4
149
+ post[:fraud_remote_addr] = options[:ip] if options[:ip]
150
+ post[:fraud_http_accept] = options[:fraud_http_accept] if options[:fraud_http_accept]
151
+ post[:fraud_http_accept_language] = options[:fraud_http_accept_language] if options[:fraud_http_accept_language]
152
+ post[:fraud_http_accept_encoding] = options[:fraud_http_accept_encoding] if options[:fraud_http_accept_encoding]
153
+ post[:fraud_http_accept_charset] = options[:fraud_http_accept_charset] if options[:fraud_http_accept_charset]
154
+ post[:fraud_http_referer] = options[:fraud_http_referer] if options[:fraud_http_referer]
155
+ post[:fraud_http_user_agent] = options[:fraud_http_user_agent] if options[:fraud_http_user_agent]
156
+ end
157
+ end
158
+
159
+ def add_finalize(post, options)
160
+ post[:finalize] = options[:finalize] ? '1' : '0'
161
+ end
162
+
163
+ def commit(action, params)
164
+ response = parse(ssl_post(self.live_url, post_data(action, params)))
165
+
166
+ Response.new(successful?(response), message_from(response), response,
167
+ :test => test?,
168
+ :authorization => response[:transaction]
169
+ )
170
+ end
171
+
172
+ def successful?(response)
173
+ response[:qpstat] == APPROVED
174
+ end
175
+
176
+ def parse(data)
177
+ response = {}
178
+
179
+ doc = REXML::Document.new(data)
180
+
181
+ doc.root.elements.each do |element|
182
+ response[element.name.to_sym] = element.text
183
+ end
184
+
185
+ response
186
+ end
187
+
188
+ def message_from(response)
189
+ response[:qpstatmsg].to_s
190
+ end
191
+
192
+ def post_data(action, params = {})
193
+ params[:protocol] = @protocol
194
+ params[:msgtype] = action.to_s
195
+ params[:merchant] = @options[:login]
196
+ params[:apikey] = @options[:apikey] if @options[:apikey]
197
+ params[:md5check] = generate_check_hash(action, params)
198
+
199
+ params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
200
+ end
201
+
202
+ def generate_check_hash(action, params)
203
+ string = MD5_CHECK_FIELDS[@protocol][action].collect do |key|
204
+ params[key.to_sym]
205
+ end.join('')
206
+
207
+ # Add the md5checkword
208
+ string << @options[:password].to_s
209
+
210
+ Digest::MD5.hexdigest(string)
211
+ end
212
+
213
+ def expdate(credit_card)
214
+ year = format(credit_card.year, :two_digits)
215
+ month = format(credit_card.month, :two_digits)
216
+
217
+ "#{year}#{month}"
218
+ end
219
+
220
+ # Limited to 20 digits max
221
+ def format_order_number(number)
222
+ number.to_s.gsub(/[^\w]/, '').rjust(4, "0")[0...20]
223
+ end
224
+ end
225
+ end
226
+ end
227
+