activemerchant 1.129.0 → 1.133.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +51 -1
  3. data/lib/active_merchant/billing/credit_card.rb +2 -0
  4. data/lib/active_merchant/billing/credit_card_methods.rb +7 -3
  5. data/lib/active_merchant/billing/gateways/adyen.rb +82 -2
  6. data/lib/active_merchant/billing/gateways/authorize_net.rb +3 -2
  7. data/lib/active_merchant/billing/gateways/borgun.rb +11 -8
  8. data/lib/active_merchant/billing/gateways/braintree_blue.rb +8 -7
  9. data/lib/active_merchant/billing/gateways/checkout_v2.rb +15 -8
  10. data/lib/active_merchant/billing/gateways/commerce_hub.rb +13 -4
  11. data/lib/active_merchant/billing/gateways/cyber_source.rb +32 -7
  12. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +6 -8
  13. data/lib/active_merchant/billing/gateways/d_local.rb +1 -0
  14. data/lib/active_merchant/billing/gateways/global_collect.rb +41 -19
  15. data/lib/active_merchant/billing/gateways/ipg.rb +1 -1
  16. data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
  17. data/lib/active_merchant/billing/gateways/mit.rb +18 -18
  18. data/lib/active_merchant/billing/gateways/nmi.rb +5 -0
  19. data/lib/active_merchant/billing/gateways/paypal_express.rb +2 -0
  20. data/lib/active_merchant/billing/gateways/payu_latam.rb +1 -1
  21. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +1 -1
  22. data/lib/active_merchant/billing/gateways/redsys.rb +2 -1
  23. data/lib/active_merchant/billing/gateways/safe_charge.rb +2 -1
  24. data/lib/active_merchant/billing/gateways/shift4.rb +5 -2
  25. data/lib/active_merchant/billing/gateways/stripe.rb +21 -5
  26. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +111 -68
  27. data/lib/active_merchant/billing/gateways/vpos.rb +1 -1
  28. data/lib/active_merchant/billing/gateways/worldpay.rb +12 -24
  29. data/lib/active_merchant/version.rb +1 -1
  30. metadata +3 -3
@@ -34,9 +34,9 @@ module ActiveMerchant #:nodoc:
34
34
  add_connected_account(post, options)
35
35
  add_radar_data(post, options)
36
36
  add_shipping_address(post, options)
37
+ add_stored_credentials(post, options)
37
38
  setup_future_usage(post, options)
38
39
  add_exemption(post, options)
39
- add_stored_credentials(post, options)
40
40
  add_ntid(post, options)
41
41
  add_claim_without_transaction_id(post, options)
42
42
  add_error_on_requires_action(post, options)
@@ -76,22 +76,27 @@ module ActiveMerchant #:nodoc:
76
76
 
77
77
  def create_payment_method(payment_method, options = {})
78
78
  post_data = add_payment_method_data(payment_method, options)
79
-
80
79
  options = format_idempotency_key(options, 'pm')
81
80
  commit(:post, 'payment_methods', post_data, options)
82
81
  end
83
82
 
84
83
  def add_payment_method_data(payment_method, options = {})
85
- post_data = {}
86
- post_data[:type] = 'card'
87
- post_data[:card] = {}
88
- post_data[:card][:number] = payment_method.number
89
- post_data[:card][:exp_month] = payment_method.month
90
- post_data[:card][:exp_year] = payment_method.year
91
- post_data[:card][:cvc] = payment_method.verification_value if payment_method.verification_value
92
- add_billing_address(post_data, options)
93
- add_name_only(post_data, payment_method) if post_data[:billing_details].nil?
94
- post_data
84
+ post = {
85
+ type: 'card',
86
+ card: {
87
+ number: payment_method.number,
88
+ exp_month: payment_method.month,
89
+ exp_year: payment_method.year
90
+ }
91
+ }
92
+
93
+ post[:card][:cvc] = payment_method.verification_value if payment_method.verification_value
94
+ if billing = options[:billing_address] || options[:address]
95
+ post[:billing_details] = add_address(billing, options)
96
+ end
97
+
98
+ add_name_only(post, payment_method) if post[:billing_details].nil?
99
+ post
95
100
  end
