activemerchant 1.49.0 → 1.50.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.
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
+