activemerchant 1.121.0 → 1.125.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.
- checksums.yaml +4 -4
- data/CHANGELOG +217 -0
- data/README.md +1 -1
- data/lib/active_merchant/billing/check.rb +13 -19
- data/lib/active_merchant/billing/credit_card.rb +13 -0
- data/lib/active_merchant/billing/credit_card_formatting.rb +1 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +24 -12
- data/lib/active_merchant/billing/gateway.rb +1 -1
- data/lib/active_merchant/billing/gateways/adyen.rb +75 -27
- data/lib/active_merchant/billing/gateways/authorize_net.rb +10 -8
- data/lib/active_merchant/billing/gateways/blue_pay.rb +29 -0
- data/lib/active_merchant/billing/gateways/blue_snap.rb +2 -2
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +6 -3
- data/lib/active_merchant/billing/gateways/card_stream.rb +17 -13
- data/lib/active_merchant/billing/gateways/cashnet.rb +15 -5
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +33 -4
- data/lib/active_merchant/billing/gateways/credorax.rb +2 -1
- data/lib/active_merchant/billing/gateways/cyber_source.rb +41 -6
- data/lib/active_merchant/billing/gateways/d_local.rb +12 -6
- data/lib/active_merchant/billing/gateways/decidir.rb +7 -1
- data/lib/active_merchant/billing/gateways/decidir_plus.rb +173 -0
- data/lib/active_merchant/billing/gateways/ebanx.rb +16 -1
- data/lib/active_merchant/billing/gateways/elavon.rb +65 -30
- data/lib/active_merchant/billing/gateways/element.rb +22 -2
- data/lib/active_merchant/billing/gateways/global_collect.rb +130 -26
- data/lib/active_merchant/billing/gateways/ipg.rb +416 -0
- data/lib/active_merchant/billing/gateways/kushki.rb +30 -0
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +6 -3
- data/lib/active_merchant/billing/gateways/merchant_warrior.rb +2 -0
- data/lib/active_merchant/billing/gateways/mit.rb +260 -0
- data/lib/active_merchant/billing/gateways/moka.rb +290 -0
- data/lib/active_merchant/billing/gateways/monei.rb +228 -144
- data/lib/active_merchant/billing/gateways/mundipagg.rb +22 -11
- data/lib/active_merchant/billing/gateways/nmi.rb +29 -10
- data/lib/active_merchant/billing/gateways/orbital.rb +46 -8
- data/lib/active_merchant/billing/gateways/pay_arc.rb +392 -0
- data/lib/active_merchant/billing/gateways/pay_conex.rb +3 -1
- data/lib/active_merchant/billing/gateways/pay_trace.rb +404 -0
- data/lib/active_merchant/billing/gateways/payeezy.rb +4 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +21 -4
- data/lib/active_merchant/billing/gateways/payment_express.rb +2 -2
- data/lib/active_merchant/billing/gateways/paymentez.rb +14 -2
- data/lib/active_merchant/billing/gateways/paysafe.rb +412 -0
- data/lib/active_merchant/billing/gateways/payu_latam.rb +9 -4
- data/lib/active_merchant/billing/gateways/payway_dot_com.rb +3 -3
- data/lib/active_merchant/billing/gateways/pin.rb +31 -4
- data/lib/active_merchant/billing/gateways/priority.rb +347 -0
- data/lib/active_merchant/billing/gateways/realex.rb +18 -0
- data/lib/active_merchant/billing/gateways/redsys.rb +35 -32
- data/lib/active_merchant/billing/gateways/safe_charge.rb +8 -2
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +13 -4
- data/lib/active_merchant/billing/gateways/stripe.rb +27 -7
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +115 -39
- data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -1
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +2 -1
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +21 -7
- data/lib/active_merchant/billing/gateways/vpos.rb +49 -6
- data/lib/active_merchant/billing/gateways/wompi.rb +193 -0
- data/lib/active_merchant/billing/gateways/worldpay.rb +226 -62
- data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
- data/lib/active_merchant/billing/response.rb +4 -0
- data/lib/active_merchant/billing/three_d_secure_eci_mapper.rb +27 -0
- data/lib/active_merchant/billing.rb +1 -0
- data/lib/active_merchant/version.rb +1 -1
- metadata +13 -3
@@ -0,0 +1,347 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class PriorityGateway < Gateway
|
4
|
+
# Sandbox and Production
|
5
|
+
self.test_url = 'https://sandbox.api.mxmerchant.com/checkout/v3/payment'
|
6
|
+
self.live_url = 'https://api.mxmerchant.com/checkout/v3/payment'
|
7
|
+
|
8
|
+
class_attribute :test_url_verify, :live_url_verify, :test_auth, :live_auth, :test_env_verify, :live_env_verify, :test_url_batch, :live_url_batch, :test_url_jwt, :live_url_jwt, :merchant
|
9
|
+
|
10
|
+
# Sandbox and Production - verify card
|
11
|
+
self.test_url_verify = 'https://sandbox-api2.mxmerchant.com/merchant/v1/bin'
|
12
|
+
self.live_url_verify = 'https://api2.mxmerchant.com/merchant/v1/bin'
|
13
|
+
|
14
|
+
# Sandbox and Production - check batch status
|
15
|
+
self.test_url_batch = 'https://sandbox.api.mxmerchant.com/checkout/v3/batch'
|
16
|
+
self.live_url_batch = 'https://api.mxmerchant.com/checkout/v3/batch'
|
17
|
+
|
18
|
+
# Sandbox and Production - generate jwt for verify card url
|
19
|
+
self.test_url_jwt = 'https://sandbox-api2.mxmerchant.com/security/v1/application/merchantId'
|
20
|
+
self.live_url_jwt = 'https://api2.mxmerchant.com/security/v1/application/merchantId'
|
21
|
+
|
22
|
+
self.supported_countries = ['US']
|
23
|
+
self.default_currency = 'USD'
|
24
|
+
self.supported_cardtypes = %i[visa master american_express discover]
|
25
|
+
|
26
|
+
self.homepage_url = 'https://mxmerchant.com/'
|
27
|
+
self.display_name = 'Priority'
|
28
|
+
|
29
|
+
def initialize(options = {})
|
30
|
+
requires!(options, :merchant_id, :key, :secret)
|
31
|
+
super
|
32
|
+
end
|
33
|
+
|
34
|
+
def basic_auth
|
35
|
+
Base64.strict_encode64("#{@options[:key]}:#{@options[:secret]}")
|
36
|
+
end
|
37
|
+
|
38
|
+
def request_headers
|
39
|
+
{
|
40
|
+
'Content-Type' => 'application/json',
|
41
|
+
'Authorization' => "Basic #{basic_auth}"
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def request_verify_headers(jwt)
|
46
|
+
{
|
47
|
+
'Authorization' => "Bearer #{jwt}"
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def purchase(amount, credit_card, options = {})
|
52
|
+
params = {}
|
53
|
+
params['amount'] = localized_amount(amount.to_f, options[:currency])
|
54
|
+
params['authOnly'] = false
|
55
|
+
|
56
|
+
add_credit_card(params, credit_card, 'purchase', options)
|
57
|
+
add_type_merchant_purchase(params, @options[:merchant_id], true, options)
|
58
|
+
commit('purchase', params: params, jwt: options)
|
59
|
+
end
|
60
|
+
|
61
|
+
def authorize(amount, credit_card, options = {})
|
62
|
+
params = {}
|
63
|
+
params['amount'] = localized_amount(amount.to_f, options[:currency])
|
64
|
+
params['authOnly'] = true
|
65
|
+
|
66
|
+
add_credit_card(params, credit_card, 'purchase', options)
|
67
|
+
add_type_merchant_purchase(params, @options[:merchant_id], false, options)
|
68
|
+
commit('purchase', params: params, jwt: options)
|
69
|
+
end
|
70
|
+
|
71
|
+
def refund(amount, authorization, options = {})
|
72
|
+
params = {}
|
73
|
+
params['merchantId'] = @options[:merchant_id]
|
74
|
+
params['paymentToken'] = get_hash(authorization)['payment_token'] || options[:payment_token]
|
75
|
+
# refund amounts must be negative
|
76
|
+
params['amount'] = ('-' + localized_amount(amount.to_f, options[:currency])).to_f
|
77
|
+
commit('refund', params: params, jwt: options)
|
78
|
+
end
|
79
|
+
|
80
|
+
def capture(amount, authorization, options = {})
|
81
|
+
params = {}
|
82
|
+
params['amount'] = localized_amount(amount.to_f, options[:currency])
|
83
|
+
params['authCode'] = options[:authCode]
|
84
|
+
params['merchantId'] = @options[:merchant_id]
|
85
|
+
params['paymentToken'] = get_hash(authorization)['payment_token']
|
86
|
+
params['shouldGetCreditCardLevel'] = true
|
87
|
+
params['source'] = options[:source]
|
88
|
+
params['tenderType'] = 'Card'
|
89
|
+
|
90
|
+
commit('capture', params: params, jwt: options)
|
91
|
+
end
|
92
|
+
|
93
|
+
def void(authorization, options = {})
|
94
|
+
commit('void', iid: get_hash(authorization)['id'], jwt: options)
|
95
|
+
end
|
96
|
+
|
97
|
+
def verify(credit_card, options)
|
98
|
+
jwt = options[:jwt_token]
|
99
|
+
commit('verify', card_number: credit_card.number, jwt: jwt)
|
100
|
+
end
|
101
|
+
|
102
|
+
def supports_scrubbing?
|
103
|
+
true
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_payment_status(batch_id, options)
|
107
|
+
commit('get_payment_status', params: batch_id, jwt: options)
|
108
|
+
end
|
109
|
+
|
110
|
+
def close_batch(batch_id, options)
|
111
|
+
commit('close_batch', params: batch_id, jwt: options)
|
112
|
+
end
|
113
|
+
|
114
|
+
def create_jwt(options)
|
115
|
+
commit('create_jwt', params: @options[:merchant_id], jwt: options)
|
116
|
+
end
|
117
|
+
|
118
|
+
def scrub(transcript)
|
119
|
+
transcript.
|
120
|
+
gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
|
121
|
+
gsub(%r((number\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
|
122
|
+
gsub(%r((cvv\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]')
|
123
|
+
end
|
124
|
+
|
125
|
+
def add_credit_card(params, credit_card, action, options)
|
126
|
+
return unless credit_card&.is_a?(CreditCard)
|
127
|
+
|
128
|
+
card_details = {}
|
129
|
+
|
130
|
+
card_details['expiryMonth'] = format(credit_card.month, :two_digits).to_s
|
131
|
+
card_details['expiryYear'] = format(credit_card.year, :two_digits).to_s
|
132
|
+
card_details['expiryDate'] = exp_date(credit_card)
|
133
|
+
card_details['cardType'] = credit_card.brand
|
134
|
+
card_details['last4'] = credit_card.last_digits
|
135
|
+
card_details['cvv'] = credit_card.verification_value
|
136
|
+
card_details['number'] = credit_card.number
|
137
|
+
|
138
|
+
card_details['entryMode'] = options['entryMode'].blank? ? 'Keyed' : options['entryMode']
|
139
|
+
|
140
|
+
case action
|
141
|
+
when 'purchase'
|
142
|
+
card_details['avsStreet'] = options[:billing_address][:address1] if options[:billing_address]
|
143
|
+
card_details['avsZip'] = options[:billing_address][:zip] if options[:billing_address]
|
144
|
+
when 'refund'
|
145
|
+
card_details['cardId'] = options[:card_id]
|
146
|
+
card_details['cardPresent'] = options[:card_present]
|
147
|
+
card_details['hasContract'] = options[:has_contract]
|
148
|
+
card_details['isCorp'] = options[:is_corp]
|
149
|
+
card_details['isDebit'] = options[:is_debit]
|
150
|
+
card_details['token'] = options[:token]
|
151
|
+
else
|
152
|
+
card_details
|
153
|
+
end
|
154
|
+
|
155
|
+
params['cardAccount'] = card_details
|
156
|
+
end
|
157
|
+
|
158
|
+
def exp_date(credit_card)
|
159
|
+
"#{format(credit_card.month, :two_digits)}/#{format(credit_card.year, :two_digits)}"
|
160
|
+
end
|
161
|
+
|
162
|
+
def purchases
|
163
|
+
[{ taxRate: '0.0000', additionalTaxRate: nil, discountRate: nil }]
|
164
|
+
end
|
165
|
+
|
166
|
+
def add_type_merchant_purchase(params, merchant, is_settle_funds, options)
|
167
|
+
params['cardPresent'] = false
|
168
|
+
params['cardPresentType'] = 'CardNotPresent'
|
169
|
+
params['isAuth'] = true
|
170
|
+
params['isSettleFunds'] = is_settle_funds
|
171
|
+
params['isTicket'] = false
|
172
|
+
|
173
|
+
params['merchantId'] = merchant
|
174
|
+
params['mxAdvantageEnabled'] = false
|
175
|
+
params['paymentType'] = 'Sale'
|
176
|
+
|
177
|
+
params['purchases'] = purchases
|
178
|
+
|
179
|
+
params['shouldGetCreditCardLevel'] = true
|
180
|
+
params['shouldVaultCard'] = true
|
181
|
+
params['source'] = options[:source]
|
182
|
+
params['sourceZip'] = options[:billing_address][:zip] if options[:billing_address]
|
183
|
+
params['taxExempt'] = false
|
184
|
+
params['tenderType'] = 'Card'
|
185
|
+
end
|
186
|
+
|
187
|
+
def commit(action, params: '', iid: '', card_number: nil, jwt: '')
|
188
|
+
response =
|
189
|
+
begin
|
190
|
+
case action
|
191
|
+
when 'void'
|
192
|
+
parse(ssl_request(:delete, url(action, params, ref_number: iid), nil, request_headers))
|
193
|
+
when 'verify'
|
194
|
+
parse(ssl_get(url(action, params, credit_card_number: card_number), request_verify_headers(jwt)))
|
195
|
+
when 'get_payment_status', 'create_jwt'
|
196
|
+
parse(ssl_get(url(action, params, ref_number: iid), request_headers))
|
197
|
+
when 'close_batch'
|
198
|
+
parse(ssl_request(:put, url(action, params, ref_number: iid), nil, request_headers))
|
199
|
+
else
|
200
|
+
parse(ssl_post(url(action, params), post_data(params), request_headers))
|
201
|
+
end
|
202
|
+
rescue ResponseError => e
|
203
|
+
parse(e.response.body)
|
204
|
+
end
|
205
|
+
success = success_from(response, action)
|
206
|
+
response = { 'code' => '204' } if response == ''
|
207
|
+
Response.new(
|
208
|
+
success,
|
209
|
+
message_from(response),
|
210
|
+
response,
|
211
|
+
authorization: success ? authorization_from(response) : nil,
|
212
|
+
error_code: success || response == '' ? nil : error_from(response),
|
213
|
+
test: test?
|
214
|
+
)
|
215
|
+
end
|
216
|
+
|
217
|
+
def handle_response(response)
|
218
|
+
if response.code != '204' && (200...300).cover?(response.code.to_i)
|
219
|
+
response.body
|
220
|
+
elsif response.code == '204' || response == ''
|
221
|
+
response.body = { 'code' => '204' }
|
222
|
+
else
|
223
|
+
raise ResponseError.new(response)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def url(action, params, ref_number: '', credit_card_number: nil)
|
228
|
+
case action
|
229
|
+
when 'void'
|
230
|
+
base_url + "/#{ref_number}?force=true"
|
231
|
+
when 'verify'
|
232
|
+
(verify_url + '?search=') + credit_card_number.to_s[0..6]
|
233
|
+
when 'get_payment_status', 'close_batch'
|
234
|
+
batch_url + "/#{params}"
|
235
|
+
when 'create_jwt'
|
236
|
+
jwt_url + "/#{params}/token"
|
237
|
+
else
|
238
|
+
base_url + '?includeCustomerMatches=false&echo=true'
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def base_url
|
243
|
+
test? ? test_url : live_url
|
244
|
+
end
|
245
|
+
|
246
|
+
def verify_url
|
247
|
+
test? ? self.test_url_verify : self.live_url_verify
|
248
|
+
end
|
249
|
+
|
250
|
+
def jwt_url
|
251
|
+
test? ? self.test_url_jwt : self.live_url_jwt
|
252
|
+
end
|
253
|
+
|
254
|
+
def batch_url
|
255
|
+
test? ? self.test_url_batch : self.live_url_batch
|
256
|
+
end
|
257
|
+
|
258
|
+
def parse(body)
|
259
|
+
return body if body['code'] == '204'
|
260
|
+
|
261
|
+
JSON.parse(body)
|
262
|
+
rescue JSON::ParserError
|
263
|
+
message = 'Invalid JSON response received from Priority Gateway. Please contact Priority Gateway if you continue to receive this message.'
|
264
|
+
message += " (The raw response returned by the API was #{body.inspect})"
|
265
|
+
{
|
266
|
+
'message' => message
|
267
|
+
}
|
268
|
+
end
|
269
|
+
|
270
|
+
def success_from(response, action)
|
271
|
+
success = response['status'] == 'Approved' || response['status'] == 'Open' if response['status']
|
272
|
+
success = response['code'] == '204' if action == 'void'
|
273
|
+
success = !response['bank'].empty? if action == 'verify' && response['bank']
|
274
|
+
success
|
275
|
+
end
|
276
|
+
|
277
|
+
def message_from(response)
|
278
|
+
return response['details'][0] if response['details'] && response['details'][0]
|
279
|
+
|
280
|
+
response['authMessage'] || response['message'] || response['status']
|
281
|
+
end
|
282
|
+
|
283
|
+
def authorization_from(response)
|
284
|
+
{
|
285
|
+
'payment_token' => response['paymentToken'],
|
286
|
+
'id' => response['id']
|
287
|
+
}
|
288
|
+
end
|
289
|
+
|
290
|
+
def error_from(response)
|
291
|
+
response['errorCode'] || response['status']
|
292
|
+
end
|
293
|
+
|
294
|
+
def post_data(params)
|
295
|
+
params.to_json
|
296
|
+
end
|
297
|
+
|
298
|
+
def add_pos_data(options)
|
299
|
+
pos_options = {}
|
300
|
+
pos_options['panCaptureMethod'] = options[:pan_capture_method]
|
301
|
+
|
302
|
+
pos_options
|
303
|
+
end
|
304
|
+
|
305
|
+
def add_purchases_data(options)
|
306
|
+
purchases = {}
|
307
|
+
|
308
|
+
purchases['dateCreated'] = options[:date_created]
|
309
|
+
purchases['iId'] = options[:i_id]
|
310
|
+
purchases['transactionIId'] = options[:transaction_i_id]
|
311
|
+
purchases['transactionId'] = options[:transaction_id]
|
312
|
+
purchases['name'] = options[:name]
|
313
|
+
purchases['description'] = options[:description]
|
314
|
+
purchases['code'] = options[:code]
|
315
|
+
purchases['unitOfMeasure'] = options[:unit_of_measure]
|
316
|
+
purchases['unitPrice'] = options[:unit_price]
|
317
|
+
purchases['quantity'] = options[:quantity]
|
318
|
+
purchases['taxRate'] = options[:tax_rate]
|
319
|
+
purchases['taxAmount'] = options[:tax_amount]
|
320
|
+
purchases['discountRate'] = options[:discount_rate]
|
321
|
+
purchases['discountAmount'] = options[:discount_amt]
|
322
|
+
purchases['extendedAmount'] = options[:extended_amt]
|
323
|
+
purchases['lineItemId'] = options[:line_item_id]
|
324
|
+
|
325
|
+
purchase_arr = []
|
326
|
+
purchase_arr[0] = purchases
|
327
|
+
purchase_arr
|
328
|
+
end
|
329
|
+
|
330
|
+
def add_risk_data(options)
|
331
|
+
risk = {}
|
332
|
+
risk['cvvResponseCode'] = options[:cvv_response_code]
|
333
|
+
risk['cvvResponse'] = options[:cvv_response]
|
334
|
+
risk['cvvMatch'] = options[:cvv_match]
|
335
|
+
risk['avsResponse'] = options[:avs_response]
|
336
|
+
risk['avsAddressMatch'] = options[:avs_address_match]
|
337
|
+
risk['avsZipMatch'] = options[:avs_zip_match]
|
338
|
+
|
339
|
+
risk
|
340
|
+
end
|
341
|
+
|
342
|
+
def get_hash(string)
|
343
|
+
JSON.parse(string.gsub('=>', ':'))
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
@@ -151,6 +151,7 @@ module ActiveMerchant
|
|
151
151
|
else
|
152
152
|
add_three_d_secure(xml, options)
|
153
153
|
end
|
154
|
+
add_stored_credential(xml, options)
|
154
155
|
add_comments(xml, options)
|
155
156
|
add_address_and_customer_info(xml, options)
|
156
157
|
end
|
@@ -323,6 +324,23 @@ module ActiveMerchant
|
|
323
324
|
end
|
324
325
|
end
|
325
326
|
|
327
|
+
def add_stored_credential(xml, options)
|
328
|
+
return unless stored_credential = options[:stored_credential]
|
329
|
+
|
330
|
+
xml.tag! 'storedcredential' do
|
331
|
+
xml.tag! 'type', stored_credential_type(stored_credential[:reason_type])
|
332
|
+
xml.tag! 'initiator', stored_credential[:initiator]
|
333
|
+
xml.tag! 'sequence', stored_credential[:initial_transaction] ? 'first' : 'subsequent'
|
334
|
+
xml.tag! 'srd', stored_credential[:network_transaction_id]
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def stored_credential_type(reason)
|
339
|
+
return 'oneoff' if reason == 'unscheduled'
|
340
|
+
|
341
|
+
reason
|
342
|
+
end
|
343
|
+
|
326
344
|
def format_address_code(address)
|
327
345
|
code = [address[:zip].to_s, address[:address1].to_s + address[:address2].to_s]
|
328
346
|
code.collect { |e| e.gsub(/\D/, '') }.reject(&:empty?).join('|')
|
@@ -203,7 +203,7 @@ module ActiveMerchant #:nodoc:
|
|
203
203
|
add_order(data, options[:order_id])
|
204
204
|
add_payment(data, payment)
|
205
205
|
add_external_mpi_fields(data, options)
|
206
|
-
|
206
|
+
add_three_ds_data(data, options) if options[:execute_threed]
|
207
207
|
add_stored_credential_options(data, options)
|
208
208
|
data[:description] = options[:description]
|
209
209
|
data[:store_in_vault] = options[:store]
|
@@ -222,7 +222,7 @@ module ActiveMerchant #:nodoc:
|
|
222
222
|
add_order(data, options[:order_id])
|
223
223
|
add_payment(data, payment)
|
224
224
|
add_external_mpi_fields(data, options)
|
225
|
-
|
225
|
+
add_three_ds_data(data, options) if options[:execute_threed]
|
226
226
|
add_stored_credential_options(data, options)
|
227
227
|
data[:description] = options[:description]
|
228
228
|
data[:store_in_vault] = options[:store]
|
@@ -312,7 +312,7 @@ module ActiveMerchant #:nodoc:
|
|
312
312
|
test? ? test_url : live_url
|
313
313
|
end
|
314
314
|
|
315
|
-
def
|
315
|
+
def webservice_url
|
316
316
|
test? ? 'https://sis-t.redsys.es:25443/sis/services/SerClsWSEntradaV2' : 'https://sis.redsys.es/sis/services/SerClsWSEntradaV2'
|
317
317
|
end
|
318
318
|
|
@@ -372,43 +372,51 @@ module ActiveMerchant #:nodoc:
|
|
372
372
|
end
|
373
373
|
end
|
374
374
|
|
375
|
-
def
|
376
|
-
data[:
|
375
|
+
def add_three_ds_data(data, options)
|
376
|
+
data[:three_ds_data] = { threeDSInfo: 'CardData' } if options[:execute_threed] == true
|
377
377
|
end
|
378
378
|
|
379
|
-
def
|
380
|
-
|
381
|
-
return '
|
382
|
-
|
379
|
+
def determine_peticion_type(data)
|
380
|
+
three_ds_info = data.dig(:three_ds_data, :threeDSInfo)
|
381
|
+
return 'iniciaPeticion' if three_ds_info == 'CardData'
|
382
|
+
return 'trataPeticion' if three_ds_info == 'AuthenticationData' ||
|
383
|
+
three_ds_info == 'ChallengeResponse' ||
|
384
|
+
data[:sca_exemption] == 'MIT'
|
385
|
+
end
|
386
|
+
|
387
|
+
def use_webservice_endpoint?(data, options)
|
388
|
+
options[:use_webservice_endpoint].to_s == 'true' || data[:three_ds_data] || data[:sca_exemption] == 'MIT'
|
383
389
|
end
|
384
390
|
|
385
391
|
def commit(data, options = {})
|
386
|
-
|
387
|
-
|
392
|
+
xmlreq = xml_request_from(data, options)
|
393
|
+
|
394
|
+
if use_webservice_endpoint?(data, options)
|
395
|
+
peticion_type = determine_peticion_type(data)
|
396
|
+
|
388
397
|
request = <<-REQUEST
|
389
398
|
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://webservice.sis.sermepa.es" xmlns:intf="http://webservice.sis.sermepa.es" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
|
390
399
|
<soapenv:Header/>
|
391
400
|
<soapenv:Body>
|
392
|
-
<intf:#{
|
401
|
+
<intf:#{peticion_type} xmlns:intf="http://webservice.sis.sermepa.es">
|
393
402
|
<intf:datoEntrada>
|
394
|
-
<![CDATA[#{
|
403
|
+
<![CDATA[#{xmlreq}]]>
|
395
404
|
</intf:datoEntrada>
|
396
|
-
</intf:#{
|
405
|
+
</intf:#{peticion_type}>
|
397
406
|
</soapenv:Body>
|
398
407
|
</soapenv:Envelope>
|
399
408
|
REQUEST
|
400
|
-
parse(ssl_post(
|
409
|
+
parse(ssl_post(webservice_url, request, headers(peticion_type)), peticion_type)
|
401
410
|
else
|
402
|
-
|
403
|
-
parse(ssl_post(url, "entrada=#{CGI.escape(xmlreq)}", headers), action)
|
411
|
+
parse(ssl_post(url, "entrada=#{CGI.escape(xmlreq)}", headers), peticion_type)
|
404
412
|
end
|
405
413
|
end
|
406
414
|
|
407
|
-
def headers(
|
408
|
-
if
|
415
|
+
def headers(peticion_type = nil)
|
416
|
+
if peticion_type
|
409
417
|
{
|
410
418
|
'Content-Type' => 'text/xml',
|
411
|
-
'SOAPAction' =>
|
419
|
+
'SOAPAction' => peticion_type
|
412
420
|
}
|
413
421
|
else
|
414
422
|
{
|
@@ -470,14 +478,9 @@ module ActiveMerchant #:nodoc:
|
|
470
478
|
xml.target!
|
471
479
|
end
|
472
480
|
|
473
|
-
# Template Method to allow AM API clients to override decision to escape, based on their own criteria.
|
474
|
-
def escape_special_chars?(data, options = {})
|
475
|
-
data[:threeds]
|
476
|
-
end
|
477
|
-
|
478
481
|
def build_merchant_data(xml, data, options = {})
|
479
482
|
# See https://sis-t.redsys.es:25443/sis/services/SerClsWSEntradaV2/wsdl/SerClsWSEntradaV2.wsdl
|
480
|
-
# (which results from calling #
|
483
|
+
# (which results from calling #webservice_url + '?WSDL', https://sis-t.redsys.es:25443/sis/services/SerClsWSEntradaV2?WSDL)
|
481
484
|
xml.DATOSENTRADA do
|
482
485
|
# Basic elements
|
483
486
|
xml.DS_Version 0.1
|
@@ -485,7 +488,7 @@ module ActiveMerchant #:nodoc:
|
|
485
488
|
xml.DS_MERCHANT_AMOUNT data[:amount]
|
486
489
|
xml.DS_MERCHANT_ORDER data[:order_id]
|
487
490
|
xml.DS_MERCHANT_TRANSACTIONTYPE data[:action]
|
488
|
-
if data[:description] &&
|
491
|
+
if data[:description] && use_webservice_endpoint?(data, options)
|
489
492
|
xml.DS_MERCHANT_PRODUCTDESCRIPTION CGI.escape(data[:description])
|
490
493
|
else
|
491
494
|
xml.DS_MERCHANT_PRODUCTDESCRIPTION data[:description]
|
@@ -494,17 +497,17 @@ module ActiveMerchant #:nodoc:
|
|
494
497
|
xml.DS_MERCHANT_MERCHANTCODE @options[:login]
|
495
498
|
xml.DS_MERCHANT_MERCHANTSIGNATURE build_signature(data) unless sha256_authentication?
|
496
499
|
|
497
|
-
|
498
|
-
if
|
500
|
+
peticion_type = determine_peticion_type(data) if data[:three_ds_data]
|
501
|
+
if peticion_type == 'iniciaPeticion' && data[:sca_exemption]
|
499
502
|
xml.DS_MERCHANT_EXCEP_SCA 'Y'
|
500
503
|
else
|
501
504
|
xml.DS_MERCHANT_EXCEP_SCA data[:sca_exemption] if data[:sca_exemption]
|
502
|
-
xml.DS_MERCHANT_DIRECTPAYMENT data[:sca_exemption_direct_payment_enabled] if data[:
|
505
|
+
xml.DS_MERCHANT_DIRECTPAYMENT data[:sca_exemption_direct_payment_enabled] || 'true' if data[:sca_exemption] == 'MIT'
|
503
506
|
end
|
504
507
|
|
505
508
|
# Only when card is present
|
506
509
|
if data[:card]
|
507
|
-
if data[:card][:name] &&
|
510
|
+
if data[:card][:name] && use_webservice_endpoint?(data, options)
|
508
511
|
xml.DS_MERCHANT_TITULAR CGI.escape(data[:card][:name])
|
509
512
|
else
|
510
513
|
xml.DS_MERCHANT_TITULAR data[:card][:name]
|
@@ -525,7 +528,7 @@ module ActiveMerchant #:nodoc:
|
|
525
528
|
# Requires account configuration to be able to use
|
526
529
|
xml.DS_MERCHANT_DIRECTPAYMENT 'moto' if options.dig(:moto) && options.dig(:metadata, :manual_entry)
|
527
530
|
|
528
|
-
xml.DS_MERCHANT_EMV3DS data[:
|
531
|
+
xml.DS_MERCHANT_EMV3DS data[:three_ds_data].to_json if data[:three_ds_data]
|
529
532
|
|
530
533
|
if options[:stored_credential]
|
531
534
|
xml.DS_MERCHANT_COF_INI data[:DS_MERCHANT_COF_INI]
|
@@ -62,6 +62,7 @@ module ActiveMerchant #:nodoc:
|
|
62
62
|
post[:sg_CCToken] = token
|
63
63
|
post[:sg_ExpMonth] = exp_month
|
64
64
|
post[:sg_ExpYear] = exp_year
|
65
|
+
post[:sg_Email] = options[:email]
|
65
66
|
|
66
67
|
commit(post)
|
67
68
|
end
|
@@ -126,9 +127,11 @@ module ActiveMerchant #:nodoc:
|
|
126
127
|
private
|
127
128
|
|
128
129
|
def add_transaction_data(trans_type, post, money, options)
|
130
|
+
currency = options[:currency] || currency(money)
|
131
|
+
|
129
132
|
post[:sg_TransType] = trans_type
|
130
|
-
post[:sg_Currency] =
|
131
|
-
post[:sg_Amount] =
|
133
|
+
post[:sg_Currency] = currency
|
134
|
+
post[:sg_Amount] = localized_amount(money, currency)
|
132
135
|
post[:sg_ClientLoginID] = @options[:client_login_id]
|
133
136
|
post[:sg_ClientPassword] = @options[:client_password]
|
134
137
|
post[:sg_ResponseFormat] = '4'
|
@@ -143,6 +146,8 @@ module ActiveMerchant #:nodoc:
|
|
143
146
|
post[:sg_Descriptor] = options[:merchant_descriptor] if options[:merchant_descriptor]
|
144
147
|
post[:sg_MerchantPhoneNumber] = options[:merchant_phone_number] if options[:merchant_phone_number]
|
145
148
|
post[:sg_MerchantName] = options[:merchant_name] if options[:merchant_name]
|
149
|
+
post[:sg_ProductID] = options[:product_id] if options[:product_id]
|
150
|
+
post[:sg_NotUseCVV] = options[:not_use_cvv].to_s == 'true' ? 1 : 0 unless options[:not_use_cvv].nil?
|
146
151
|
end
|
147
152
|
|
148
153
|
def add_payment(post, payment, options = {})
|
@@ -185,6 +190,7 @@ module ActiveMerchant #:nodoc:
|
|
185
190
|
post[:sg_Xid] = options[:three_d_secure][:xid]
|
186
191
|
post[:sg_IsExternalMPI] = 1
|
187
192
|
post[:sg_EnablePartialApproval] = options[:is_partial_approval]
|
193
|
+
post[:sg_challengePreference] = options[:three_d_secure][:challenge_preference] if options[:three_d_secure][:challenge_preference]
|
188
194
|
end
|
189
195
|
|
190
196
|
def parse(xml)
|
@@ -254,11 +254,20 @@ module ActiveMerchant #:nodoc:
|
|
254
254
|
end
|
255
255
|
|
256
256
|
def childnode_to_response(response, node, childnode)
|
257
|
-
|
258
|
-
|
259
|
-
|
257
|
+
node_name = node.name.downcase
|
258
|
+
childnode_name = childnode.name.downcase
|
259
|
+
composed_name = "#{node_name}_#{childnode_name}"
|
260
|
+
|
261
|
+
childnodes_present = !childnode.elements.empty?
|
262
|
+
|
263
|
+
if childnodes_present && composed_name == 'payment_method_data'
|
264
|
+
response[composed_name.to_sym] = Hash.from_xml(childnode.to_s).values.first
|
265
|
+
elsif childnodes_present && node_name == 'gateway_specific_response_fields'
|
266
|
+
response[node_name.to_sym] = {
|
267
|
+
childnode_name => Hash.from_xml(childnode.to_s).values.first
|
268
|
+
}
|
260
269
|
else
|
261
|
-
response[
|
270
|
+
response[composed_name.to_sym] = childnode.text
|
262
271
|
end
|
263
272
|
end
|
264
273
|
|