96
101
 
97
102
  def add_payment_method_card_data_token(post_data, payment_method)
@@ -212,16 +217,7 @@ module ActiveMerchant #:nodoc:
212
217
  result = add_payment_method_token(params, payment_method, options)
213
218
  return result if result.is_a?(ActiveMerchant::Billing::Response)
214
219
 
215
- if options[:customer]
216
- customer_id = options[:customer]
217
- else
218
- post[:description] = options[:description] if options[:description]
219
- post[:email] = options[:email] if options[:email]
220
- options = format_idempotency_key(options, 'customer')
221
- post[:expand] = [:sources]
222
- customer = commit(:post, 'customers', post, options)
223
- customer_id = customer.params['id']
224
- end
220
+ customer_id = options[:customer] || customer(post, payment_method, options).params['id']
225
221
  options = format_idempotency_key(options, 'attach')
226
222
  attach_parameters = { customer: customer_id }
227
223
  attach_parameters[:validate] = options[:validate] unless options[:validate].nil?
@@ -231,6 +227,23 @@ module ActiveMerchant #:nodoc:
231
227
  end
232
228
  end
233
229
 
230
+ def customer(post, payment, options)
231
+ post[:description] = options[:description] if options[:description]
232
+ post[:expand] = [:sources]
233
+ post[:email] = options[:email]
234
+
235
+ if billing = options[:billing_address] || options[:address]
236
+ post.merge!(add_address(billing, options))
237
+ end
238
+
239
+ if shipping = options[:shipping_address]
240
+ post[:shipping] = add_address(shipping, options).except(:email)
241
+ end
242
+
243
+ options = format_idempotency_key(options, 'customer')
244
+ commit(:post, 'customers', post, options)
245
+ end
246
+
234
247
  def unstore(identification, options = {}, deprecated_options = {})
235
248
  if identification.include?('pm_')
236
249
  _, payment_method = identification.split('|')
@@ -399,17 +412,19 @@ module ActiveMerchant #:nodoc:
399
412
  post[:payment_method_options][:card][:moto] = true if options[:moto]
400
413
  end
401
414
 
402
- # Stripe Payment Intents does not pass any parameters for cardholder/merchant initiated
403
- # it also does not support installments for any country other than Mexico (reason for this is unknown)
404
- # The only thing that Stripe PI requires for stored credentials to work currently is the network_transaction_id
405
- # network_transaction_id is created when the card is authenticated using the field `setup_for_future_usage` with the value `off_session` see def setup_future_usage below
415
+ # Stripe Payment Intents now supports specifying on a transaction level basis stored credential information.
416
+ # The feature is currently gated but is listed as `stored_credential_transaction_type` inside the
417
+ # `post[:payment_method_options][:card]` hash. Since this is a beta field adding an extra check to use
418
+ # the existing logic by default. To be able to utilize this field, you must reach out to Stripe.
406
419
 
407
420
  def add_stored_credentials(post, options = {})
408
421
  return unless options[:stored_credential] && !options[:stored_credential].values.all?(&:nil?)
409
422
 
410
- stored_credential = options[:stored_credential]
411
423
  post[:payment_method_options] ||= {}
412
424
  post[:payment_method_options][:card] ||= {}
425
+ add_stored_credential_transaction_type(post, options) if options[:stored_credential_transaction_type]
426
+
427
+ stored_credential = options[:stored_credential]
413
428
  post[:payment_method_options][:card][:mit_exemption] = {}
414
429
 
415
430
  # Stripe PI accepts network_transaction_id and ds_transaction_id via mit field under card.
