activemerchant 1.16.0 → 1.17.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 +0 -0
- data/CHANGELOG +15 -1
- data/CONTRIBUTORS +8 -0
- data/lib/active_merchant/billing/credit_card.rb +100 -18
- data/lib/active_merchant/billing/gateways/authorize_net.rb +31 -2
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +46 -36
- data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
- data/lib/active_merchant/billing/gateways/epay.rb +1 -1
- data/lib/active_merchant/billing/gateways/iridium.rb +3 -3
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +270 -0
- data/lib/active_merchant/billing/gateways/orbital.rb +5 -5
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +6 -3
- data/lib/active_merchant/billing/gateways/paypal_express.rb +22 -15
- data/lib/active_merchant/billing/gateways/quickpay.rb +96 -22
- data/lib/active_merchant/billing/integrations/payflow_link.rb +21 -0
- data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +58 -0
- data/lib/active_merchant/billing/integrations/payflow_link/notification.rb +78 -0
- data/lib/active_merchant/version.rb +1 -1
- metadata +23 -18
- metadata.gz.sig +0 -0
@@ -0,0 +1,270 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class OptimalPaymentGateway < Gateway
|
4
|
+
TEST_URL = 'https://webservices.test.optimalpayments.com/creditcardWS/CreditCardServlet/v1'
|
5
|
+
LIVE_URL = 'https://webservices.optimalpayments.com/creditcardWS/CreditCardServlet/v1'
|
6
|
+
|
7
|
+
# The countries the gateway supports merchants from as 2 digit ISO country codes
|
8
|
+
self.supported_countries = ['CA', 'US', 'GB']
|
9
|
+
|
10
|
+
# The card types supported by the payment gateway
|
11
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :solo] # :switch?
|
12
|
+
|
13
|
+
# The homepage URL of the gateway
|
14
|
+
self.homepage_url = 'http://www.optimalpayments.com/'
|
15
|
+
|
16
|
+
# The name of the gateway
|
17
|
+
self.display_name = 'Optimal Payments'
|
18
|
+
|
19
|
+
def initialize(options = {})
|
20
|
+
#requires!(options, :login, :password)
|
21
|
+
@options = options
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def authorize(money, card_or_auth, options = {})
|
26
|
+
parse_card_or_auth(card_or_auth, options)
|
27
|
+
commit("cc#{@stored_data}Authorize", money, options)
|
28
|
+
end
|
29
|
+
alias stored_authorize authorize # back-compat
|
30
|
+
|
31
|
+
def purchase(money, card_or_auth, options = {})
|
32
|
+
parse_card_or_auth(card_or_auth, options)
|
33
|
+
commit("cc#{@stored_data}Purchase", money, options)
|
34
|
+
end
|
35
|
+
alias stored_purchase purchase # back-compat
|
36
|
+
|
37
|
+
def refund(money, authorization, options = {})
|
38
|
+
options[:confirmationNumber] = authorization
|
39
|
+
commit('ccCredit', money, options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def void(authorization, options = {})
|
43
|
+
options[:confirmationNumber] = authorization
|
44
|
+
commit('ccAuthorizeReversal', nil, options)
|
45
|
+
end
|
46
|
+
|
47
|
+
def capture(money, authorization, options = {})
|
48
|
+
options[:confirmationNumber] = authorization
|
49
|
+
commit('ccSettlement', money, options)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def parse_card_or_auth(card_or_auth, options)
|
55
|
+
if card_or_auth.respond_to?(:number)
|
56
|
+
@credit_card = card_or_auth
|
57
|
+
@stored_data = ""
|
58
|
+
else
|
59
|
+
options[:confirmationNumber] = card_or_auth
|
60
|
+
@stored_data = "StoredData"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse(body)
|
65
|
+
REXML::Document.new(body || '')
|
66
|
+
end
|
67
|
+
|
68
|
+
def commit(action, money, post)
|
69
|
+
post[:order_id] ||= 'order_id'
|
70
|
+
|
71
|
+
xml = case action
|
72
|
+
when 'ccAuthorize', 'ccPurchase', 'ccVerification'
|
73
|
+
cc_auth_request(money, post)
|
74
|
+
when 'ccCredit', 'ccSettlement'
|
75
|
+
cc_post_auth_request(money, post)
|
76
|
+
when 'ccStoredDataAuthorize', 'ccStoredDataPurchase'
|
77
|
+
cc_stored_data_request(money, post)
|
78
|
+
when 'ccAuthorizeReversal'
|
79
|
+
cc_auth_reversal_request(post)
|
80
|
+
#when 'ccCancelSettle', 'ccCancelCredit', 'ccCancelPayment'
|
81
|
+
# cc_cancel_request(money, post)
|
82
|
+
#when 'ccPayment'
|
83
|
+
# cc_payment_request(money, post)
|
84
|
+
#when 'ccAuthenticate'
|
85
|
+
# cc_authenticate_request(money, post)
|
86
|
+
else
|
87
|
+
raise 'Unknown Action'
|
88
|
+
end
|
89
|
+
txnRequest = URI.encode(xml)
|
90
|
+
response = parse(ssl_post(test? ? TEST_URL : LIVE_URL, "txnMode=#{action}&txnRequest=#{txnRequest}"))
|
91
|
+
|
92
|
+
Response.new(successful?(response), message_from(response), hash_from_xml(response),
|
93
|
+
:test => test?,
|
94
|
+
:authorization => authorization_from(response)
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
98
|
+
def successful?(response)
|
99
|
+
REXML::XPath.first(response, '//decision').text == 'ACCEPTED' rescue false
|
100
|
+
end
|
101
|
+
|
102
|
+
def message_from(response)
|
103
|
+
REXML::XPath.each(response, '//detail') do |detail|
|
104
|
+
if detail.is_a?(REXML::Element) && detail.elements['tag'].text == 'InternalResponseDescription'
|
105
|
+
return detail.elements['value'].text
|
106
|
+
end
|
107
|
+
end
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
|
111
|
+
def authorization_from(response)
|
112
|
+
REXML::XPath.first(response, '//confirmationNumber').text rescue nil
|
113
|
+
end
|
114
|
+
|
115
|
+
def hash_from_xml(response)
|
116
|
+
hsh = {}
|
117
|
+
%w(confirmationNumber authCode
|
118
|
+
decision code description
|
119
|
+
actionCode avsResponse cvdResponse
|
120
|
+
txnTime duplicateFound
|
121
|
+
).each do |tag|
|
122
|
+
node = REXML::XPath.first(response, "//#{tag}")
|
123
|
+
hsh[tag] = node.text if node
|
124
|
+
end
|
125
|
+
REXML::XPath.each(response, '//detail') do |detail|
|
126
|
+
next unless detail.is_a?(REXML::Element)
|
127
|
+
tag = detail.elements['tag'].text
|
128
|
+
value = detail.elements['value'].text
|
129
|
+
hsh[tag] = value
|
130
|
+
end
|
131
|
+
hsh
|
132
|
+
end
|
133
|
+
|
134
|
+
def xml_document(root_tag)
|
135
|
+
xml = Builder::XmlMarkup.new :indent => 2
|
136
|
+
xml.tag!(root_tag, schema) do
|
137
|
+
yield xml
|
138
|
+
end
|
139
|
+
xml.target!
|
140
|
+
end
|
141
|
+
|
142
|
+
def cc_auth_request(money, opts)
|
143
|
+
xml_document('ccAuthRequestV1') do |xml|
|
144
|
+
build_merchant_account(xml, @options)
|
145
|
+
xml.merchantRefNum opts[:order_id]
|
146
|
+
xml.amount(money/100.0)
|
147
|
+
build_card(xml, opts)
|
148
|
+
build_billing_details(xml, opts)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def cc_auth_reversal_request(opts)
|
153
|
+
xml_document('ccAuthReversalRequestV1') do |xml|
|
154
|
+
build_merchant_account(xml, @options)
|
155
|
+
xml.confirmationNumber opts[:confirmationNumber]
|
156
|
+
xml.merchantRefNum opts[:order_id]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def cc_post_auth_request(money, opts)
|
161
|
+
xml_document('ccPostAuthRequestV1') do |xml|
|
162
|
+
build_merchant_account(xml, @options)
|
163
|
+
xml.confirmationNumber opts[:confirmationNumber]
|
164
|
+
xml.merchantRefNum opts[:order_id]
|
165
|
+
xml.amount(money/100.0)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def cc_stored_data_request(money, opts)
|
170
|
+
xml_document('ccStoredDataRequestV1') do |xml|
|
171
|
+
build_merchant_account(xml, @options)
|
172
|
+
xml.merchantRefNum opts[:order_id]
|
173
|
+
xml.confirmationNumber opts[:confirmationNumber]
|
174
|
+
xml.amount(money/100.0)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# untested
|
179
|
+
#
|
180
|
+
# def cc_cancel_request(opts)
|
181
|
+
# xml_document('ccCancelRequestV1') do |xml|
|
182
|
+
# build_merchant_account(xml, @options)
|
183
|
+
# xml.confirmationNumber opts[:confirmationNumber]
|
184
|
+
# end
|
185
|
+
# end
|
186
|
+
#
|
187
|
+
# def cc_payment_request(money, opts)
|
188
|
+
# xml_document('ccPaymentRequestV1') do |xml|
|
189
|
+
# build_merchant_account(xml, @options)
|
190
|
+
# xml.merchantRefNum opts[:order_id]
|
191
|
+
# xml.amount(money/100.0)
|
192
|
+
# build_card(xml, opts)
|
193
|
+
# build_billing_details(xml, opts)
|
194
|
+
# end
|
195
|
+
# end
|
196
|
+
#
|
197
|
+
# def cc_authenticate_request(opts)
|
198
|
+
# xml_document('ccAuthenticateRequestV1') do |xml|
|
199
|
+
# build_merchant_account(xml, @options)
|
200
|
+
# xml.confirmationNumber opts[:confirmationNumber]
|
201
|
+
# xml.paymentResponse 'myPaymentResponse'
|
202
|
+
# end
|
203
|
+
# end
|
204
|
+
|
205
|
+
def schema
|
206
|
+
{ 'xmlns' => 'http://www.optimalpayments.com/creditcard/xmlschema/v1',
|
207
|
+
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
208
|
+
'xsi:schemaLocation' => 'http://www.optimalpayments.com/creditcard/xmlschema/v1'
|
209
|
+
}
|
210
|
+
end
|
211
|
+
|
212
|
+
def build_merchant_account(xml, opts)
|
213
|
+
xml.tag! 'merchantAccount' do
|
214
|
+
xml.tag! 'accountNum' , opts[:account]
|
215
|
+
xml.tag! 'storeID' , opts[:login]
|
216
|
+
xml.tag! 'storePwd' , opts[:password]
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def build_card(xml, opts)
|
221
|
+
xml.tag! 'card' do
|
222
|
+
xml.tag! 'cardNum' , @credit_card.number
|
223
|
+
xml.tag! 'cardExpiry' do
|
224
|
+
xml.tag! 'month' , @credit_card.month
|
225
|
+
xml.tag! 'year' , @credit_card.year
|
226
|
+
end
|
227
|
+
if type = card_type(@credit_card.type)
|
228
|
+
xml.tag! 'cardType' , type
|
229
|
+
end
|
230
|
+
if @credit_card.verification_value
|
231
|
+
xml.tag! 'cvdIndicator' , '1' # Value Provided
|
232
|
+
xml.tag! 'cvd' , @credit_card.verification_value
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def build_billing_details(xml, opts)
|
238
|
+
xml.tag! 'billingDetails' do
|
239
|
+
addr = opts[:billing_address]
|
240
|
+
xml.tag! 'cardPayMethod', 'WEB'
|
241
|
+
if addr[:name]
|
242
|
+
xml.tag! 'firstName', CGI.escape(addr[:name].split(' ').first) # TODO: parse properly
|
243
|
+
xml.tag! 'lastName' , CGI.escape(addr[:name].split(' ').last )
|
244
|
+
end
|
245
|
+
xml.tag! 'street' , CGI.escape(addr[:address1]) if addr[:address1] && !addr[:address1].empty?
|
246
|
+
xml.tag! 'street2', CGI.escape(addr[:address2]) if addr[:address2] && !addr[:address2].empty?
|
247
|
+
xml.tag! 'city' , CGI.escape(addr[:city] ) if addr[:city] && !addr[:city].empty?
|
248
|
+
xml.tag! 'state' , CGI.escape(addr[:state] ) if addr[:state] && !addr[:state].empty?
|
249
|
+
xml.tag! 'country', CGI.escape(addr[:country] ) if addr[:country] && !addr[:country].empty?
|
250
|
+
xml.tag! 'zip' , CGI.escape(addr[:zip] ) # this one's actually required
|
251
|
+
xml.tag! 'phone' , CGI.escape(addr[:phone] ) if addr[:phone] && !addr[:phone].empty?
|
252
|
+
#xml.tag! 'email' , ''
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def card_type(key)
|
257
|
+
{ 'visa' => 'VI',
|
258
|
+
'master' => 'MC',
|
259
|
+
'american_express'=> 'AM',
|
260
|
+
'discover' => 'DI',
|
261
|
+
'diners_club' => 'DC',
|
262
|
+
#'switch' => '',
|
263
|
+
'solo' => 'SO'
|
264
|
+
}[key]
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
@@ -80,8 +80,8 @@ module ActiveMerchant #:nodoc:
|
|
80
80
|
def initialize(options = {})
|
81
81
|
unless options[:ip_authentication] == true
|
82
82
|
requires!(options, :login, :password, :merchant_id)
|
83
|
-
@options = options
|
84
83
|
end
|
84
|
+
@options = options
|
85
85
|
super
|
86
86
|
end
|
87
87
|
|
@@ -167,6 +167,7 @@ module ActiveMerchant #:nodoc:
|
|
167
167
|
xml.tag! :CurrencyCode, currency_code(currency)
|
168
168
|
xml.tag! :CurrencyExponent, '2' # Will need updating to support currencies such as the Yen.
|
169
169
|
|
170
|
+
xml.tag! :CardSecValInd, 1 if creditcard.verification_value? && %w( visa discover ).include?(creditcard.type)
|
170
171
|
xml.tag! :CardSecVal, creditcard.verification_value if creditcard.verification_value?
|
171
172
|
end
|
172
173
|
|
@@ -223,11 +224,11 @@ module ActiveMerchant #:nodoc:
|
|
223
224
|
end
|
224
225
|
|
225
226
|
def success?(response)
|
226
|
-
if response[:message_type] == "R"
|
227
|
+
if response[:message_type].nil? || response[:message_type] == "R"
|
227
228
|
response[:proc_status] == SUCCESS
|
228
229
|
else
|
229
230
|
response[:proc_status] == SUCCESS &&
|
230
|
-
|
231
|
+
response[:resp_code] == APPROVED
|
231
232
|
end
|
232
233
|
end
|
233
234
|
|
@@ -247,7 +248,7 @@ module ActiveMerchant #:nodoc:
|
|
247
248
|
xml.tag! :NewOrder do
|
248
249
|
xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
|
249
250
|
xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
|
250
|
-
xml.tag! :IndustryType, "EC"
|
251
|
+
xml.tag! :IndustryType, parameters[:industry_type] || "EC"
|
251
252
|
xml.tag! :MessageType, action
|
252
253
|
xml.tag! :BIN, '000002' # PNS Tampa
|
253
254
|
xml.tag! :MerchantID, @options[:merchant_id]
|
@@ -289,7 +290,6 @@ module ActiveMerchant #:nodoc:
|
|
289
290
|
end
|
290
291
|
|
291
292
|
def build_void_request_xml(money, authorization, parameters = {})
|
292
|
-
requires!(parameters, :transaction_index)
|
293
293
|
tx_ref_num, order_id = authorization.split(';')
|
294
294
|
xml = Builder::XmlMarkup.new(:indent => 2)
|
295
295
|
xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
|
@@ -63,10 +63,13 @@ module ActiveMerchant #:nodoc:
|
|
63
63
|
def initialize(options = {})
|
64
64
|
requires!(options, :login, :password)
|
65
65
|
|
66
|
+
headers = {'X-PP-AUTHORIZATION' => options.delete(:auth_signature), 'X-PAYPAL-MESSAGE-PROTOCOL' => 'SOAP11'} if options[:auth_signature]
|
66
67
|
@options = {
|
67
68
|
:pem => pem_file,
|
68
|
-
:signature => signature
|
69
|
+
:signature => signature,
|
70
|
+
:headers => headers || {}
|
69
71
|
}.update(options)
|
72
|
+
|
70
73
|
|
71
74
|
if @options[:pem].blank? && @options[:signature].blank?
|
72
75
|
raise ArgumentError, "An API Certificate or API Signature is required to make requests to PayPal"
|
@@ -280,7 +283,7 @@ module ActiveMerchant #:nodoc:
|
|
280
283
|
xml.instruct!
|
281
284
|
xml.tag! 'env:Envelope', ENVELOPE_NAMESPACES do
|
282
285
|
xml.tag! 'env:Header' do
|
283
|
-
add_credentials(xml)
|
286
|
+
add_credentials(xml) unless @options[:headers] && @options[:headers]['X-PP-AUTHORIZATION']
|
284
287
|
end
|
285
288
|
|
286
289
|
xml.tag! 'env:Body' do
|
@@ -320,7 +323,7 @@ module ActiveMerchant #:nodoc:
|
|
320
323
|
end
|
321
324
|
|
322
325
|
def commit(action, request)
|
323
|
-
response = parse(action, ssl_post(endpoint_url, build_request(request)))
|
326
|
+
response = parse(action, ssl_post(endpoint_url, build_request(request), @options[:headers]))
|
324
327
|
|
325
328
|
build_response(successful?(response), message_from(response), response,
|
326
329
|
:test => test?,
|
@@ -80,6 +80,8 @@ module ActiveMerchant #:nodoc:
|
|
80
80
|
xml.tag! 'n2:ButtonSource', application_id.to_s.slice(0,32) unless application_id.blank?
|
81
81
|
xml.tag! 'n2:InvoiceID', options[:order_id]
|
82
82
|
xml.tag! 'n2:OrderDescription', options[:description]
|
83
|
+
|
84
|
+
add_items_xml(xml, options, currency_code) if options[:items]
|
83
85
|
end
|
84
86
|
end
|
85
87
|
end
|
@@ -115,25 +117,13 @@ module ActiveMerchant #:nodoc:
|
|
115
117
|
xml.tag! 'n2:OrderDescription', options[:description]
|
116
118
|
xml.tag! 'n2:InvoiceID', options[:order_id]
|
117
119
|
|
118
|
-
if options[:items]
|
119
|
-
|
120
|
-
|
121
|
-
xml.tag! 'n2:Name', item[:name]
|
122
|
-
xml.tag! 'n2:Number', item[:number]
|
123
|
-
xml.tag! 'n2:Quantity', item[:quantity]
|
124
|
-
if item[:amount]
|
125
|
-
xml.tag! 'n2:Amount', localized_amount(item[:amount], currency_code), 'currencyID' => currency_code
|
126
|
-
end
|
127
|
-
xml.tag! 'n2:Description', item[:description]
|
128
|
-
xml.tag! 'n2:ItemURL', item[:url]
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
120
|
+
add_items_xml(xml, options, currency_code) if options[:items]
|
121
|
+
|
122
|
+
add_address(xml, 'n2:ShipToAddress', options[:shipping_address] || options[:address])
|
132
123
|
|
133
124
|
xml.tag! 'n2:PaymentAction', action
|
134
125
|
end
|
135
126
|
|
136
|
-
add_address(xml, 'n2:Address', options[:shipping_address] || options[:address])
|
137
127
|
xml.tag! 'n2:AddressOverride', options[:address_override] ? '1' : '0'
|
138
128
|
xml.tag! 'n2:NoShipping', options[:no_shipping] ? '1' : '0'
|
139
129
|
xml.tag! 'n2:ReturnURL', options[:return_url]
|
@@ -172,6 +162,23 @@ module ActiveMerchant #:nodoc:
|
|
172
162
|
def build_response(success, message, response, options = {})
|
173
163
|
PaypalExpressResponse.new(success, message, response, options)
|
174
164
|
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def add_items_xml(xml, options, currency_code)
|
169
|
+
options[:items].each do |item|
|
170
|
+
xml.tag! 'n2:PaymentDetailsItem' do
|
171
|
+
xml.tag! 'n2:Name', item[:name]
|
172
|
+
xml.tag! 'n2:Number', item[:number]
|
173
|
+
xml.tag! 'n2:Quantity', item[:quantity]
|
174
|
+
if item[:amount]
|
175
|
+
xml.tag! 'n2:Amount', localized_amount(item[:amount], currency_code), 'currencyID' => currency_code
|
176
|
+
end
|
177
|
+
xml.tag! 'n2:Description', item[:description]
|
178
|
+
xml.tag! 'n2:ItemURL', item[:url]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
175
182
|
end
|
176
183
|
end
|
177
184
|
end
|
@@ -8,30 +8,91 @@ module ActiveMerchant #:nodoc:
|
|
8
8
|
|
9
9
|
self.default_currency = 'DKK'
|
10
10
|
self.money_format = :cents
|
11
|
-
self.supported_cardtypes = [
|
11
|
+
self.supported_cardtypes = [:dankort, :forbrugsforeningen, :visa, :master, :american_express, :diners_club, :jcb, :maestro]
|
12
12
|
self.supported_countries = ['DK', 'SE']
|
13
13
|
self.homepage_url = 'http://quickpay.dk/'
|
14
14
|
self.display_name = 'Quickpay'
|
15
15
|
|
16
|
-
PROTOCOL = 3
|
17
|
-
|
18
16
|
MD5_CHECK_FIELDS = {
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
17
|
+
3 => {
|
18
|
+
:authorize => %w(protocol msgtype merchant ordernumber amount
|
19
|
+
currency autocapture cardnumber expirationdate
|
20
|
+
cvd cardtypelock testmode),
|
21
|
+
|
22
|
+
:capture => %w(protocol msgtype merchant amount transaction),
|
23
|
+
|
24
|
+
:cancel => %w(protocol msgtype merchant transaction),
|
25
|
+
|
26
|
+
:refund => %w(protocol msgtype merchant amount transaction),
|
27
|
+
|
28
|
+
:subscribe => %w(protocol msgtype merchant ordernumber cardnumber
|
29
|
+
expirationdate cvd cardtypelock description testmode),
|
30
|
+
|
31
|
+
:recurring => %w(protocol msgtype merchant ordernumber amount
|
32
|
+
currency autocapture transaction),
|
33
|
+
|
34
|
+
:status => %w(protocol msgtype merchant transaction),
|
35
|
+
|
36
|
+
:chstatus => %w(protocol msgtype merchant)
|
37
|
+
},
|
38
|
+
|
39
|
+
4 => {
|
40
|
+
:authorize => %w(protocol msgtype merchant ordernumber amount
|
41
|
+
currency autocapture cardnumber expirationdate cvd
|
42
|
+
cardtypelock testmode fraud_remote_addr
|
43
|
+
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
|
+
:capture => %w(protocol msgtype merchant amount transaction
|
48
|
+
fraud_remote_addr fraud_http_accept
|
49
|
+
fraud_http_accept_language fraud_http_accept_encoding
|
50
|
+
fraud_http_accept_charset fraud_http_referer
|
51
|
+
fraud_http_user_agent apikey),
|
52
|
+
|
53
|
+
:cancel => %w(protocol msgtype merchant transaction fraud_remote_addr
|
54
|
+
fraud_http_accept fraud_http_accept_language
|
55
|
+
fraud_http_accept_encoding fraud_http_accept_charset
|
56
|
+
fraud_http_referer fraud_http_user_agent apikey),
|
57
|
+
|
58
|
+
:refund => %w(protocol msgtype merchant amount transaction
|
59
|
+
fraud_remote_addr 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
|
+
:subscribe => %w(protocol msgtype merchant ordernumber cardnumber
|
64
|
+
expirationdate cvd cardtypelock description testmode
|
65
|
+
fraud_remote_addr fraud_http_accept fraud_http_accept_language
|
66
|
+
fraud_http_accept_encoding fraud_http_accept_charset
|
67
|
+
fraud_http_referer fraud_http_user_agent apikey),
|
68
|
+
|
69
|
+
:recurring => %w(protocol msgtype merchant ordernumber amount currency
|
70
|
+
autocapture transaction fraud_remote_addr fraud_http_accept
|
71
|
+
fraud_http_accept_language fraud_http_accept_encoding
|
72
|
+
fraud_http_accept_charset fraud_http_referer
|
73
|
+
fraud_http_user_agent apikey),
|
74
|
+
|
75
|
+
:status => %w(protocol msgtype merchant transaction fraud_remote_addr
|
76
|
+
fraud_http_accept fraud_http_accept_language
|
77
|
+
fraud_http_accept_encoding fraud_http_accept_charset
|
78
|
+
fraud_http_referer fraud_http_user_agent apikey),
|
79
|
+
|
80
|
+
:chstatus => %w(protocol msgtype merchant fraud_remote_addr fraud_http_accept
|
81
|
+
fraud_http_accept_language fraud_http_accept_encoding
|
82
|
+
fraud_http_accept_charset fraud_http_referer
|
83
|
+
fraud_http_user_agent apikey)
|
84
|
+
}
|
27
85
|
}
|
28
86
|
|
29
87
|
APPROVED = '000'
|
30
88
|
|
31
89
|
# The login is the QuickpayId
|
32
|
-
# The password is the md5checkword from the Quickpay
|
90
|
+
# The password is the md5checkword from the Quickpay manager
|
91
|
+
# To use the API-key from the Quickpay manager, specify :api-key
|
92
|
+
# Using the API-key, requires that you use version 4. Specify :version => 4 in options.
|
33
93
|
def initialize(options = {})
|
34
94
|
requires!(options, :login, :password)
|
95
|
+
@protocol = options.delete(:version) || 3 # default to protocol version 3
|
35
96
|
@options = options
|
36
97
|
super
|
37
98
|
end
|
@@ -43,6 +104,7 @@ module ActiveMerchant #:nodoc:
|
|
43
104
|
add_invoice(post, options)
|
44
105
|
add_creditcard_or_reference(post, credit_card_or_reference, options)
|
45
106
|
add_autocapture(post, false)
|
107
|
+
add_fraud_parameters(post, options)
|
46
108
|
add_testmode(post)
|
47
109
|
|
48
110
|
commit(recurring_or_authorize(credit_card_or_reference), post)
|
@@ -54,6 +116,7 @@ module ActiveMerchant #:nodoc:
|
|
54
116
|
add_amount(post, money, options)
|
55
117
|
add_creditcard_or_reference(post, credit_card_or_reference, options)
|
56
118
|
add_invoice(post, options)
|
119
|
+
add_fraud_parameters(post, options)
|
57
120
|
add_autocapture(post, true)
|
58
121
|
|
59
122
|
commit(recurring_or_authorize(credit_card_or_reference), post)
|
@@ -64,6 +127,7 @@ module ActiveMerchant #:nodoc:
|
|
64
127
|
|
65
128
|
add_reference(post, authorization)
|
66
129
|
add_amount_without_currency(post, money)
|
130
|
+
add_fraud_parameters(post, options)
|
67
131
|
|
68
132
|
commit(:capture, post)
|
69
133
|
end
|
@@ -72,6 +136,7 @@ module ActiveMerchant #:nodoc:
|
|
72
136
|
post = {}
|
73
137
|
|
74
138
|
add_reference(post, identification)
|
139
|
+
add_fraud_parameters(post, options)
|
75
140
|
|
76
141
|
commit(:cancel, post)
|
77
142
|
end
|
@@ -81,6 +146,7 @@ module ActiveMerchant #:nodoc:
|
|
81
146
|
|
82
147
|
add_amount_without_currency(post, money)
|
83
148
|
add_reference(post, identification)
|
149
|
+
add_fraud_parameters(post, options)
|
84
150
|
|
85
151
|
commit(:refund, post)
|
86
152
|
end
|
@@ -96,6 +162,7 @@ module ActiveMerchant #:nodoc:
|
|
96
162
|
add_creditcard(post, creditcard, options)
|
97
163
|
add_invoice(post, options)
|
98
164
|
add_description(post, options)
|
165
|
+
add_fraud_parameters(post, options)
|
99
166
|
add_testmode(post)
|
100
167
|
|
101
168
|
commit(:subscribe, post)
|
@@ -150,6 +217,18 @@ module ActiveMerchant #:nodoc:
|
|
150
217
|
def add_testmode(post)
|
151
218
|
post[:testmode] = test? ? '1' : '0'
|
152
219
|
end
|
220
|
+
|
221
|
+
def add_fraud_parameters(post, options)
|
222
|
+
if @protocol == 4
|
223
|
+
post[:fraud_remote_addr] = options[:fraud_remote_addr] if options[:fraud_remote_addr]
|
224
|
+
post[:fraud_http_accept] = options[:fraud_http_accept] if options[:fraud_http_accept]
|
225
|
+
post[:fraud_http_accept_language] = options[:fraud_http_accept_language] if options[:fraud_http_accept_language]
|
226
|
+
post[:fraud_http_accept_encoding] = options[:fraud_http_accept_encoding] if options[:fraud_http_accept_encoding]
|
227
|
+
post[:fraud_http_accept_charset] = options[:fraud_http_accept_charset] if options[:fraud_http_accept_charset]
|
228
|
+
post[:fraud_http_referer] = options[:fraud_http_referer] if options[:fraud_http_referer]
|
229
|
+
post[:fraud_http_user_agent] = options[:fraud_http_user_agent] if options[:fraud_http_user_agent]
|
230
|
+
end
|
231
|
+
end
|
153
232
|
|
154
233
|
def commit(action, params)
|
155
234
|
response = parse(ssl_post(URL, post_data(action, params)))
|
@@ -177,27 +256,22 @@ module ActiveMerchant #:nodoc:
|
|
177
256
|
end
|
178
257
|
|
179
258
|
def message_from(response)
|
180
|
-
|
181
|
-
when '008' # Error in request data
|
182
|
-
response[:qpstatmsg].to_s
|
183
|
-
#.scan(/[A-Z][a-z0-9 \/]+/).to_sentence
|
184
|
-
else
|
185
|
-
response[:qpstatmsg].to_s
|
186
|
-
end
|
259
|
+
response[:qpstatmsg].to_s
|
187
260
|
end
|
188
261
|
|
189
262
|
def post_data(action, params = {})
|
190
|
-
params[:protocol] =
|
263
|
+
params[:protocol] = @protocol
|
191
264
|
params[:msgtype] = action.to_s
|
192
265
|
params[:merchant] = @options[:login]
|
266
|
+
params[:apikey] = @options[:apikey] if @options[:apikey]
|
193
267
|
params[:md5check] = generate_check_hash(action, params)
|
194
268
|
|
195
269
|
params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
196
270
|
end
|
197
271
|
|
198
272
|
def generate_check_hash(action, params)
|
199
|
-
string = MD5_CHECK_FIELDS[action].collect do |key|
|
200
|
-
params[key]
|
273
|
+
string = MD5_CHECK_FIELDS[@protocol][action].collect do |key|
|
274
|
+
params[key.to_sym]
|
201
275
|
end.join('')
|
202
276
|
|
203
277
|
# Add the md5checkword
|