activemerchant 1.116.0 → 1.121.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 +148 -1
- data/README.md +4 -2
- data/lib/active_merchant/billing/check.rb +10 -0
- data/lib/active_merchant/billing/credit_card.rb +3 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +80 -15
- data/lib/active_merchant/billing/gateways/adyen.rb +29 -8
- data/lib/active_merchant/billing/gateways/authorize_net.rb +37 -1
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +4 -0
- data/lib/active_merchant/billing/gateways/blue_snap.rb +3 -1
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +54 -7
- data/lib/active_merchant/billing/gateways/cashnet.rb +7 -2
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +33 -2
- data/lib/active_merchant/billing/gateways/credorax.rb +30 -14
- data/lib/active_merchant/billing/gateways/cyber_source.rb +51 -8
- data/lib/active_merchant/billing/gateways/d_local.rb +1 -1
- data/lib/active_merchant/billing/gateways/decidir.rb +22 -2
- data/lib/active_merchant/billing/gateways/elavon.rb +54 -2
- data/lib/active_merchant/billing/gateways/eway_rapid.rb +13 -0
- data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +17 -6
- data/lib/active_merchant/billing/gateways/forte.rb +12 -0
- data/lib/active_merchant/billing/gateways/global_collect.rb +25 -6
- data/lib/active_merchant/billing/gateways/hps.rb +65 -2
- data/lib/active_merchant/billing/gateways/litle.rb +21 -5
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +2 -2
- data/lib/active_merchant/billing/gateways/netbanx.rb +37 -2
- data/lib/active_merchant/billing/gateways/orbital.rb +178 -45
- data/lib/active_merchant/billing/gateways/payeezy.rb +53 -11
- data/lib/active_merchant/billing/gateways/payment_express.rb +10 -5
- data/lib/active_merchant/billing/gateways/paymentez.rb +21 -1
- data/lib/active_merchant/billing/gateways/paypal.rb +10 -2
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +1 -0
- data/lib/active_merchant/billing/gateways/payway_dot_com.rb +253 -0
- data/lib/active_merchant/billing/gateways/pin.rb +11 -0
- data/lib/active_merchant/billing/gateways/qvalent.rb +23 -9
- data/lib/active_merchant/billing/gateways/redsys.rb +101 -5
- data/lib/active_merchant/billing/gateways/safe_charge.rb +39 -6
- data/lib/active_merchant/billing/gateways/stripe.rb +9 -9
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +82 -25
- data/lib/active_merchant/billing/gateways/vpos.rb +177 -0
- data/lib/active_merchant/billing/gateways/worldpay.rb +31 -14
- data/lib/active_merchant/billing/response.rb +2 -1
- data/lib/active_merchant/version.rb +1 -1
- data/lib/certs/cacert.pem +1582 -2431
- metadata +5 -3
@@ -30,6 +30,7 @@ module ActiveMerchant #:nodoc:
|
|
30
30
|
add_address(post, creditcard, options)
|
31
31
|
add_capture(post, options)
|
32
32
|
add_metadata(post, options)
|
33
|
+
add_3ds(post, options)
|
33
34
|
|
34
35
|
commit(:post, 'charges', post, options)
|
35
36
|
end
|
@@ -158,6 +159,16 @@ module ActiveMerchant #:nodoc:
|
|
158
159
|
post[:metadata] = options[:metadata] if options[:metadata]
|
159
160
|
end
|
160
161
|
|
162
|
+
def add_3ds(post, options)
|
163
|
+
if options[:three_d_secure]
|
164
|
+
post[:three_d_secure] = {}
|
165
|
+
post[:three_d_secure][:version] = options[:three_d_secure][:version] if options[:three_d_secure][:version]
|
166
|
+
post[:three_d_secure][:eci] = options[:three_d_secure][:eci] if options[:three_d_secure][:eci]
|
167
|
+
post[:three_d_secure][:cavv] = options[:three_d_secure][:cavv] if options[:three_d_secure][:cavv]
|
168
|
+
post[:three_d_secure][:transaction_id] = options[:three_d_secure][:ds_transaction_id] || options[:three_d_secure][:xid]
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
161
172
|
def headers(params = {})
|
162
173
|
result = {
|
163
174
|
'Content-Type' => 'application/json',
|
@@ -17,7 +17,7 @@ module ActiveMerchant #:nodoc:
|
|
17
17
|
}
|
18
18
|
|
19
19
|
def initialize(options = {})
|
20
|
-
requires!(options, :username, :password, :merchant, :pem
|
20
|
+
requires!(options, :username, :password, :merchant, :pem)
|
21
21
|
super
|
22
22
|
end
|
23
23
|
|
@@ -30,6 +30,7 @@ module ActiveMerchant #:nodoc:
|
|
30
30
|
add_stored_credential_data(post, payment_method, options)
|
31
31
|
add_customer_data(post, options)
|
32
32
|
add_soft_descriptors(post, options)
|
33
|
+
add_customer_reference(post, options)
|
33
34
|
|
34
35
|
commit('capture', post)
|
35
36
|
end
|
@@ -43,6 +44,7 @@ module ActiveMerchant #:nodoc:
|
|
43
44
|
add_stored_credential_data(post, payment_method, options)
|
44
45
|
add_customer_data(post, options)
|
45
46
|
add_soft_descriptors(post, options)
|
47
|
+
add_customer_reference(post, options)
|
46
48
|
|
47
49
|
commit('preauth', post)
|
48
50
|
end
|
@@ -53,6 +55,7 @@ module ActiveMerchant #:nodoc:
|
|
53
55
|
add_reference(post, authorization, options)
|
54
56
|
add_customer_data(post, options)
|
55
57
|
add_soft_descriptors(post, options)
|
58
|
+
add_customer_reference(post, options)
|
56
59
|
|
57
60
|
commit('captureWithoutAuth', post)
|
58
61
|
end
|
@@ -64,6 +67,7 @@ module ActiveMerchant #:nodoc:
|
|
64
67
|
add_customer_data(post, options)
|
65
68
|
add_soft_descriptors(post, options)
|
66
69
|
post['order.ECI'] = options[:eci] || 'SSL'
|
70
|
+
add_customer_reference(post, options)
|
67
71
|
|
68
72
|
commit('refund', post)
|
69
73
|
end
|
@@ -76,6 +80,7 @@ module ActiveMerchant #:nodoc:
|
|
76
80
|
add_payment_method(post, payment_method)
|
77
81
|
add_customer_data(post, options)
|
78
82
|
add_soft_descriptors(post, options)
|
83
|
+
add_customer_reference(post, options)
|
79
84
|
|
80
85
|
commit('refund', post)
|
81
86
|
end
|
@@ -85,6 +90,7 @@ module ActiveMerchant #:nodoc:
|
|
85
90
|
add_reference(post, authorization, options)
|
86
91
|
add_customer_data(post, options)
|
87
92
|
add_soft_descriptors(post, options)
|
93
|
+
add_customer_reference(post, options)
|
88
94
|
|
89
95
|
commit('reversal', post)
|
90
96
|
end
|
@@ -92,7 +98,7 @@ module ActiveMerchant #:nodoc:
|
|
92
98
|
def store(payment_method, options = {})
|
93
99
|
post = {}
|
94
100
|
add_payment_method(post, payment_method)
|
95
|
-
add_card_reference(post)
|
101
|
+
add_card_reference(post, options)
|
96
102
|
|
97
103
|
commit('registerAccount', post)
|
98
104
|
end
|
@@ -149,12 +155,16 @@ module ActiveMerchant #:nodoc:
|
|
149
155
|
return unless payment_method.brand == 'visa'
|
150
156
|
|
151
157
|
stored_credential = options[:stored_credential]
|
152
|
-
if stored_credential[:
|
153
|
-
|
154
|
-
|
158
|
+
if stored_credential[:reason_type] == 'unscheduled'
|
159
|
+
if stored_credential[:initiator] == 'merchant'
|
160
|
+
post['card.storedCredentialUsage'] = 'UNSCHEDULED_MIT'
|
161
|
+
elsif stored_credential[:initiator] == 'customer'
|
162
|
+
post['card.storedCredentialUsage'] = 'UNSCHEDULED_CIT'
|
163
|
+
end
|
164
|
+
elsif stored_credential[:reason_type] == 'recurring'
|
155
165
|
post['card.storedCredentialUsage'] = 'RECURRING'
|
156
|
-
elsif stored_credential[:reason_type] == '
|
157
|
-
post['card.storedCredentialUsage'] = '
|
166
|
+
elsif stored_credential[:reason_type] == 'installment'
|
167
|
+
post['card.storedCredentialUsage'] = 'INSTALLMENT'
|
158
168
|
end
|
159
169
|
end
|
160
170
|
|
@@ -181,8 +191,12 @@ module ActiveMerchant #:nodoc:
|
|
181
191
|
post['card.CVN'] = payment_method.verification_value
|
182
192
|
end
|
183
193
|
|
184
|
-
def add_card_reference(post)
|
185
|
-
post['customer.customerReferenceNumber'] = options[:order_id]
|
194
|
+
def add_card_reference(post, options)
|
195
|
+
post['customer.customerReferenceNumber'] = options[:customer_reference_number] || options[:order_id]
|
196
|
+
end
|
197
|
+
|
198
|
+
def add_customer_reference(post, options)
|
199
|
+
post['customer.customerReferenceNumber'] = options[:customer_reference_number] if options[:customer_reference_number]
|
186
200
|
end
|
187
201
|
|
188
202
|
def add_reference(post, authorization, options)
|
@@ -126,6 +126,7 @@ module ActiveMerchant #:nodoc:
|
|
126
126
|
184 => 'Authentication error',
|
127
127
|
190 => 'Refusal with no specific reason',
|
128
128
|
191 => 'Expiry date incorrect',
|
129
|
+
195 => 'Requires SCA authentication',
|
129
130
|
|
130
131
|
201 => 'Card expired',
|
131
132
|
202 => 'Card blocked temporarily or under suspicion of fraud',
|
@@ -170,6 +171,10 @@ module ActiveMerchant #:nodoc:
|
|
170
171
|
9914 => 'KO Confirmation'
|
171
172
|
}
|
172
173
|
|
174
|
+
# Expected values as per documentation
|
175
|
+
THREE_DS_V1 = '1.0.2'
|
176
|
+
THREE_DS_V2 = '2.1.0'
|
177
|
+
|
173
178
|
# Creates a new instance
|
174
179
|
#
|
175
180
|
# Redsys requires a login and secret_key, and optionally also accepts a
|
@@ -197,10 +202,13 @@ module ActiveMerchant #:nodoc:
|
|
197
202
|
add_amount(data, money, options)
|
198
203
|
add_order(data, options[:order_id])
|
199
204
|
add_payment(data, payment)
|
205
|
+
add_external_mpi_fields(data, options)
|
200
206
|
add_threeds(data, options) if options[:execute_threed]
|
207
|
+
add_stored_credential_options(data, options)
|
201
208
|
data[:description] = options[:description]
|
202
209
|
data[:store_in_vault] = options[:store]
|
203
210
|
data[:sca_exemption] = options[:sca_exemption]
|
211
|
+
data[:sca_exemption_direct_payment_enabled] = options[:sca_exemption_direct_payment_enabled]
|
204
212
|
|
205
213
|
commit data, options
|
206
214
|
end
|
@@ -213,10 +221,13 @@ module ActiveMerchant #:nodoc:
|
|
213
221
|
add_amount(data, money, options)
|
214
222
|
add_order(data, options[:order_id])
|
215
223
|
add_payment(data, payment)
|
224
|
+
add_external_mpi_fields(data, options)
|
216
225
|
add_threeds(data, options) if options[:execute_threed]
|
226
|
+
add_stored_credential_options(data, options)
|
217
227
|
data[:description] = options[:description]
|
218
228
|
data[:store_in_vault] = options[:store]
|
219
229
|
data[:sca_exemption] = options[:sca_exemption]
|
230
|
+
data[:sca_exemption_direct_payment_enabled] = options[:sca_exemption_direct_payment_enabled]
|
220
231
|
|
221
232
|
commit data, options
|
222
233
|
end
|
@@ -321,6 +332,46 @@ module ActiveMerchant #:nodoc:
|
|
321
332
|
end
|
322
333
|
end
|
323
334
|
|
335
|
+
def add_external_mpi_fields(data, options)
|
336
|
+
return unless options[:three_d_secure]
|
337
|
+
|
338
|
+
if options[:three_d_secure][:version] == THREE_DS_V2
|
339
|
+
data[:threeDSServerTransID] = options[:three_d_secure][:three_ds_server_trans_id] if options[:three_d_secure][:three_ds_server_trans_id]
|
340
|
+
data[:dsTransID] = options[:three_d_secure][:ds_transaction_id] if options[:three_d_secure][:ds_transaction_id]
|
341
|
+
data[:authenticacionValue] = options[:three_d_secure][:cavv] if options[:three_d_secure][:cavv]
|
342
|
+
data[:protocolVersion] = options[:three_d_secure][:version] if options[:three_d_secure][:version]
|
343
|
+
data[:authenticacionMethod] = options[:authentication_method] if options[:authentication_method]
|
344
|
+
data[:authenticacionType] = options[:authentication_type] if options[:authentication_type]
|
345
|
+
data[:authenticacionFlow] = options[:authentication_flow] if options[:authentication_flow]
|
346
|
+
data[:eci_v2] = options[:three_d_secure][:eci] if options[:three_d_secure][:eci]
|
347
|
+
elsif options[:three_d_secure][:version] == THREE_DS_V1
|
348
|
+
data[:txid] = options[:three_d_secure][:xid] if options[:three_d_secure][:xid]
|
349
|
+
data[:cavv] = options[:three_d_secure][:cavv] if options[:three_d_secure][:cavv]
|
350
|
+
data[:eci_v1] = options[:three_d_secure][:eci] if options[:three_d_secure][:eci]
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
def add_stored_credential_options(data, options)
|
355
|
+
return unless options[:stored_credential]
|
356
|
+
|
357
|
+
case options[:stored_credential][:initial_transaction]
|
358
|
+
when true
|
359
|
+
data[:DS_MERCHANT_COF_INI] = 'S'
|
360
|
+
when false
|
361
|
+
data[:DS_MERCHANT_COF_INI] = 'N'
|
362
|
+
data[:DS_MERCHANT_COF_TXNID] = options[:stored_credential][:network_transaction_id] if options[:stored_credential][:network_transaction_id]
|
363
|
+
end
|
364
|
+
|
365
|
+
case options[:stored_credential][:reason_type]
|
366
|
+
when 'recurring'
|
367
|
+
data[:DS_MERCHANT_COF_TYPE] = 'R'
|
368
|
+
when 'installment'
|
369
|
+
data[:DS_MERCHANT_COF_TYPE] = 'I'
|
370
|
+
when 'unscheduled'
|
371
|
+
return
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
324
375
|
def add_threeds(data, options)
|
325
376
|
data[:threeds] = { threeDSInfo: 'CardData' } if options[:execute_threed] == true
|
326
377
|
end
|
@@ -348,7 +399,8 @@ module ActiveMerchant #:nodoc:
|
|
348
399
|
REQUEST
|
349
400
|
parse(ssl_post(threeds_url, request, headers(action)), action)
|
350
401
|
else
|
351
|
-
|
402
|
+
xmlreq = xml_request_from(data, options)
|
403
|
+
parse(ssl_post(url, "entrada=#{CGI.escape(xmlreq)}", headers), action)
|
352
404
|
end
|
353
405
|
end
|
354
406
|
|
@@ -418,7 +470,14 @@ module ActiveMerchant #:nodoc:
|
|
418
470
|
xml.target!
|
419
471
|
end
|
420
472
|
|
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
|
+
|
421
478
|
def build_merchant_data(xml, data, options = {})
|
479
|
+
# See https://sis-t.redsys.es:25443/sis/services/SerClsWSEntradaV2/wsdl/SerClsWSEntradaV2.wsdl
|
480
|
+
# (which results from calling #threeds_url + '?WSDL', https://sis-t.redsys.es:25443/sis/services/SerClsWSEntradaV2?WSDL)
|
422
481
|
xml.DATOSENTRADA do
|
423
482
|
# Basic elements
|
424
483
|
xml.DS_Version 0.1
|
@@ -426,7 +485,7 @@ module ActiveMerchant #:nodoc:
|
|
426
485
|
xml.DS_MERCHANT_AMOUNT data[:amount]
|
427
486
|
xml.DS_MERCHANT_ORDER data[:order_id]
|
428
487
|
xml.DS_MERCHANT_TRANSACTIONTYPE data[:action]
|
429
|
-
if data[:description] && data
|
488
|
+
if data[:description] && escape_special_chars?(data, options)
|
430
489
|
xml.DS_MERCHANT_PRODUCTDESCRIPTION CGI.escape(data[:description])
|
431
490
|
else
|
432
491
|
xml.DS_MERCHANT_PRODUCTDESCRIPTION data[:description]
|
@@ -434,11 +493,18 @@ module ActiveMerchant #:nodoc:
|
|
434
493
|
xml.DS_MERCHANT_TERMINAL options[:terminal] || @options[:terminal]
|
435
494
|
xml.DS_MERCHANT_MERCHANTCODE @options[:login]
|
436
495
|
xml.DS_MERCHANT_MERCHANTSIGNATURE build_signature(data) unless sha256_authentication?
|
437
|
-
|
496
|
+
|
497
|
+
action = determine_3ds_action(data[:threeds]) if data[:threeds]
|
498
|
+
if action == 'iniciaPeticion' && data[:sca_exemption]
|
499
|
+
xml.DS_MERCHANT_EXCEP_SCA 'Y'
|
500
|
+
else
|
501
|
+
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[:sca_exemption_direct_payment_enabled]
|
503
|
+
end
|
438
504
|
|
439
505
|
# Only when card is present
|
440
506
|
if data[:card]
|
441
|
-
if data[:card][:name] && data
|
507
|
+
if data[:card][:name] && escape_special_chars?(data, options)
|
442
508
|
xml.DS_MERCHANT_TITULAR CGI.escape(data[:card][:name])
|
443
509
|
else
|
444
510
|
xml.DS_MERCHANT_TITULAR data[:card][:name]
|
@@ -447,6 +513,9 @@ module ActiveMerchant #:nodoc:
|
|
447
513
|
xml.DS_MERCHANT_EXPIRYDATE data[:card][:date]
|
448
514
|
xml.DS_MERCHANT_CVV2 data[:card][:cvv]
|
449
515
|
xml.DS_MERCHANT_IDENTIFIER 'REQUIRED' if data[:store_in_vault]
|
516
|
+
|
517
|
+
build_merchant_mpi_external(xml, data)
|
518
|
+
|
450
519
|
elsif data[:credit_card_token]
|
451
520
|
xml.DS_MERCHANT_IDENTIFIER data[:credit_card_token]
|
452
521
|
xml.DS_MERCHANT_DIRECTPAYMENT 'true'
|
@@ -457,9 +526,36 @@ module ActiveMerchant #:nodoc:
|
|
457
526
|
xml.DS_MERCHANT_DIRECTPAYMENT 'moto' if options.dig(:moto) && options.dig(:metadata, :manual_entry)
|
458
527
|
|
459
528
|
xml.DS_MERCHANT_EMV3DS data[:threeds].to_json if data[:threeds]
|
529
|
+
|
530
|
+
if options[:stored_credential]
|
531
|
+
xml.DS_MERCHANT_COF_INI data[:DS_MERCHANT_COF_INI]
|
532
|
+
xml.DS_MERCHANT_COF_TYPE data[:DS_MERCHANT_COF_TYPE]
|
533
|
+
xml.DS_MERCHANT_COF_TXNID data[:DS_MERCHANT_COF_TXNID] if data[:DS_MERCHANT_COF_TXNID]
|
534
|
+
end
|
460
535
|
end
|
461
536
|
end
|
462
537
|
|
538
|
+
def build_merchant_mpi_external(xml, data)
|
539
|
+
return unless data[:txid] || data[:threeDSServerTransID]
|
540
|
+
|
541
|
+
ds_merchant_mpi_external = {}
|
542
|
+
ds_merchant_mpi_external[:TXID] = data[:txid] if data[:txid]
|
543
|
+
ds_merchant_mpi_external[:CAVV] = data[:cavv] if data[:cavv]
|
544
|
+
ds_merchant_mpi_external[:ECI] = data[:eci_v1] if data[:eci_v1]
|
545
|
+
|
546
|
+
ds_merchant_mpi_external[:threeDSServerTransID] = data[:threeDSServerTransID] if data[:threeDSServerTransID]
|
547
|
+
ds_merchant_mpi_external[:dsTransID] = data[:dsTransID] if data[:dsTransID]
|
548
|
+
ds_merchant_mpi_external[:authenticacionValue] = data[:authenticacionValue] if data[:authenticacionValue]
|
549
|
+
ds_merchant_mpi_external[:protocolVersion] = data[:protocolVersion] if data[:protocolVersion]
|
550
|
+
ds_merchant_mpi_external[:Eci] = data[:eci_v2] if data[:eci_v2]
|
551
|
+
ds_merchant_mpi_external[:authenticacionMethod] = data[:authenticacionMethod] if data[:authenticacionMethod]
|
552
|
+
ds_merchant_mpi_external[:authenticacionType] = data[:authenticacionType] if data[:authenticacionType]
|
553
|
+
ds_merchant_mpi_external[:authenticacionFlow] = data[:authenticacionFlow] if data[:authenticacionFlow]
|
554
|
+
|
555
|
+
xml.DS_MERCHANT_MPIEXTERNAL ds_merchant_mpi_external.to_json unless ds_merchant_mpi_external.empty?
|
556
|
+
xml.target!
|
557
|
+
end
|
558
|
+
|
463
559
|
def parse(data, action)
|
464
560
|
params = {}
|
465
561
|
success = false
|
@@ -542,7 +638,7 @@ module ActiveMerchant #:nodoc:
|
|
542
638
|
def response_text(code)
|
543
639
|
code = code.to_i
|
544
640
|
code = 0 if code < 100
|
545
|
-
RESPONSE_TEXTS[code] || '
|
641
|
+
RESPONSE_TEXTS[code] || 'Unknown code, please check in manual'
|
546
642
|
end
|
547
643
|
|
548
644
|
def response_text_3ds(xml, params)
|
@@ -22,8 +22,19 @@ module ActiveMerchant #:nodoc:
|
|
22
22
|
|
23
23
|
def purchase(money, payment, options = {})
|
24
24
|
post = {}
|
25
|
-
|
26
|
-
|
25
|
+
|
26
|
+
# Determine if 3DS is requested, or there is standard external MPI data
|
27
|
+
if options[:three_d_secure]
|
28
|
+
if options[:three_d_secure].is_a?(Hash)
|
29
|
+
add_external_mpi_data(post, options)
|
30
|
+
else
|
31
|
+
post[:sg_APIType] = 1
|
32
|
+
trans_type = 'Sale3D'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
trans_type ||= 'Sale'
|
37
|
+
|
27
38
|
add_transaction_data(trans_type, post, money, options)
|
28
39
|
add_payment(post, payment, options)
|
29
40
|
add_customer_details(post, payment, options)
|
@@ -33,6 +44,8 @@ module ActiveMerchant #:nodoc:
|
|
33
44
|
|
34
45
|
def authorize(money, payment, options = {})
|
35
46
|
post = {}
|
47
|
+
|
48
|
+
add_external_mpi_data(post, options) if options[:three_d_secure]&.is_a?(Hash)
|
36
49
|
add_transaction_data('Auth', post, money, options)
|
37
50
|
add_payment(post, payment, options)
|
38
51
|
add_customer_details(post, payment, options)
|
@@ -69,8 +82,10 @@ module ActiveMerchant #:nodoc:
|
|
69
82
|
|
70
83
|
def credit(money, payment, options = {})
|
71
84
|
post = {}
|
85
|
+
|
72
86
|
add_payment(post, payment, options)
|
73
87
|
add_transaction_data('Credit', post, money, options)
|
88
|
+
|
74
89
|
post[:sg_CreditType] = 1
|
75
90
|
|
76
91
|
commit(post)
|
@@ -131,12 +146,20 @@ module ActiveMerchant #:nodoc:
|
|
131
146
|
end
|
132
147
|
|
133
148
|
def add_payment(post, payment, options = {})
|
134
|
-
post[:sg_NameOnCard] = payment.name
|
135
|
-
post[:sg_CardNumber] = payment.number
|
136
149
|
post[:sg_ExpMonth] = format(payment.month, :two_digits)
|
137
150
|
post[:sg_ExpYear] = format(payment.year, :two_digits)
|
138
|
-
post[:
|
139
|
-
|
151
|
+
post[:sg_CardNumber] = payment.number
|
152
|
+
|
153
|
+
if payment.is_a?(NetworkTokenizationCreditCard) && payment.source == :network_token
|
154
|
+
post[:sg_CAVV] = payment.payment_cryptogram
|
155
|
+
post[:sg_ECI] = options[:three_d_secure] && options[:three_d_secure][:eci] || '05'
|
156
|
+
post[:sg_IsExternalMPI] = 1
|
157
|
+
post[:sg_ExternalTokenProvider] = 5
|
158
|
+
else
|
159
|
+
post[:sg_CVV2] = payment.verification_value
|
160
|
+
post[:sg_NameOnCard] = payment.name
|
161
|
+
post[:sg_StoredCredentialMode] = (options[:stored_credential_mode] == true ? 1 : 0)
|
162
|
+
end
|
140
163
|
end
|
141
164
|
|
142
165
|
def add_customer_details(post, payment, options)
|
@@ -154,6 +177,16 @@ module ActiveMerchant #:nodoc:
|
|
154
177
|
post[:sg_Email] = options[:email]
|
155
178
|
end
|
156
179
|
|
180
|
+
def add_external_mpi_data(post, options)
|
181
|
+
post[:sg_ECI] = options[:three_d_secure][:eci] if options[:three_d_secure][:eci]
|
182
|
+
post[:sg_CAVV] = options[:three_d_secure][:cavv] if options[:three_d_secure][:cavv]
|
183
|
+
post[:sg_dsTransID] = options[:three_d_secure][:ds_transaction_id] if options[:three_d_secure][:ds_transaction_id]
|
184
|
+
post[:sg_threeDSProtocolVersion] = options[:three_d_secure][:ds_transaction_id] ? '2' : '1'
|
185
|
+
post[:sg_Xid] = options[:three_d_secure][:xid]
|
186
|
+
post[:sg_IsExternalMPI] = 1
|
187
|
+
post[:sg_EnablePartialApproval] = options[:is_partial_approval]
|
188
|
+
end
|
189
|
+
|
157
190
|
def parse(xml)
|
158
191
|
response = {}
|
159
192
|
|
@@ -28,7 +28,7 @@ module ActiveMerchant #:nodoc:
|
|
28
28
|
self.supported_countries = %w(AT AU BE BG BR CA CH CY CZ DE DK EE ES FI FR GB GR HK IE IT JP LT LU LV MT MX NL NO NZ PL PT RO SE SG SI SK US)
|
29
29
|
self.default_currency = 'USD'
|
30
30
|
self.money_format = :cents
|
31
|
-
self.supported_cardtypes = %i[visa master american_express discover jcb diners_club maestro]
|
31
|
+
self.supported_cardtypes = %i[visa master american_express discover jcb diners_club maestro unionpay]
|
32
32
|
self.currencies_without_fractions = %w(BIF CLP DJF GNF JPY KMF KRW MGA PYG RWF VND VUV XAF XOF XPF UGX)
|
33
33
|
|
34
34
|
self.homepage_url = 'https://stripe.com/'
|
@@ -279,14 +279,14 @@ module ActiveMerchant #:nodoc:
|
|
279
279
|
transcript.
|
280
280
|
gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
|
281
281
|
gsub(%r((&?three_d_secure\[cryptogram\]=)[\w=]*(&?)), '\1[FILTERED]\2').
|
282
|
-
gsub(%r((card\[cryptogram\]=)[^&]+(&?)), '\1[FILTERED]\
|
283
|
-
gsub(%r((card\[cvc\]=)\d+), '\1[FILTERED]').
|
284
|
-
gsub(%r((card\[emv_approval_data\]=)[^&]+(&?)), '\1[FILTERED]\
|
285
|
-
gsub(%r((card\[emv_auth_data\]=)[^&]+(&?)), '\1[FILTERED]\
|
286
|
-
gsub(%r((card\[encrypted_pin\]=)[^&]+(&?)), '\1[FILTERED]\
|
287
|
-
gsub(%r((card\[encrypted_pin_key_id\]=)[\w=]+(&?)), '\1[FILTERED]\
|
288
|
-
gsub(%r((card\[number\]=)\d+), '\1[FILTERED]').
|
289
|
-
gsub(%r((card\[swipe_data\]=)[^&]+(&?)), '\1[FILTERED]\
|
282
|
+
gsub(%r(((\[card\]|card)\[cryptogram\]=)[^&]+(&?)), '\1[FILTERED]\3').
|
283
|
+
gsub(%r(((\[card\]|card)\[cvc\]=)\d+), '\1[FILTERED]').
|
284
|
+
gsub(%r(((\[card\]|card)\[emv_approval_data\]=)[^&]+(&?)), '\1[FILTERED]\3').
|
285
|
+
gsub(%r(((\[card\]|card)\[emv_auth_data\]=)[^&]+(&?)), '\1[FILTERED]\3').
|
286
|
+
gsub(%r(((\[card\]|card)\[encrypted_pin\]=)[^&]+(&?)), '\1[FILTERED]\3').
|
287
|
+
gsub(%r(((\[card\]|card)\[encrypted_pin_key_id\]=)[\w=]+(&?)), '\1[FILTERED]\3').
|
288
|
+
gsub(%r(((\[card\]|card)\[number\]=)\d+), '\1[FILTERED]').
|
289
|
+
gsub(%r(((\[card\]|card)\[swipe_data\]=)[^&]+(&?)), '\1[FILTERED]\3')
|
290
290
|
end
|
291
291
|
|
292
292
|
def supports_network_tokenization?
|
@@ -23,12 +23,15 @@ module ActiveMerchant #:nodoc:
|
|
23
23
|
payment_method = add_payment_method_token(post, payment_method, options)
|
24
24
|
return payment_method if payment_method.is_a?(ActiveMerchant::Billing::Response)
|
25
25
|
|
26
|
+
add_external_three_d_secure_auth_data(post, options)
|
26
27
|
add_metadata(post, options)
|
27
28
|
add_return_url(post, options)
|
28
29
|
add_connected_account(post, options)
|
29
30
|
add_shipping_address(post, options)
|
30
31
|
setup_future_usage(post, options)
|
31
32
|
add_exemption(post, options)
|
33
|
+
add_stored_credentials(post, options)
|
34
|
+
add_error_on_requires_action(post, options)
|
32
35
|
request_three_d_secure(post, options)
|
33
36
|
|
34
37
|
CREATE_INTENT_ATTRIBUTES.each do |attribute|
|
@@ -54,16 +57,22 @@ module ActiveMerchant #:nodoc:
|
|
54
57
|
end
|
55
58
|
|
56
59
|
def create_payment_method(payment_method, options = {})
|
57
|
-
|
58
|
-
|
59
|
-
post[:card] = {}
|
60
|
-
post[:card][:number] = payment_method.number
|
61
|
-
post[:card][:exp_month] = payment_method.month
|
62
|
-
post[:card][:exp_year] = payment_method.year
|
63
|
-
post[:card][:cvc] = payment_method.verification_value if payment_method.verification_value
|
64
|
-
add_billing_address(post, options)
|
60
|
+
post_data = create_payment_method_data(payment_method, options)
|
61
|
+
|
65
62
|
options = format_idempotency_key(options, 'pm')
|
66
|
-
commit(:post, 'payment_methods',
|
63
|
+
commit(:post, 'payment_methods', post_data, options)
|
64
|
+
end
|
65
|
+
|
66
|
+
def create_payment_method_data(payment_method, options = {})
|
67
|
+
post_data = {}
|
68
|
+
post_data[:type] = 'card'
|
69
|
+
post_data[:card] = {}
|
70
|
+
post_data[:card][:number] = payment_method.number
|
71
|
+
post_data[:card][:exp_month] = payment_method.month
|
72
|
+
post_data[:card][:exp_year] = payment_method.year
|
73
|
+
post_data[:card][:cvc] = payment_method.verification_value if payment_method.verification_value
|
74
|
+
add_billing_address(post_data, options)
|
75
|
+
post_data
|
67
76
|
end
|
68
77
|
|
69
78
|
def update_intent(money, intent_id, payment_method, options = {})
|
@@ -100,6 +109,17 @@ module ActiveMerchant #:nodoc:
|
|
100
109
|
commit(:post, 'setup_intents', post, options)
|
101
110
|
end
|
102
111
|
|
112
|
+
def retrieve_setup_intent(setup_intent_id)
|
113
|
+
# Retrieving a setup_intent passing 'expand[]=latest_attempt' allows the caller to
|
114
|
+
# check for a network_transaction_id and ds_transaction_id
|
115
|
+
# eg (latest_attempt -> payment_method_details -> card -> network_transaction_id)
|
116
|
+
#
|
117
|
+
# Being able to retrieve these fields enables payment flows that rely on MIT exemptions, e.g: off_session
|
118
|
+
commit(:post, "setup_intents/#{setup_intent_id}", {
|
119
|
+
'expand[]': 'latest_attempt'
|
120
|
+
}, {})
|
121
|
+
end
|
122
|
+
|
103
123
|
def authorize(money, payment_method, options = {})
|
104
124
|
create_intent(money, payment_method, options.merge!(confirm: true, capture_method: 'manual'))
|
105
125
|
end
|
@@ -163,7 +183,6 @@ module ActiveMerchant #:nodoc:
|
|
163
183
|
if options[:customer]
|
164
184
|
customer_id = options[:customer]
|
165
185
|
else
|
166
|
-
post[:validate] = options[:validate] unless options[:validate].nil?
|
167
186
|
post[:description] = options[:description] if options[:description]
|
168
187
|
post[:email] = options[:email] if options[:email]
|
169
188
|
options = format_idempotency_key(options, 'customer')
|
@@ -171,7 +190,9 @@ module ActiveMerchant #:nodoc:
|
|
171
190
|
customer_id = customer.params['id']
|
172
191
|
end
|
173
192
|
options = format_idempotency_key(options, 'attach')
|
174
|
-
|
193
|
+
attach_parameters = { customer: customer_id }
|
194
|
+
attach_parameters[:validate] = options[:validate] unless options[:validate].nil?
|
195
|
+
commit(:post, "payment_methods/#{params[:payment_method]}/attach", attach_parameters, options)
|
175
196
|
else
|
176
197
|
super(payment_method, options)
|
177
198
|
end
|
@@ -192,6 +213,10 @@ module ActiveMerchant #:nodoc:
|
|
192
213
|
|
193
214
|
private
|
194
215
|
|
216
|
+
def off_session_request?(options = {})
|
217
|
+
(options[:off_session] || options[:setup_future_usage]) && options[:confirm] == true
|
218
|
+
end
|
219
|
+
|
195
220
|
def add_connected_account(post, options = {})
|
196
221
|
super(post, options)
|
197
222
|
post[:application_fee_amount] = options[:application_fee] if options[:application_fee]
|
@@ -199,25 +224,21 @@ module ActiveMerchant #:nodoc:
|
|
199
224
|
|
200
225
|
def add_whitelisted_attribute(post, options, attribute)
|
201
226
|
post[attribute] = options[attribute] if options[attribute]
|
202
|
-
post
|
203
227
|
end
|
204
228
|
|
205
229
|
def add_capture_method(post, options)
|
206
230
|
capture_method = options[:capture_method].to_s
|
207
231
|
post[:capture_method] = capture_method if ALLOWED_METHOD_STATES.include?(capture_method)
|
208
|
-
post
|
209
232
|
end
|
210
233
|
|
211
234
|
def add_confirmation_method(post, options)
|
212
235
|
confirmation_method = options[:confirmation_method].to_s
|
213
236
|
post[:confirmation_method] = confirmation_method if ALLOWED_METHOD_STATES.include?(confirmation_method)
|
214
|
-
post
|
215
237
|
end
|
216
238
|
|
217
239
|
def add_customer(post, options)
|
218
240
|
customer = options[:customer].to_s
|
219
241
|
post[:customer] = customer if customer.start_with?('cus_')
|
220
|
-
post
|
221
242
|
end
|
222
243
|
|
223
244
|
def add_return_url(post, options)
|
@@ -225,22 +246,27 @@ module ActiveMerchant #:nodoc:
|
|
225
246
|
|
226
247
|
post[:confirm] = options[:confirm]
|
227
248
|
post[:return_url] = options[:return_url] if options[:return_url]
|
228
|
-
post
|
229
249
|
end
|
230
250
|
|
231
251
|
def add_payment_method_token(post, payment_method, options)
|
232
252
|
return if payment_method.nil?
|
233
253
|
|
234
254
|
if payment_method.is_a?(ActiveMerchant::Billing::CreditCard)
|
235
|
-
|
236
|
-
|
255
|
+
if off_session_request?(options)
|
256
|
+
post[:payment_method_data] = create_payment_method_data(payment_method, options)
|
257
|
+
return
|
258
|
+
else
|
259
|
+
p = create_payment_method(payment_method, options)
|
260
|
+
return p unless p.success?
|
237
261
|
|
238
|
-
|
262
|
+
payment_method = p.params['id']
|
263
|
+
end
|
239
264
|
end
|
240
265
|
|
241
|
-
|
266
|
+
case payment_method
|
267
|
+
when StripePaymentToken
|
242
268
|
post[:payment_method] = payment_method.payment_data['id']
|
243
|
-
|
269
|
+
when String
|
244
270
|
if payment_method.include?('|')
|
245
271
|
customer_id, payment_method_id = payment_method.split('|')
|
246
272
|
token = payment_method_id
|
@@ -250,6 +276,8 @@ module ActiveMerchant #:nodoc:
|
|
250
276
|
end
|
251
277
|
post[:payment_method] = token
|
252
278
|
end
|
279
|
+
|
280
|
+
post
|
253
281
|
end
|
254
282
|
|
255
283
|
def add_payment_method_types(post, options)
|
@@ -257,7 +285,6 @@ module ActiveMerchant #:nodoc:
|
|
257
285
|
return if payment_method_types.nil?
|
258
286
|
|
259
287
|
post[:payment_method_types] = Array(payment_method_types)
|
260
|
-
post
|
261
288
|
end
|
262
289
|
|
263
290
|
def add_exemption(post, options = {})
|
@@ -268,6 +295,25 @@ module ActiveMerchant #:nodoc:
|
|
268
295
|
post[:payment_method_options][:card][:moto] = true if options[:moto]
|
269
296
|
end
|
270
297
|
|
298
|
+
def add_stored_credentials(post, options = {})
|
299
|
+
return unless options[:stored_credential] && !options[:stored_credential].values.all?(&:nil?)
|
300
|
+
|
301
|
+
stored_credential = options[:stored_credential]
|
302
|
+
post[:payment_method_options] ||= {}
|
303
|
+
post[:payment_method_options][:card] ||= {}
|
304
|
+
post[:payment_method_options][:card][:mit_exemption] = {}
|
305
|
+
|
306
|
+
# Stripe PI accepts network_transaction_id and ds_transaction_id via mit field under card.
|
307
|
+
post[:payment_method_options][:card][:mit_exemption][:network_transaction_id] = stored_credential[:network_transaction_id] if stored_credential[:network_transaction_id]
|
308
|
+
post[:payment_method_options][:card][:mit_exemption][:ds_transaction_id] = stored_credential[:ds_transaction_id] if stored_credential[:ds_transaction_id]
|
309
|
+
end
|
310
|
+
|
311
|
+
def add_error_on_requires_action(post, options = {})
|
312
|
+
return unless options[:confirm]
|
313
|
+
|
314
|
+
post[:error_on_requires_action] = true if options[:error_on_requires_action]
|
315
|
+
end
|
316
|
+
|
271
317
|
def request_three_d_secure(post, options = {})
|
272
318
|
return unless options[:request_three_d_secure] && %w(any automatic).include?(options[:request_three_d_secure])
|
273
319
|
|
@@ -276,9 +322,22 @@ module ActiveMerchant #:nodoc:
|
|
276
322
|
post[:payment_method_options][:card][:request_three_d_secure] = options[:request_three_d_secure]
|
277
323
|
end
|
278
324
|
|
325
|
+
def add_external_three_d_secure_auth_data(post, options = {})
|
326
|
+
return unless options[:three_d_secure]&.is_a?(Hash)
|
327
|
+
|
328
|
+
three_d_secure = options[:three_d_secure]
|
329
|
+
post[:payment_method_options] ||= {}
|
330
|
+
post[:payment_method_options][:card] ||= {}
|
331
|
+
post[:payment_method_options][:card][:three_d_secure] ||= {}
|
332
|
+
post[:payment_method_options][:card][:three_d_secure][:version] = three_d_secure[:version] || (three_d_secure[:ds_transaction_id] ? '2.2.0' : '1.0.2')
|
333
|
+
post[:payment_method_options][:card][:three_d_secure][:electronic_commerce_indicator] = three_d_secure[:eci] if three_d_secure[:eci]
|
334
|
+
post[:payment_method_options][:card][:three_d_secure][:cryptogram] = three_d_secure[:cavv] if three_d_secure[:cavv]
|
335
|
+
post[:payment_method_options][:card][:three_d_secure][:transaction_id] = three_d_secure[:ds_transaction_id] || three_d_secure[:xid]
|
336
|
+
end
|
337
|
+
|
279
338
|
def setup_future_usage(post, options = {})
|
280
339
|
post[:setup_future_usage] = options[:setup_future_usage] if %w(on_session off_session).include?(options[:setup_future_usage])
|
281
|
-
post[:off_session] = options[:off_session] if options
|
340
|
+
post[:off_session] = options[:off_session] if off_session_request?(options)
|
282
341
|
post
|
283
342
|
end
|
284
343
|
|
@@ -296,7 +355,6 @@ module ActiveMerchant #:nodoc:
|
|
296
355
|
post[:billing_details][:email] = billing[:email] if billing[:email]
|
297
356
|
post[:billing_details][:name] = billing[:name] if billing[:name]
|
298
357
|
post[:billing_details][:phone] = billing[:phone] if billing[:phone]
|
299
|
-
post
|
300
358
|
end
|
301
359
|
|
302
360
|
def add_shipping_address(post, options = {})
|
@@ -315,7 +373,6 @@ module ActiveMerchant #:nodoc:
|
|
315
373
|
post[:shipping][:carrier] = shipping[:carrier] if shipping[:carrier]
|
316
374
|
post[:shipping][:phone] = shipping[:phone] if shipping[:phone]
|
317
375
|
post[:shipping][:tracking_number] = shipping[:tracking_number] if shipping[:tracking_number]
|
318
|
-
post
|
319
376
|
end
|
320
377
|
|
321
378
|
def format_idempotency_key(options, suffix)
|