@@ -419,6 +434,50 @@ module ActiveMerchant #:nodoc:
419
434
  post[:payment_method_options][:card][:mit_exemption][:network_transaction_id] = stored_credential[:network_transaction_id] if stored_credential[:network_transaction_id]
420
435
  end
421
436
 
437
+ def add_stored_credential_transaction_type(post, options = {})
438
+ stored_credential = options[:stored_credential]
439
+ # Do not add anything unless these are present.
440
+ return unless stored_credential[:reason_type] && stored_credential[:initiator]
441
+
442
+ # Not compatible with off_session parameter.
443
+ options.delete(:off_session)
444
+ if stored_credential[:initial_transaction]
445
+ # Initial transactions must by CIT
446
+ return unless stored_credential[:initiator] == 'cardholder'
447
+
448
+ initial_transaction_stored_credential(post, stored_credential[:reason_type])
449
+ else
450
+ # Subsequent transaction
451
+ subsequent_transaction_stored_credential(post, stored_credential[:initiator], stored_credential[:reason_type])
452
+ end
453
+ end
454
+
455
+ def initial_transaction_stored_credential(post, reason_type)
456
+ if reason_type == 'unscheduled'
457
+ # Charge on-session and store card for future one-off payment use
458
+ post[:payment_method_options][:card][:stored_credential_transaction_type] = 'setup_off_session_unscheduled'
459
+ elsif reason_type == 'recurring'
460
+ # Charge on-session and store card for future recurring payment use
461
+ post[:payment_method_options][:card][:stored_credential_transaction_type] = 'setup_off_session_recurring'
462
+ else
463
+ # Charge on-session and store card for future on-session payment use.
464
+ post[:payment_method_options][:card][:stored_credential_transaction_type] = 'setup_on_session'
465
+ end
466
+ end
467
+
468
+ def subsequent_transaction_stored_credential(post, initiator, reason_type)
469
+ if initiator == 'cardholder'
470
+ # Charge on-session customer using previously stored card.
471
+ post[:payment_method_options][:card][:stored_credential_transaction_type] = 'stored_on_session'
472
+ elsif reason_type == 'recurring'
473
+ # Charge off-session customer using previously stored card for recurring transaction
474
+ post[:payment_method_options][:card][:stored_credential_transaction_type] = 'stored_off_session_recurring'
475
+ else
476
+ # Charge off-session customer using previously stored card for one-off transaction
477
+ post[:payment_method_options][:card][:stored_credential_transaction_type] = 'stored_off_session_unscheduled'
478
+ end
479
+ end
480
+
422
481
  def add_ntid(post, options = {})
423
482
  return unless options[:network_transaction_id]
424
483
 
@@ -478,30 +537,35 @@ module ActiveMerchant #:nodoc:
478
537
  def add_billing_address_for_card_tokenization(post, options = {})
479
538
  return unless (billing = options[:billing_address] || options[:address])
480
539
 
481
- post[:card][:address_city] = billing[:city] if billing[:city]
482
- post[:card][:address_country] = billing[:country] if billing[:country]
483
- post[:card][:address_line1] = billing[:address1] if billing[:address1]
484
- post[:card][:address_line2] = billing[:address2] if billing[:address2]
485
- post[:card][:address_zip] = billing[:zip] if billing[:zip]
486
- post[:card][:address_state] = billing[:state] if billing[:state]
540
+ billing = add_address(billing, options)
541
+ billing[:address].transform_keys! { |k| k == :postal_code ? :address_zip : k.to_s.prepend('address_').to_sym }
542
+
543
+ post[:card][:name] = billing[:name]
544
+ post[:card].merge!(billing[:address])
487
545
  end
488
546
 
489
- def add_billing_address(post, options = {})
490
- return unless billing = options[:billing_address] || options[:address]
547
+ def add_shipping_address(post, options = {})
548
+ return unless shipping = options[:shipping_address]
491
549
 
