activemerchant 1.90.0 → 1.99.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 +202 -0
- data/README.md +6 -2
- data/lib/active_merchant/billing/avs_result.rb +4 -5
- data/lib/active_merchant/billing/credit_card.rb +8 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +81 -5
- data/lib/active_merchant/billing/gateway.rb +10 -0
- data/lib/active_merchant/billing/gateways/adyen.rb +206 -54
- data/lib/active_merchant/billing/gateways/bambora_apac.rb +226 -0
- data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +43 -10
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +3 -0
- data/lib/active_merchant/billing/gateways/beanstream.rb +11 -6
- data/lib/active_merchant/billing/gateways/blue_pay.rb +10 -8
- data/lib/active_merchant/billing/gateways/blue_snap.rb +211 -36
- data/lib/active_merchant/billing/gateways/bpoint.rb +4 -4
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +79 -18
- data/lib/active_merchant/billing/gateways/card_connect.rb +6 -1
- data/lib/active_merchant/billing/gateways/cecabank.rb +20 -9
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +98 -61
- data/lib/active_merchant/billing/gateways/credorax.rb +69 -4
- data/lib/active_merchant/billing/gateways/cyber_source.rb +85 -14
- data/lib/active_merchant/billing/gateways/d_local.rb +3 -3
- data/lib/active_merchant/billing/gateways/decidir.rb +245 -0
- data/lib/active_merchant/billing/gateways/elavon.rb +9 -0
- data/lib/active_merchant/billing/gateways/epay.rb +13 -2
- data/lib/active_merchant/billing/gateways/eway_rapid.rb +42 -12
- data/lib/active_merchant/billing/gateways/fat_zebra.rb +26 -7
- data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +42 -3
- data/lib/active_merchant/billing/gateways/global_collect.rb +3 -7
- data/lib/active_merchant/billing/gateways/hps.rb +46 -1
- data/lib/active_merchant/billing/gateways/ipp.rb +1 -0
- data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
- data/lib/active_merchant/billing/gateways/litle.rb +61 -3
- data/lib/active_merchant/billing/gateways/mastercard.rb +30 -5
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +1 -1
- data/lib/active_merchant/billing/gateways/migs.rb +8 -0
- data/lib/active_merchant/billing/gateways/monei.rb +31 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +3 -4
- data/lib/active_merchant/billing/gateways/mundipagg.rb +37 -9
- data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
- data/lib/active_merchant/billing/gateways/netbanx.rb +4 -0
- data/lib/active_merchant/billing/gateways/nmi.rb +45 -5
- data/lib/active_merchant/billing/gateways/openpay.rb +1 -1
- data/lib/active_merchant/billing/gateways/opp.rb +20 -1
- data/lib/active_merchant/billing/gateways/orbital.rb +92 -11
- data/lib/active_merchant/billing/gateways/payflow.rb +64 -14
- data/lib/active_merchant/billing/gateways/payment_express.rb +7 -0
- data/lib/active_merchant/billing/gateways/paymentez.rb +7 -11
- data/lib/active_merchant/billing/gateways/paymill.rb +5 -0
- data/lib/active_merchant/billing/gateways/paypal.rb +14 -1
- data/lib/active_merchant/billing/gateways/paypal_express.rb +3 -1
- data/lib/active_merchant/billing/gateways/payu_latam.rb +6 -2
- data/lib/active_merchant/billing/gateways/pin.rb +19 -6
- data/lib/active_merchant/billing/gateways/pro_pay.rb +1 -1
- data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +7 -1
- data/lib/active_merchant/billing/gateways/qvalent.rb +54 -1
- data/lib/active_merchant/billing/gateways/realex.rb +42 -5
- data/lib/active_merchant/billing/gateways/redsys.rb +113 -30
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +43 -29
- data/lib/active_merchant/billing/gateways/stripe.rb +66 -34
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +271 -0
- data/lib/active_merchant/billing/gateways/tns.rb +10 -5
- data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +5 -5
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +46 -6
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +19 -8
- data/lib/active_merchant/billing/gateways/visanet_peru.rb +22 -10
- data/lib/active_merchant/billing/gateways/worldpay.rb +237 -34
- data/lib/active_merchant/country.rb +2 -1
- data/lib/active_merchant/version.rb +1 -1
- metadata +20 -4
|
@@ -193,28 +193,32 @@ module ActiveMerchant #:nodoc:
|
|
|
193
193
|
requires!(options, :order_id)
|
|
194
194
|
|
|
195
195
|
data = {}
|
|
196
|
-
add_action(data, :purchase)
|
|
196
|
+
add_action(data, :purchase, options)
|
|
197
197
|
add_amount(data, money, options)
|
|
198
198
|
add_order(data, options[:order_id])
|
|
199
199
|
add_payment(data, payment)
|
|
200
|
+
add_threeds(data, options) if options[:execute_threed]
|
|
200
201
|
data[:description] = options[:description]
|
|
201
202
|
data[:store_in_vault] = options[:store]
|
|
203
|
+
data[:sca_exemption] = options[:sca_exemption]
|
|
202
204
|
|
|
203
|
-
commit data
|
|
205
|
+
commit data, options
|
|
204
206
|
end
|
|
205
207
|
|
|
206
208
|
def authorize(money, payment, options = {})
|
|
207
209
|
requires!(options, :order_id)
|
|
208
210
|
|
|
209
211
|
data = {}
|
|
210
|
-
add_action(data, :authorize)
|
|
212
|
+
add_action(data, :authorize, options)
|
|
211
213
|
add_amount(data, money, options)
|
|
212
214
|
add_order(data, options[:order_id])
|
|
213
215
|
add_payment(data, payment)
|
|
216
|
+
add_threeds(data, options) if options[:execute_threed]
|
|
214
217
|
data[:description] = options[:description]
|
|
215
218
|
data[:store_in_vault] = options[:store]
|
|
219
|
+
data[:sca_exemption] = options[:sca_exemption]
|
|
216
220
|
|
|
217
|
-
commit data
|
|
221
|
+
commit data, options
|
|
218
222
|
end
|
|
219
223
|
|
|
220
224
|
def capture(money, authorization, options = {})
|
|
@@ -225,7 +229,7 @@ module ActiveMerchant #:nodoc:
|
|
|
225
229
|
add_order(data, order_id)
|
|
226
230
|
data[:description] = options[:description]
|
|
227
231
|
|
|
228
|
-
commit data
|
|
232
|
+
commit data, options
|
|
229
233
|
end
|
|
230
234
|
|
|
231
235
|
def void(authorization, options = {})
|
|
@@ -236,7 +240,7 @@ module ActiveMerchant #:nodoc:
|
|
|
236
240
|
add_order(data, order_id)
|
|
237
241
|
data[:description] = options[:description]
|
|
238
242
|
|
|
239
|
-
commit data
|
|
243
|
+
commit data, options
|
|
240
244
|
end
|
|
241
245
|
|
|
242
246
|
def refund(money, authorization, options = {})
|
|
@@ -247,7 +251,7 @@ module ActiveMerchant #:nodoc:
|
|
|
247
251
|
add_order(data, order_id)
|
|
248
252
|
data[:description] = options[:description]
|
|
249
253
|
|
|
250
|
-
commit data
|
|
254
|
+
commit data, options
|
|
251
255
|
end
|
|
252
256
|
|
|
253
257
|
def verify(creditcard, options = {})
|
|
@@ -278,8 +282,8 @@ module ActiveMerchant #:nodoc:
|
|
|
278
282
|
|
|
279
283
|
private
|
|
280
284
|
|
|
281
|
-
def add_action(data, action)
|
|
282
|
-
data[:action] = transaction_code(action)
|
|
285
|
+
def add_action(data, action, options = {})
|
|
286
|
+
data[:action] = options[:execute_threed].present? ? '0' : transaction_code(action)
|
|
283
287
|
end
|
|
284
288
|
|
|
285
289
|
def add_amount(data, money, options)
|
|
@@ -295,6 +299,10 @@ module ActiveMerchant #:nodoc:
|
|
|
295
299
|
test? ? test_url : live_url
|
|
296
300
|
end
|
|
297
301
|
|
|
302
|
+
def threeds_url
|
|
303
|
+
test? ? 'https://sis-t.redsys.es:25443/sis/services/SerClsWSEntradaV2': 'https://sis.redsys.es/sis/services/SerClsWSEntradaV2'
|
|
304
|
+
end
|
|
305
|
+
|
|
298
306
|
def add_payment(data, card)
|
|
299
307
|
if card.is_a?(String)
|
|
300
308
|
data[:credit_card_token] = card
|
|
@@ -311,21 +319,57 @@ module ActiveMerchant #:nodoc:
|
|
|
311
319
|
end
|
|
312
320
|
end
|
|
313
321
|
|
|
314
|
-
def
|
|
315
|
-
|
|
322
|
+
def add_threeds(data, options)
|
|
323
|
+
if options[:execute_threed] == true
|
|
324
|
+
data[:threeds] = {threeDSInfo: 'CardData'}
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def determine_3ds_action(threeds_hash)
|
|
329
|
+
return 'iniciaPeticion' if threeds_hash[:threeDSInfo] == 'CardData'
|
|
330
|
+
return 'trataPeticion' if threeds_hash[:threeDSInfo] == 'AuthenticationData' ||
|
|
331
|
+
threeds_hash[:threeDSInfo] == 'ChallengeResponse'
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def commit(data, options = {})
|
|
335
|
+
if data[:threeds]
|
|
336
|
+
action = determine_3ds_action(data[:threeds])
|
|
337
|
+
request = <<-EOS
|
|
338
|
+
<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" >
|
|
339
|
+
<soapenv:Header/>
|
|
340
|
+
<soapenv:Body>
|
|
341
|
+
<intf:#{action} xmlns:intf="http://webservice.sis.sermepa.es">
|
|
342
|
+
<intf:datoEntrada>
|
|
343
|
+
<![CDATA[#{xml_request_from(data, options)}]]>
|
|
344
|
+
</intf:datoEntrada>
|
|
345
|
+
</intf:#{action}>
|
|
346
|
+
</soapenv:Body>
|
|
347
|
+
</soapenv:Envelope>
|
|
348
|
+
EOS
|
|
349
|
+
parse(ssl_post(threeds_url, request, headers(action)), action)
|
|
350
|
+
else
|
|
351
|
+
parse(ssl_post(url, "entrada=#{CGI.escape(xml_request_from(data, options))}", headers), action)
|
|
352
|
+
end
|
|
316
353
|
end
|
|
317
354
|
|
|
318
|
-
def headers
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
355
|
+
def headers(action=nil)
|
|
356
|
+
if action
|
|
357
|
+
{
|
|
358
|
+
'Content-Type' => 'text/xml',
|
|
359
|
+
'SOAPAction' => action
|
|
360
|
+
}
|
|
361
|
+
else
|
|
362
|
+
{
|
|
363
|
+
'Content-Type' => 'application/x-www-form-urlencoded'
|
|
364
|
+
}
|
|
365
|
+
end
|
|
322
366
|
end
|
|
323
367
|
|
|
324
|
-
def xml_request_from(data)
|
|
368
|
+
def xml_request_from(data, options = {})
|
|
325
369
|
if sha256_authentication?
|
|
326
|
-
build_sha256_xml_request(data)
|
|
370
|
+
build_sha256_xml_request(data, options)
|
|
327
371
|
else
|
|
328
|
-
build_sha1_xml_request(data)
|
|
372
|
+
build_sha1_xml_request(data, options)
|
|
329
373
|
end
|
|
330
374
|
end
|
|
331
375
|
|
|
@@ -351,30 +395,30 @@ module ActiveMerchant #:nodoc:
|
|
|
351
395
|
Digest::SHA1.hexdigest(str)
|
|
352
396
|
end
|
|
353
397
|
|
|
354
|
-
def build_sha256_xml_request(data)
|
|
398
|
+
def build_sha256_xml_request(data, options = {})
|
|
355
399
|
xml = Builder::XmlMarkup.new
|
|
356
400
|
xml.instruct!
|
|
357
401
|
xml.REQUEST do
|
|
358
|
-
build_merchant_data(xml, data)
|
|
402
|
+
build_merchant_data(xml, data, options)
|
|
359
403
|
xml.DS_SIGNATUREVERSION 'HMAC_SHA256_V1'
|
|
360
|
-
xml.DS_SIGNATURE sign_request(merchant_data_xml(data), data[:order_id])
|
|
404
|
+
xml.DS_SIGNATURE sign_request(merchant_data_xml(data, options), data[:order_id])
|
|
361
405
|
end
|
|
362
406
|
xml.target!
|
|
363
407
|
end
|
|
364
408
|
|
|
365
|
-
def build_sha1_xml_request(data)
|
|
409
|
+
def build_sha1_xml_request(data, options = {})
|
|
366
410
|
xml = Builder::XmlMarkup.new :indent => 2
|
|
367
|
-
build_merchant_data(xml, data)
|
|
411
|
+
build_merchant_data(xml, data, options)
|
|
368
412
|
xml.target!
|
|
369
413
|
end
|
|
370
414
|
|
|
371
|
-
def merchant_data_xml(data)
|
|
415
|
+
def merchant_data_xml(data, options = {})
|
|
372
416
|
xml = Builder::XmlMarkup.new
|
|
373
|
-
build_merchant_data(xml, data)
|
|
417
|
+
build_merchant_data(xml, data, options)
|
|
374
418
|
xml.target!
|
|
375
419
|
end
|
|
376
420
|
|
|
377
|
-
def build_merchant_data(xml, data)
|
|
421
|
+
def build_merchant_data(xml, data, options = {})
|
|
378
422
|
xml.DATOSENTRADA do
|
|
379
423
|
# Basic elements
|
|
380
424
|
xml.DS_Version 0.1
|
|
@@ -383,9 +427,10 @@ module ActiveMerchant #:nodoc:
|
|
|
383
427
|
xml.DS_MERCHANT_ORDER data[:order_id]
|
|
384
428
|
xml.DS_MERCHANT_TRANSACTIONTYPE data[:action]
|
|
385
429
|
xml.DS_MERCHANT_PRODUCTDESCRIPTION data[:description]
|
|
386
|
-
xml.DS_MERCHANT_TERMINAL @options[:terminal]
|
|
430
|
+
xml.DS_MERCHANT_TERMINAL options[:terminal] || @options[:terminal]
|
|
387
431
|
xml.DS_MERCHANT_MERCHANTCODE @options[:login]
|
|
388
432
|
xml.DS_MERCHANT_MERCHANTSIGNATURE build_signature(data) unless sha256_authentication?
|
|
433
|
+
xml.DS_MERCHANT_EXCEP_SCA data[:sca_exemption] if data[:sca_exemption]
|
|
389
434
|
|
|
390
435
|
# Only when card is present
|
|
391
436
|
if data[:card]
|
|
@@ -398,22 +443,42 @@ module ActiveMerchant #:nodoc:
|
|
|
398
443
|
xml.DS_MERCHANT_IDENTIFIER data[:credit_card_token]
|
|
399
444
|
xml.DS_MERCHANT_DIRECTPAYMENT 'true'
|
|
400
445
|
end
|
|
446
|
+
|
|
447
|
+
# Set moto flag only if explicitly requested via moto field
|
|
448
|
+
# Requires account configuration to be able to use
|
|
449
|
+
if options.dig(:moto) && options.dig(:metadata, :manual_entry)
|
|
450
|
+
xml.DS_MERCHANT_DIRECTPAYMENT 'moto'
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
if data[:threeds]
|
|
454
|
+
xml.DS_MERCHANT_EMV3DS data[:threeds].to_json
|
|
455
|
+
end
|
|
401
456
|
end
|
|
402
457
|
end
|
|
403
458
|
|
|
404
|
-
def parse(data)
|
|
459
|
+
def parse(data, action)
|
|
405
460
|
params = {}
|
|
406
461
|
success = false
|
|
407
462
|
message = ''
|
|
408
463
|
options = @options.merge(:test => test?)
|
|
409
464
|
xml = Nokogiri::XML(data)
|
|
410
465
|
code = xml.xpath('//RETORNOXML/CODIGO').text
|
|
411
|
-
|
|
466
|
+
|
|
467
|
+
if ['iniciaPeticion', 'trataPeticion'].include?(action)
|
|
468
|
+
vxml = Nokogiri::XML(data).remove_namespaces!.xpath("//Envelope/Body/#{action}Response/#{action}Return").inner_text
|
|
469
|
+
xml = Nokogiri::XML(vxml)
|
|
470
|
+
node = (action == 'iniciaPeticion' ? 'INFOTARJETA' : 'OPERACION')
|
|
471
|
+
op = xml.xpath("//RETORNOXML/#{node}")
|
|
472
|
+
op.children.each do |element|
|
|
473
|
+
params[element.name.downcase.to_sym] = element.text
|
|
474
|
+
end
|
|
475
|
+
message = response_text_3ds(xml, params)
|
|
476
|
+
success = params.size > 0 && is_success_response?(params[:ds_response])
|
|
477
|
+
elsif code == '0'
|
|
412
478
|
op = xml.xpath('//RETORNOXML/OPERACION')
|
|
413
479
|
op.children.each do |element|
|
|
414
480
|
params[element.name.downcase.to_sym] = element.text
|
|
415
481
|
end
|
|
416
|
-
|
|
417
482
|
if validate_signature(params)
|
|
418
483
|
message = response_text(params[:ds_response])
|
|
419
484
|
options[:authorization] = build_authorization(params)
|
|
@@ -474,6 +539,20 @@ module ActiveMerchant #:nodoc:
|
|
|
474
539
|
RESPONSE_TEXTS[code] || 'Unkown code, please check in manual'
|
|
475
540
|
end
|
|
476
541
|
|
|
542
|
+
def response_text_3ds(xml, params)
|
|
543
|
+
code = xml.xpath('//RETORNOXML/CODIGO').text
|
|
544
|
+
message = ''
|
|
545
|
+
if code != '0'
|
|
546
|
+
message = "#{code} ERROR"
|
|
547
|
+
elsif params[:ds_emv3ds]
|
|
548
|
+
three_ds_data = JSON.parse(params[:ds_emv3ds])
|
|
549
|
+
message = three_ds_data['threeDSInfo']
|
|
550
|
+
elsif params[:ds_response]
|
|
551
|
+
message = response_text(params[:ds_response])
|
|
552
|
+
end
|
|
553
|
+
message
|
|
554
|
+
end
|
|
555
|
+
|
|
477
556
|
def is_success_response?(code)
|
|
478
557
|
(code.to_i < 100) || [400, 481, 500, 900].include?(code.to_i)
|
|
479
558
|
end
|
|
@@ -523,6 +602,10 @@ module ActiveMerchant #:nodoc:
|
|
|
523
602
|
xml_signed_fields += data[:ds_cardnumber]
|
|
524
603
|
end
|
|
525
604
|
|
|
605
|
+
if data[:ds_emv3ds]
|
|
606
|
+
xml_signed_fields += data[:ds_emv3ds]
|
|
607
|
+
end
|
|
608
|
+
|
|
526
609
|
xml_signed_fields + data[:ds_transactiontype] + data[:ds_securepayment]
|
|
527
610
|
end
|
|
528
611
|
|
|
@@ -35,19 +35,13 @@ module ActiveMerchant #:nodoc:
|
|
|
35
35
|
# Public: Run a purchase transaction.
|
|
36
36
|
#
|
|
37
37
|
# money - The monetary amount of the transaction in cents.
|
|
38
|
-
# payment_method - The CreditCard or the Spreedly payment method token.
|
|
38
|
+
# payment_method - The CreditCard or Check or the Spreedly payment method token.
|
|
39
39
|
# options - A hash of options:
|
|
40
40
|
# :store - Retain the payment method if the purchase
|
|
41
41
|
# succeeds. Defaults to false. (optional)
|
|
42
42
|
def purchase(money, payment_method, options = {})
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
else
|
|
46
|
-
MultiResponse.run do |r|
|
|
47
|
-
r.process { save_card(options[:store], payment_method, options) }
|
|
48
|
-
r.process { purchase_with_token(money, r.authorization, options) }
|
|
49
|
-
end
|
|
50
|
-
end
|
|
43
|
+
request = build_transaction_request(money, payment_method, options)
|
|
44
|
+
commit("gateways/#{options[:gateway_token] || @options[:gateway_token]}/purchase.xml", request)
|
|
51
45
|
end
|
|
52
46
|
|
|
53
47
|
# Public: Run an authorize transaction.
|
|
@@ -58,14 +52,8 @@ module ActiveMerchant #:nodoc:
|
|
|
58
52
|
# :store - Retain the payment method if the authorize
|
|
59
53
|
# succeeds. Defaults to false. (optional)
|
|
60
54
|
def authorize(money, payment_method, options = {})
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
else
|
|
64
|
-
MultiResponse.run do |r|
|
|
65
|
-
r.process { save_card(options[:store], payment_method, options) }
|
|
66
|
-
r.process { authorize_with_token(money, r.authorization, options) }
|
|
67
|
-
end
|
|
68
|
-
end
|
|
55
|
+
request = build_transaction_request(money, payment_method, options)
|
|
56
|
+
commit("gateways/#{@options[:gateway_token]}/authorize.xml", request)
|
|
69
57
|
end
|
|
70
58
|
|
|
71
59
|
def capture(money, authorization, options={})
|
|
@@ -79,6 +67,7 @@ module ActiveMerchant #:nodoc:
|
|
|
79
67
|
def refund(money, authorization, options={})
|
|
80
68
|
request = build_xml_request('transaction') do |doc|
|
|
81
69
|
add_invoice(doc, money, options)
|
|
70
|
+
add_extra_options(:gateway_specific_fields, doc, options)
|
|
82
71
|
end
|
|
83
72
|
|
|
84
73
|
commit("transactions/#{authorization}/credit.xml", request)
|
|
@@ -155,32 +144,25 @@ module ActiveMerchant #:nodoc:
|
|
|
155
144
|
end
|
|
156
145
|
|
|
157
146
|
def purchase_with_token(money, payment_method_token, options)
|
|
158
|
-
request =
|
|
147
|
+
request = build_transaction_request(money, payment_method_token, options)
|
|
159
148
|
commit("gateways/#{options[:gateway_token] || @options[:gateway_token]}/purchase.xml", request)
|
|
160
149
|
end
|
|
161
150
|
|
|
162
151
|
def authorize_with_token(money, payment_method_token, options)
|
|
163
|
-
request =
|
|
152
|
+
request = build_transaction_request(money, payment_method_token, options)
|
|
164
153
|
commit("gateways/#{@options[:gateway_token]}/authorize.xml", request)
|
|
165
154
|
end
|
|
166
155
|
|
|
167
156
|
def verify_with_token(payment_method_token, options)
|
|
168
|
-
request =
|
|
169
|
-
add_invoice(doc, nil, options)
|
|
170
|
-
doc.payment_method_token(payment_method_token)
|
|
171
|
-
doc.retain_on_success(true) if options[:store]
|
|
172
|
-
add_extra_options(:gateway_specific_fields, doc, options)
|
|
173
|
-
end
|
|
174
|
-
|
|
157
|
+
request = build_transaction_request(nil, payment_method_token, options)
|
|
175
158
|
commit("gateways/#{@options[:gateway_token]}/verify.xml", request)
|
|
176
159
|
end
|
|
177
160
|
|
|
178
|
-
def
|
|
161
|
+
def build_transaction_request(money, payment_method, options)
|
|
179
162
|
build_xml_request('transaction') do |doc|
|
|
180
163
|
add_invoice(doc, money, options)
|
|
164
|
+
add_payment_method(doc, payment_method, options)
|
|
181
165
|
add_extra_options(:gateway_specific_fields, doc, options)
|
|
182
|
-
doc.payment_method_token(payment_method_token)
|
|
183
|
-
doc.retain_on_success(true) if options[:store]
|
|
184
166
|
end
|
|
185
167
|
end
|
|
186
168
|
|
|
@@ -190,6 +172,27 @@ module ActiveMerchant #:nodoc:
|
|
|
190
172
|
doc.order_id(options[:order_id])
|
|
191
173
|
doc.ip(options[:ip]) if options[:ip]
|
|
192
174
|
doc.description(options[:description]) if options[:description]
|
|
175
|
+
|
|
176
|
+
if options[:merchant_name_descriptor]
|
|
177
|
+
doc.merchant_name_descriptor(options[:merchant_name_descriptor])
|
|
178
|
+
end
|
|
179
|
+
if options[:merchant_location_descriptor]
|
|
180
|
+
doc.merchant_location_descriptor(options[:merchant_location_descriptor])
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def add_payment_method(doc, payment_method, options)
|
|
185
|
+
doc.retain_on_success(true) if options[:store]
|
|
186
|
+
|
|
187
|
+
if payment_method.is_a?(String)
|
|
188
|
+
doc.payment_method_token(payment_method)
|
|
189
|
+
elsif payment_method.is_a?(CreditCard)
|
|
190
|
+
add_credit_card(doc, payment_method, options)
|
|
191
|
+
elsif payment_method.is_a?(Check)
|
|
192
|
+
add_bank_account(doc, payment_method, options)
|
|
193
|
+
else
|
|
194
|
+
raise TypeError, 'Payment method not supported'
|
|
195
|
+
end
|
|
193
196
|
end
|
|
194
197
|
|
|
195
198
|
def add_credit_card(doc, credit_card, options)
|
|
@@ -210,6 +213,17 @@ module ActiveMerchant #:nodoc:
|
|
|
210
213
|
end
|
|
211
214
|
end
|
|
212
215
|
|
|
216
|
+
def add_bank_account(doc, bank_account, options)
|
|
217
|
+
doc.bank_account do
|
|
218
|
+
doc.first_name(bank_account.first_name)
|
|
219
|
+
doc.last_name(bank_account.last_name)
|
|
220
|
+
doc.bank_routing_number(bank_account.routing_number)
|
|
221
|
+
doc.bank_account_number(bank_account.account_number)
|
|
222
|
+
doc.bank_account_type(bank_account.account_type)
|
|
223
|
+
doc.bank_account_holder_type(bank_account.account_holder_type)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
213
227
|
def add_extra_options(type, doc, options)
|
|
214
228
|
doc.send(type) do
|
|
215
229
|
extra_options_to_doc(doc, options[type])
|
|
@@ -2,6 +2,8 @@ require 'active_support/core_ext/hash/slice'
|
|
|
2
2
|
|
|
3
3
|
module ActiveMerchant #:nodoc:
|
|
4
4
|
module Billing #:nodoc:
|
|
5
|
+
# This gateway uses an older version of the Stripe API.
|
|
6
|
+
# To utilize the updated {Payment Intents API}[https://stripe.com/docs/api/payment_intents], integrate with the StripePaymentIntents gateway
|
|
5
7
|
class StripeGateway < Gateway
|
|
6
8
|
self.live_url = 'https://api.stripe.com/v1/'
|
|
7
9
|
|
|
@@ -21,7 +23,9 @@ module ActiveMerchant #:nodoc:
|
|
|
21
23
|
'unchecked' => 'P'
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
DEFAULT_API_VERSION = '2015-04-07'
|
|
27
|
+
|
|
28
|
+
self.supported_countries = %w(AT AU BE BR CA CH DE DK EE ES FI FR GB GR HK IE IT JP LT LU LV MX NL NO NZ PL PT SE SG SI SK US)
|
|
25
29
|
self.default_currency = 'USD'
|
|
26
30
|
self.money_format = :cents
|
|
27
31
|
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro]
|
|
@@ -150,14 +154,21 @@ module ActiveMerchant #:nodoc:
|
|
|
150
154
|
post[:reason] = options[:reason] if options[:reason]
|
|
151
155
|
post[:expand] = [:charge]
|
|
152
156
|
|
|
153
|
-
|
|
154
|
-
|
|
157
|
+
response = commit(:post, "charges/#{CGI.escape(identification)}/refunds", post, options)
|
|
158
|
+
|
|
159
|
+
if response.success? && options[:refund_fee_amount] && options[:refund_fee_amount].to_s != '0'
|
|
160
|
+
charge = api_request(:get, "charges/#{CGI.escape(identification)}", nil, options)
|
|
155
161
|
|
|
156
|
-
if
|
|
157
|
-
|
|
158
|
-
|
|
162
|
+
if application_fee = charge['application_fee']
|
|
163
|
+
fee_refund_options = {
|
|
164
|
+
currency: options[:currency], # currency isn't used by Stripe here, but we need it for #add_amount
|
|
165
|
+
key: @fee_refund_api_key
|
|
166
|
+
}
|
|
167
|
+
refund_application_fee(options[:refund_fee_amount].to_i, application_fee, fee_refund_options)
|
|
159
168
|
end
|
|
160
169
|
end
|
|
170
|
+
|
|
171
|
+
response
|
|
161
172
|
end
|
|
162
173
|
|
|
163
174
|
def verify(payment, options = {})
|
|
@@ -168,21 +179,10 @@ module ActiveMerchant #:nodoc:
|
|
|
168
179
|
end
|
|
169
180
|
end
|
|
170
181
|
|
|
171
|
-
def application_fee_from_response(response)
|
|
172
|
-
return unless response.success?
|
|
173
|
-
response.params['application_fee'] unless response.params['application_fee'].empty?
|
|
174
|
-
end
|
|
175
|
-
|
|
176
182
|
def refund_application_fee(money, identification, options = {})
|
|
177
|
-
return Response.new(false, 'Application fee id could not be found') unless identification
|
|
178
|
-
|
|
179
183
|
post = {}
|
|
180
184
|
add_amount(post, money, options)
|
|
181
|
-
|
|
182
|
-
options.delete(:stripe_account)
|
|
183
|
-
|
|
184
|
-
refund_fee = commit(:post, "application_fees/#{CGI.escape(identification)}/refunds", post, options)
|
|
185
|
-
application_fee_response!(refund_fee, "Application fee could not be refunded: #{refund_fee.message}")
|
|
185
|
+
commit(:post, "application_fees/#{CGI.escape(identification)}/refunds", post, options)
|
|
186
186
|
end
|
|
187
187
|
|
|
188
188
|
# Note: creating a new credit card will not change the customer's existing default credit card (use :set_default => true)
|
|
@@ -304,8 +304,8 @@ module ActiveMerchant #:nodoc:
|
|
|
304
304
|
add_amount(post, money, options, true)
|
|
305
305
|
post[:type] = type
|
|
306
306
|
if type == 'card'
|
|
307
|
-
add_creditcard(post, payment, options)
|
|
308
|
-
post
|
|
307
|
+
add_creditcard(post, payment, options, true)
|
|
308
|
+
add_source_owner(post, payment, options)
|
|
309
309
|
elsif type == 'three_d_secure'
|
|
310
310
|
post[:three_d_secure] = {card: payment}
|
|
311
311
|
post[:redirect] = {return_url: options[:redirect_url]}
|
|
@@ -313,10 +313,16 @@ module ActiveMerchant #:nodoc:
|
|
|
313
313
|
commit(:post, 'sources', post, options)
|
|
314
314
|
end
|
|
315
315
|
|
|
316
|
+
def show_source(source_id, options)
|
|
317
|
+
commit(:get, "sources/#{source_id}", nil, options)
|
|
318
|
+
end
|
|
319
|
+
|
|
316
320
|
def create_webhook_endpoint(options, events)
|
|
317
321
|
post = {}
|
|
318
322
|
post[:url] = options[:callback_url]
|
|
319
323
|
post[:enabled_events] = events
|
|
324
|
+
post[:connect] = true if options[:stripe_account]
|
|
325
|
+
options.delete(:stripe_account)
|
|
320
326
|
commit(:post, 'webhook_endpoints', post, options)
|
|
321
327
|
end
|
|
322
328
|
|
|
@@ -324,6 +330,18 @@ module ActiveMerchant #:nodoc:
|
|
|
324
330
|
commit(:delete, "webhook_endpoints/#{options[:webhook_id]}", {}, options)
|
|
325
331
|
end
|
|
326
332
|
|
|
333
|
+
def show_webhook_endpoint(options)
|
|
334
|
+
options.delete(:stripe_account)
|
|
335
|
+
commit(:get, "webhook_endpoints/#{options[:webhook_id]}", nil, options)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def list_webhook_endpoints(options)
|
|
339
|
+
params = {}
|
|
340
|
+
params[:limit] = options[:limit] if options[:limit]
|
|
341
|
+
options.delete(:stripe_account)
|
|
342
|
+
commit(:get, "webhook_endpoints?#{post_data(params)}", nil, options)
|
|
343
|
+
end
|
|
344
|
+
|
|
327
345
|
def create_post_for_auth_or_purchase(money, payment, options)
|
|
328
346
|
post = {}
|
|
329
347
|
|
|
@@ -333,6 +351,12 @@ module ActiveMerchant #:nodoc:
|
|
|
333
351
|
add_creditcard(post, payment, options)
|
|
334
352
|
end
|
|
335
353
|
|
|
354
|
+
add_charge_details(post, money, payment, options)
|
|
355
|
+
post
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
# Used internally by Spreedly to populate the charge object for 3DS 1.0 transactions
|
|
359
|
+
def add_charge_details(post, money, payment, options)
|
|
336
360
|
if emv_payment?(payment)
|
|
337
361
|
add_statement_address(post, options)
|
|
338
362
|
add_emv_metadata(post, payment)
|
|
@@ -435,7 +459,7 @@ module ActiveMerchant #:nodoc:
|
|
|
435
459
|
post[:statement_address][:state] = statement_address[:state]
|
|
436
460
|
end
|
|
437
461
|
|
|
438
|
-
def add_creditcard(post, creditcard, options)
|
|
462
|
+
def add_creditcard(post, creditcard, options, use_sources = false)
|
|
439
463
|
card = {}
|
|
440
464
|
if emv_payment?(creditcard)
|
|
441
465
|
add_emv_creditcard(post, creditcard.icc_data)
|
|
@@ -458,7 +482,7 @@ module ActiveMerchant #:nodoc:
|
|
|
458
482
|
card[:exp_month] = creditcard.month
|
|
459
483
|
card[:exp_year] = creditcard.year
|
|
460
484
|
card[:cvc] = creditcard.verification_value if creditcard.verification_value?
|
|
461
|
-
card[:name] = creditcard.name if creditcard.name
|
|
485
|
+
card[:name] = creditcard.name if creditcard.name && !use_sources
|
|
462
486
|
end
|
|
463
487
|
|
|
464
488
|
if creditcard.is_a?(NetworkTokenizationCreditCard)
|
|
@@ -468,7 +492,7 @@ module ActiveMerchant #:nodoc:
|
|
|
468
492
|
end
|
|
469
493
|
post[:card] = card
|
|
470
494
|
|
|
471
|
-
add_address(post, options)
|
|
495
|
+
add_address(post, options) unless use_sources
|
|
472
496
|
elsif creditcard.kind_of?(String)
|
|
473
497
|
if options[:track_data]
|
|
474
498
|
card[:swipe_data] = options[:track_data]
|
|
@@ -516,15 +540,23 @@ module ActiveMerchant #:nodoc:
|
|
|
516
540
|
post[:metadata][:card_read_method] = creditcard.read_method if creditcard.respond_to?(:read_method)
|
|
517
541
|
end
|
|
518
542
|
|
|
519
|
-
def
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
application_fee_response!(fetch_charge, "Application fee id could not be retrieved: #{fetch_charge.message}")
|
|
524
|
-
end
|
|
543
|
+
def add_source_owner(post, creditcard, options)
|
|
544
|
+
post[:owner] = {}
|
|
545
|
+
post[:owner][:name] = creditcard.name if creditcard.name
|
|
546
|
+
post[:owner][:email] = options[:email] if options[:email]
|
|
525
547
|
|
|
526
|
-
|
|
527
|
-
|
|
548
|
+
if address = options[:billing_address] || options[:address]
|
|
549
|
+
owner_address = {}
|
|
550
|
+
owner_address[:line1] = address[:address1] if address[:address1]
|
|
551
|
+
owner_address[:line2] = address[:address2] if address[:address2]
|
|
552
|
+
owner_address[:country] = address[:country] if address[:country]
|
|
553
|
+
owner_address[:postal_code] = address[:zip] if address[:zip]
|
|
554
|
+
owner_address[:state] = address[:state] if address[:state]
|
|
555
|
+
owner_address[:city] = address[:city] if address[:city]
|
|
556
|
+
|
|
557
|
+
post[:owner][:phone] = address[:phone] if address[:phone]
|
|
558
|
+
post[:owner][:address] = owner_address
|
|
559
|
+
end
|
|
528
560
|
end
|
|
529
561
|
|
|
530
562
|
def parse(body)
|
|
@@ -586,7 +618,7 @@ module ActiveMerchant #:nodoc:
|
|
|
586
618
|
end
|
|
587
619
|
|
|
588
620
|
def api_version(options)
|
|
589
|
-
options[:version] || @options[:version] ||
|
|
621
|
+
options[:version] || @options[:version] || self.class::DEFAULT_API_VERSION
|
|
590
622
|
end
|
|
591
623
|
|
|
592
624
|
def api_request(method, endpoint, parameters = nil, options = {})
|
|
@@ -629,8 +661,8 @@ module ActiveMerchant #:nodoc:
|
|
|
629
661
|
return response.fetch('error', {})['charge'] unless success
|
|
630
662
|
|
|
631
663
|
if url == 'customers'
|
|
632
|
-
[response['id'], response
|
|
633
|
-
elsif method == :post && url.match(/customers\/.*\/cards/)
|
|
664
|
+
[response['id'], response.dig('sources', 'data').first&.dig('id')].join('|')
|
|
665
|
+
elsif method == :post && (url.match(/customers\/.*\/cards/) || url.match(/payment_methods\/.*\/attach/))
|
|
634
666
|
[response['customer'], response['id']].join('|')
|
|
635
667
|
else
|
|
636
668
|
response['id']
|