492
- email = billing[:email] || options[:email]
550
+ post[:shipping] = add_address(shipping, options).except(:email)
551
+ post[:shipping][:carrier] = (shipping[:carrier] || options[:shipping_carrier]) if shipping[:carrier] || options[:shipping_carrier]
552
+ post[:shipping][:tracking_number] = (shipping[:tracking_number] || options[:shipping_tracking_number]) if shipping[:tracking_number] || options[:shipping_tracking_number]
553
+ end
493
554
 
494
- post[:billing_details] = {}
495
- post[:billing_details][:address] = {}
496
- post[:billing_details][:address][:city] = billing[:city] if billing[:city]
497
- post[:billing_details][:address][:country] = billing[:country] if billing[:country]
498
- post[:billing_details][:address][:line1] = billing[:address1] if billing[:address1]
499
- post[:billing_details][:address][:line2] = billing[:address2] if billing[:address2]
500
- post[:billing_details][:address][:postal_code] = billing[:zip] if billing[:zip]
501
- post[:billing_details][:address][:state] = billing[:state] if billing[:state]
502
- post[:billing_details][:email] = email if email
503
- post[:billing_details][:name] = billing[:name] if billing[:name]
504
- post[:billing_details][:phone] = billing[:phone] if billing[:phone]
555
+ def add_address(address, options)
556
+ {
557
+ address: {
558
+ city: address[:city],
559
+ country: address[:country],
560
+ line1: address[:address1],
561
+ line2: address[:address2],
562
+ postal_code: address[:zip],
563
+ state: address[:state]
564
+ }.compact,
565
+ email: address[:email] || options[:email],
566
+ phone: address[:phone] || address[:phone_number],
567
+ name: address[:name]
568
+ }.compact
505
569
  end
506
570
 
507
571
  def add_name_only(post, payment_method)
@@ -511,27 +575,6 @@ module ActiveMerchant #:nodoc:
511
575
  post[:billing_details][:name] = name
512
576
  end
513
577
 
514
- def add_shipping_address(post, options = {})
515
- return unless shipping = options[:shipping_address]
516
-
517
- post[:shipping] = {}
518
-
519
- # fields required by Stripe PI
520
- post[:shipping][:address] = {}
521
- post[:shipping][:address][:line1] = shipping[:address1]
522
- post[:shipping][:name] = shipping[:name]
523
-
524
- # fields considered optional by Stripe PI
525
- post[:shipping][:address][:city] = shipping[:city] if shipping[:city]
526
- post[:shipping][:address][:country] = shipping[:country] if shipping[:country]
527
- post[:shipping][:address][:line2] = shipping[:address2] if shipping[:address2]
528
- post[:shipping][:address][:postal_code] = shipping[:zip] if shipping[:zip]
529
- post[:shipping][:address][:state] = shipping[:state] if shipping[:state]
530
- post[:shipping][:phone] = shipping[:phone_number] if shipping[:phone_number]
531
- post[:shipping][:carrier] = (shipping[:carrier] || options[:shipping_carrier]) if shipping[:carrier] || options[:shipping_carrier]
532
- post[:shipping][:tracking_number] = (shipping[:tracking_number] || options[:shipping_tracking_number]) if shipping[:tracking_number] || options[:shipping_tracking_number]
533
- end
534
-
535
578
  def format_idempotency_key(options, suffix)
536
579
  return options unless options[:idempotency_key]
537
580
 
@@ -9,7 +9,7 @@ module ActiveMerchant #:nodoc:
9
9
 
10
10
  self.supported_countries = ['PY']
11
11
  self.default_currency = 'PYG'
12
- self.supported_cardtypes = %i[visa master]
12
+ self.supported_cardtypes = %i[visa master panal]
13
13
 
14
14
  self.homepage_url = 'https://comercios.bancard.com.py'
15
15
  self.display_name = 'vPOS'
@@ -28,21 +28,6 @@ module ActiveMerchant #:nodoc:
28
28
  network_token: 'NETWORKTOKEN'
29
29
  }
30
30
 
31
- CARD_CODES = {
32
- 'visa' => 'VISA-SSL',
33
- 'master' => 'ECMC-SSL',
34
- 'discover' => 'DISCOVER-SSL',
35
- 'american_express' => 'AMEX-SSL',
36
- 'jcb' => 'JCB-SSL',
37
- 'maestro' => 'MAESTRO-SSL',
38
- 'diners_club' => 'DINERS-SSL',
39
- 'elo' => 'ELO-SSL',
40
- 'naranja' => 'NARANJA-SSL',
41
- 'cabal' => 'CABAL-SSL',
42
- 'unionpay' => 'CHINAUNIONPAY-SSL',
43
- 'unknown' => 'CARD-SSL'
44
- }
45
-
46
31
  AVS_CODE_MAP = {
47
32
  'A' => 'M', # Match
48
33
  'B' => 'P', # Postcode matches, address not verified
@@ -646,7 +631,7 @@ module ActiveMerchant #:nodoc:
646
631
  end
647
632
 
648
633
  def add_card_details(xml, payment_method, options)
649
- xml.tag! card_code_for(payment_method) do
634
+ xml.tag! 'CARD-SSL' do
650
635
  add_card(xml, payment_method, options)
651
636
  end
652
637
  end
@@ -683,7 +668,8 @@ module ActiveMerchant #:nodoc:
683
668
  'year' => format(payment_method.year, :four_digits_year)
684
669
  )
685
670
  end
686
- xml.cardHolderName card_holder_name(payment_method, options)
671
+ name = card_holder_name(payment_method, options)
672
+ xml.cardHolderName name if name.present?
687
673
  xml.cvc payment_method.verification_value
688
674
 
689
675
  add_address(xml, (options[:billing_address] || options[:address]), options)
@@ -995,13 +981,19 @@ module ActiveMerchant #:nodoc:
995
981
  case payment_method
996
982
  when String
997
983
  token_type_and_details(payment_method)
998
- when NetworkTokenizationCreditCard
999
- { payment_type: :network_token }
1000
984
  else
1001
- { payment_type: :credit }
985
+ type = network_token?(payment_method) ? :network_token : :credit
986
+
987
+ { payment_type: type }
1002
988
  end
1003
989
  end
1004
990
 
991
+ def network_token?(payment_method)
992
+ payment_method.respond_to?(:source) &&
993
+ payment_method.respond_to?(:payment_cryptogram) &&
994
+ payment_method.respond_to?(:eci)
995
+ end
996
+
1005
997
  def token_type_and_details(token)
1006
998
  token_details = token_details_from_authorization(token)
1007
999
  token_details[:payment_type] = token_details.has_key?(:token_id) ? :token : :pay_as_order
@@ -1027,10 +1019,6 @@ module ActiveMerchant #:nodoc:
1027
1019
  return 2
1028
1020
  end
1029
1021
 
1030
- def card_code_for(payment_method)
1031
- CARD_CODES[card_brand(payment_method)] || CARD_CODES['unknown']
1032
- end
1033
-
1034
1022
  def eligible_for_0_auth?(payment_method, options = {})
1035
1023
  payment_method.is_a?(CreditCard) && %w(visa master).include?(payment_method.brand) && options[:zero_dollar_auth]
1036
1024
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = '1.129.0'
2
+ VERSION = '1.133.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemerchant
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.129.0
4
+ version: 1.133.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Luetke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-03 00:00:00.000000000 Z
11
+ date: 2023-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -480,7 +480,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
480
480
  - !ruby/object:Gem::Version
481
481
  version: '0'
482
482
  requirements: []
483
- rubygems_version: 3.4.12
483
+ rubygems_version: 3.4.16
484
484
  signing_key:
485
485
  specification_version: 4
486
486
  summary: Framework and tools for dealing with credit card transactions.