activemerchant 1.121.0 → 1.123.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +86 -0
  3. data/README.md +1 -1
  4. data/lib/active_merchant/billing/check.rb +13 -16
  5. data/lib/active_merchant/billing/credit_card.rb +3 -0
  6. data/lib/active_merchant/billing/credit_card_formatting.rb +1 -0
  7. data/lib/active_merchant/billing/credit_card_methods.rb +21 -12
  8. data/lib/active_merchant/billing/gateways/adyen.rb +15 -19
  9. data/lib/active_merchant/billing/gateways/authorize_net.rb +10 -8
  10. data/lib/active_merchant/billing/gateways/blue_pay.rb +29 -0
  11. data/lib/active_merchant/billing/gateways/blue_snap.rb +2 -2
  12. data/lib/active_merchant/billing/gateways/braintree_blue.rb +6 -3
  13. data/lib/active_merchant/billing/gateways/credorax.rb +2 -1
  14. data/lib/active_merchant/billing/gateways/cyber_source.rb +30 -3
  15. data/lib/active_merchant/billing/gateways/decidir.rb +7 -1
  16. data/lib/active_merchant/billing/gateways/elavon.rb +60 -28
  17. data/lib/active_merchant/billing/gateways/element.rb +2 -0
  18. data/lib/active_merchant/billing/gateways/global_collect.rb +19 -10
  19. data/lib/active_merchant/billing/gateways/kushki.rb +23 -0
  20. data/lib/active_merchant/billing/gateways/mercado_pago.rb +3 -2
  21. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +2 -0
  22. data/lib/active_merchant/billing/gateways/moka.rb +277 -0
  23. data/lib/active_merchant/billing/gateways/monei.rb +228 -144
  24. data/lib/active_merchant/billing/gateways/mundipagg.rb +14 -5
  25. data/lib/active_merchant/billing/gateways/nmi.rb +14 -9
  26. data/lib/active_merchant/billing/gateways/orbital.rb +28 -6
  27. data/lib/active_merchant/billing/gateways/pay_arc.rb +390 -0
  28. data/lib/active_merchant/billing/gateways/pay_trace.rb +404 -0
  29. data/lib/active_merchant/billing/gateways/payeezy.rb +4 -0
  30. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -0
  31. data/lib/active_merchant/billing/gateways/payflow.rb +9 -0
  32. data/lib/active_merchant/billing/gateways/payment_express.rb +2 -2
  33. data/lib/active_merchant/billing/gateways/paymentez.rb +5 -0
  34. data/lib/active_merchant/billing/gateways/paysafe.rb +291 -0
  35. data/lib/active_merchant/billing/gateways/payu_latam.rb +3 -3
  36. data/lib/active_merchant/billing/gateways/redsys.rb +35 -32
  37. data/lib/active_merchant/billing/gateways/safe_charge.rb +2 -0
  38. data/lib/active_merchant/billing/gateways/spreedly_core.rb +13 -4
  39. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +19 -1
  40. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +1 -1
  41. data/lib/active_merchant/billing/gateways/vpos.rb +49 -6
  42. data/lib/active_merchant/billing/gateways/worldpay.rb +39 -7
  43. data/lib/active_merchant/billing/three_d_secure_eci_mapper.rb +27 -0
  44. data/lib/active_merchant/billing.rb +1 -0
  45. data/lib/active_merchant/version.rb +1 -1
  46. metadata +8 -3
@@ -143,6 +143,7 @@ module ActiveMerchant #:nodoc:
143
143
  post[:sg_Descriptor] = options[:merchant_descriptor] if options[:merchant_descriptor]
144
144
  post[:sg_MerchantPhoneNumber] = options[:merchant_phone_number] if options[:merchant_phone_number]
145
145
  post[:sg_MerchantName] = options[:merchant_name] if options[:merchant_name]
146
+ post[:sg_ProductID] = options[:product_id] if options[:product_id]
146
147
  end
147
148
 
148
149
  def add_payment(post, payment, options = {})
@@ -185,6 +186,7 @@ module ActiveMerchant #:nodoc:
185
186
  post[:sg_Xid] = options[:three_d_secure][:xid]
186
187
  post[:sg_IsExternalMPI] = 1
187
188
  post[:sg_EnablePartialApproval] = options[:is_partial_approval]
189
+ post[:sg_challengePreference] = options[:three_d_secure][:challenge_preference] if options[:three_d_secure][:challenge_preference]
188
190
  end
189
191
 
190
192
  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
- name = "#{node.name.downcase}_#{childnode.name.downcase}"
258
- if name == 'payment_method_data' && !childnode.elements.empty?
259
- response[name.to_sym] = Hash.from_xml(childnode.to_s).values.first
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[name.to_sym] = childnode.text
270
+ response[composed_name.to_sym] = childnode.text
262
271
  end
263
272
  end
264
273
 
@@ -31,6 +31,7 @@ module ActiveMerchant #:nodoc:
31
31
  setup_future_usage(post, options)
32
32
  add_exemption(post, options)
33
33
  add_stored_credentials(post, options)
34
+ add_ntid(post, options)
34
35
  add_error_on_requires_action(post, options)
35
36
  request_three_d_secure(post, options)
36
37
 
@@ -295,6 +296,11 @@ module ActiveMerchant #:nodoc:
295
296
  post[:payment_method_options][:card][:moto] = true if options[:moto]
296
297
  end
297
298
 
299
+ # Stripe Payment Intents does not pass any parameters for cardholder/merchant initiated
300
+ # it also does not support installments for any country other than Mexico (reason for this is unknown)
301
+ # The only thing that Stripe PI requires for stored credentials to work currently is the network_transaction_id
302
+ # 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
303
+
298
304
  def add_stored_credentials(post, options = {})
299
305
  return unless options[:stored_credential] && !options[:stored_credential].values.all?(&:nil?)
300
306
 
@@ -304,8 +310,20 @@ module ActiveMerchant #:nodoc:
304
310
  post[:payment_method_options][:card][:mit_exemption] = {}
305
311
 
306
312
  # 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]
313
+ # The network_transaction_id can be sent in nested under stored credentials OR as its own field (add_ntid handles when it is sent in on its own)
314
+ # If it is sent is as its own field AND under stored credentials, the value sent under its own field is what will send.
308
315
  post[:payment_method_options][:card][:mit_exemption][:ds_transaction_id] = stored_credential[:ds_transaction_id] if stored_credential[:ds_transaction_id]
316
+ post[:payment_method_options][:card][:mit_exemption][:network_transaction_id] = stored_credential[:network_transaction_id] if stored_credential[:network_transaction_id]
317
+ end
318
+
319
+ def add_ntid(post, options = {})
320
+ return unless options[:network_transaction_id]
321
+
322
+ post[:payment_method_options] ||= {}
323
+ post[:payment_method_options][:card] ||= {}
324
+ post[:payment_method_options][:card][:mit_exemption] = {}
325
+
326
+ post[:payment_method_options][:card][:mit_exemption][:network_transaction_id] = options[:network_transaction_id] if options[:network_transaction_id]
309
327
  end
310
328
 
311
329
  def add_error_on_requires_action(post, options = {})
@@ -343,7 +343,7 @@ module ActiveMerchant #:nodoc:
343
343
  parameters[:software] = 'Active Merchant'
344
344
  parameters[:testmode] = (@options[:test] ? 1 : 0) unless parameters.has_key?(:testmode)
345
345
  seed = SecureRandom.hex(32).upcase
346
- hash = Digest::SHA1.hexdigest("#{parameters[:command]}:#{@options[:password]}:#{parameters[:amount]}:#{parameters[:invoice]}:#{seed}")
346
+ hash = Digest::SHA1.hexdigest("#{parameters[:command]}:#{@options[:pin] || @options[:password]}:#{parameters[:amount]}:#{parameters[:invoice]}:#{seed}")
347
347
  parameters[:hash] = "s/#{seed}/#{hash}/n"
348
348
 
349
349
  parameters.collect { |key, value| "UM#{key}=#{CGI.escape(value.to_s)}" }.join('&')
@@ -63,6 +63,42 @@ module ActiveMerchant #:nodoc:
63
63
  commit(:pci_buy_rollback, post)
64
64
  end
65
65
 
66
+ def credit(money, payment, options = {})
67
+ # Not permitted for foreign cards.
68
+ commerce = options[:commerce] || @options[:commerce]
69
+ commerce_branch = options[:commerce_branch] || @options[:commerce_branch]
70
+
71
+ token = generate_token(@shop_process_id, 'refund', commerce, commerce_branch, amount(money), currency(money))
72
+ post = {}
73
+ post[:token] = token
74
+ post[:commerce] = commerce.to_i
75
+ post[:commerce_branch] = commerce_branch.to_i
76
+ post[:shop_process_id] = @shop_process_id
77
+ add_invoice(post, money, options)
78
+ add_card_data(post, payment)
79
+ add_customer_data(post, options)
80
+ post[:origin_shop_process_id] = options[:original_shop_process_id] if options[:original_shop_process_id]
81
+ commit(:refund, post)
82
+ end
83
+
84
+ def refund(money, authorization, options = {})
85
+ commerce = options[:commerce] || @options[:commerce]
86
+ commerce_branch = options[:commerce_branch] || @options[:commerce_branch]
87
+ shop_process_id = options[:shop_process_id] || @shop_process_id
88
+ _, original_shop_process_id = authorization.to_s.split('#')
89
+
90
+ token = generate_token(shop_process_id, 'refund', commerce, commerce_branch, amount(money), currency(money))
91
+ post = {}
92
+ post[:token] = token
93
+ post[:commerce] = commerce.to_i
94
+ post[:commerce_branch] = commerce_branch.to_i
95
+ post[:shop_process_id] = shop_process_id
96
+ add_invoice(post, money, options)
97
+ add_customer_data(post, options)
98
+ post[:origin_shop_process_id] = original_shop_process_id || options[:original_shop_process_id]
99
+ commit(:refund, post)
100
+ end
101
+
66
102
  def supports_scrubbing?
67
103
  true
68
104
  end
@@ -146,15 +182,22 @@ module ActiveMerchant #:nodoc:
146
182
  end
147
183
 
148
184
  def message_from(response)
149
- response.dig('confirmation', 'extended_response_description') ||
150
- response.dig('confirmation', 'response_description') ||
151
- response.dig('confirmation', 'response_details') ||
152
- response.dig('messages', 0, 'key')
185
+ %w(confirmation refund).each do |m|
186
+ message =
187
+ response.dig(m, 'extended_response_description') ||
188
+ response.dig(m, 'response_description') ||
189
+ response.dig(m, 'response_details')
190
+ return message if message
191
+ end
192
+ [response.dig('messages', 0, 'key'), response.dig('messages', 0, 'dsc')].join(':')
153
193
  end
154
194
 
155
195
  def authorization_from(response)
156
- authorization_number = response.dig('confirmation', 'authorization_number')
157
- shop_process_id = response.dig('confirmation', 'shop_process_id')
196
+ response_body = response.dig('confirmation') || response.dig('refund')
197
+ return unless response_body
198
+
199
+ authorization_number = response_body.dig('authorization_number') || response_body.dig('authorization_code')
200
+ shop_process_id = response_body.dig('shop_process_id')
158
201
 
159
202
  "#{authorization_number}##{shop_process_id}"
160
203
  end
@@ -115,8 +115,9 @@ module ActiveMerchant #:nodoc:
115
115
  end
116
116
 
117
117
  def verify(payment_method, options = {})
118
+ amount = (eligible_for_0_auth?(payment_method, options) ? 0 : 100)
118
119
  MultiResponse.run(:use_first_response) do |r|
119
- r.process { authorize(100, payment_method, options) }
120
+ r.process { authorize(amount, payment_method, options) }
120
121
  r.process(:ignore_result) { void(r.authorization, options.merge(authorization_validated: true)) }
121
122
  end
122
123
  end
@@ -130,6 +131,10 @@ module ActiveMerchant #:nodoc:
130
131
  true
131
132
  end
132
133
 
134
+ def supports_network_tokenization?
135
+ true
136
+ end
137
+
133
138
  def scrub(transcript)
134
139
  transcript.
135
140
  gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
@@ -140,7 +145,7 @@ module ActiveMerchant #:nodoc:
140
145
  private
141
146
 
142
147
  def authorize_request(money, payment_method, options)
143
- commit('authorize', build_authorization_request(money, payment_method, options), 'AUTHORISED', options)
148
+ commit('authorize', build_authorization_request(money, payment_method, options), 'AUTHORISED', 'CAPTURED', options)
144
149
  end
145
150
 
146
151
  def capture_request(money, authorization, options)
@@ -235,7 +240,11 @@ module ActiveMerchant #:nodoc:
235
240
  end
236
241
 
237
242
  def build_void_request(authorization, options)
238
- build_order_modify_request(authorization, &:cancel)
243
+ if options[:cancel_or_refund]
244
+ build_order_modify_request(authorization, &:cancelOrRefund)
245
+ else
246
+ build_order_modify_request(authorization, &:cancel)
247
+ end
239
248
  end
240
249
 
241
250
  def build_refund_request(money, authorization, options)
@@ -389,6 +398,8 @@ module ActiveMerchant #:nodoc:
389
398
  add_amount(xml, amount, options)
390
399
  end
391
400
  end
401
+ elsif options[:payment_type] == :network_token
402
+ add_network_tokenization_card(xml, payment_method)
392
403
  else
393
404
  xml.paymentDetails credit_fund_transfer_attribute(options) do
394
405
  if options[:payment_type] == :token
@@ -407,7 +418,6 @@ module ActiveMerchant #:nodoc:
407
418
  xml.session 'shopperIPAddress' => options[:ip] if options[:ip]
408
419
  xml.session 'id' => options[:session_id] if options[:session_id]
409
420
  end
410
-
411
421
  if three_d_secure = options[:three_d_secure]
412
422
  add_three_d_secure(three_d_secure, xml)
413
423
  end
@@ -415,10 +425,26 @@ module ActiveMerchant #:nodoc:
415
425
  end
416
426
  end
417
427
 
428
+ def add_network_tokenization_card(xml, payment_method)
429
+ xml.paymentDetails do
430
+ xml.tag! 'EMVCO_TOKEN-SSL', 'type' => 'NETWORKTOKEN' do
431
+ xml.tokenNumber payment_method.number
432
+ xml.expiryDate do
433
+ xml.date(
434
+ 'month' => format(payment_method.month, :two_digits),
435
+ 'year' => format(payment_method.year, :four_digits_year)
436
+ )
437
+ end
438
+ xml.cryptogram payment_method.payment_cryptogram
439
+ xml.eciIndicator format(payment_method.eci, :two_digits)
440
+ end
441
+ end
442
+ end
443
+
418
444
  def add_three_d_secure(three_d_secure, xml)
419
445
  xml.info3DSecure do
420
446
  xml.threeDSVersion three_d_secure[:version]
421
- if /^2/.match?(three_d_secure[:version])
447
+ if three_d_secure[:version] && three_d_secure[:ds_transaction_id]
422
448
  xml.dsTransactionId three_d_secure[:ds_transaction_id]
423
449
  else
424
450
  xml.xid three_d_secure[:xid]
@@ -433,7 +459,7 @@ module ActiveMerchant #:nodoc:
433
459
  xml.expiryDate do
434
460
  xml.date(
435
461
  'month' => format(payment_method.month, :two_digits),
436
- 'year' => format(payment_method.year, :four_digits)
462
+ 'year' => format(payment_method.year, :four_digits_year)
437
463
  )
438
464
  end
439
465
 
@@ -730,7 +756,9 @@ module ActiveMerchant #:nodoc:
730
756
 
731
757
  def payment_details_from(payment_method)
732
758
  payment_details = {}
733
- if payment_method.respond_to?(:number)
759
+ if payment_method.is_a?(NetworkTokenizationCreditCard) && payment_method.source == :network_token
760
+ payment_details[:payment_type] = :network_token
761
+ elsif payment_method.respond_to?(:number)
734
762
  payment_details[:payment_type] = :credit
735
763
  else
736
764
  token_details = token_details_from_authorization(payment_method)
@@ -766,6 +794,10 @@ module ActiveMerchant #:nodoc:
766
794
  def card_code_for(payment_method)
767
795
  CARD_CODES[card_brand(payment_method)] || CARD_CODES['unknown']
768
796
  end
797
+
798
+ def eligible_for_0_auth?(payment_method, options = {})
799
+ payment_method.is_a?(CreditCard) && %w(visa master).include?(payment_method.brand) && options[:zero_dollar_auth]
800
+ end
769
801
  end
770
802
  end
771
803
  end
@@ -0,0 +1,27 @@
1
+ module ActiveMerchant
2
+ module Billing
3
+ module ThreeDSecureEciMapper
4
+ NON_THREE_D_SECURE_TRANSACTION = :non_three_d_secure_transaction
5
+ ATTEMPTED_AUTHENTICATION_TRANSACTION = :attempted_authentication_transaction
6
+ FULLY_AUTHENTICATED_TRANSACTION = :fully_authenticated_transaction
7
+
8
+ ECI_00_01_02_MAP = { '00' => NON_THREE_D_SECURE_TRANSACTION, '01' => ATTEMPTED_AUTHENTICATION_TRANSACTION, '02' => FULLY_AUTHENTICATED_TRANSACTION }.freeze
9
+ ECI_05_06_07_MAP = { '05' => FULLY_AUTHENTICATED_TRANSACTION, '06' => ATTEMPTED_AUTHENTICATION_TRANSACTION, '07' => NON_THREE_D_SECURE_TRANSACTION }.freeze
10
+ BRAND_TO_ECI_MAP = {
11
+ american_express: ECI_05_06_07_MAP,
12
+ dankort: ECI_05_06_07_MAP,
13
+ diners_club: ECI_05_06_07_MAP,
14
+ discover: ECI_05_06_07_MAP,
15
+ elo: ECI_05_06_07_MAP,
16
+ jcb: ECI_05_06_07_MAP,
17
+ maestro: ECI_00_01_02_MAP,
18
+ master: ECI_00_01_02_MAP,
19
+ visa: ECI_05_06_07_MAP
20
+ }.freeze
21
+
22
+ def self.map(brand, eci)
23
+ BRAND_TO_ECI_MAP.dig(brand, eci)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -13,3 +13,4 @@ require 'active_merchant/billing/apple_pay_payment_token'
13
13
  require 'active_merchant/billing/response'
14
14
  require 'active_merchant/billing/gateways'
15
15
  require 'active_merchant/billing/gateway'
16
+ require 'active_merchant/billing/three_d_secure_eci_mapper'
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = '1.121.0'
2
+ VERSION = '1.123.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.121.0
4
+ version: 1.123.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: 2021-06-09 00:00:00.000000000 Z
11
+ date: 2021-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -293,6 +293,7 @@ files:
293
293
  - lib/active_merchant/billing/gateways/migs/migs_codes.rb
294
294
  - lib/active_merchant/billing/gateways/modern_payments.rb
295
295
  - lib/active_merchant/billing/gateways/modern_payments_cim.rb
296
+ - lib/active_merchant/billing/gateways/moka.rb
296
297
  - lib/active_merchant/billing/gateways/monei.rb
297
298
  - lib/active_merchant/billing/gateways/moneris.rb
298
299
  - lib/active_merchant/billing/gateways/money_movers.rb
@@ -316,12 +317,14 @@ files:
316
317
  - lib/active_merchant/billing/gateways/pac_net_raven.rb
317
318
  - lib/active_merchant/billing/gateways/pagarme.rb
318
319
  - lib/active_merchant/billing/gateways/pago_facil.rb
320
+ - lib/active_merchant/billing/gateways/pay_arc.rb
319
321
  - lib/active_merchant/billing/gateways/pay_conex.rb
320
322
  - lib/active_merchant/billing/gateways/pay_gate_xml.rb
321
323
  - lib/active_merchant/billing/gateways/pay_hub.rb
322
324
  - lib/active_merchant/billing/gateways/pay_junction.rb
323
325
  - lib/active_merchant/billing/gateways/pay_junction_v2.rb
324
326
  - lib/active_merchant/billing/gateways/pay_secure.rb
327
+ - lib/active_merchant/billing/gateways/pay_trace.rb
325
328
  - lib/active_merchant/billing/gateways/paybox_direct.rb
326
329
  - lib/active_merchant/billing/gateways/payeezy.rb
327
330
  - lib/active_merchant/billing/gateways/payex.rb
@@ -343,6 +346,7 @@ files:
343
346
  - lib/active_merchant/billing/gateways/paypal_digital_goods.rb
344
347
  - lib/active_merchant/billing/gateways/paypal_express.rb
345
348
  - lib/active_merchant/billing/gateways/paypal_express_common.rb
349
+ - lib/active_merchant/billing/gateways/paysafe.rb
346
350
  - lib/active_merchant/billing/gateways/payscout.rb
347
351
  - lib/active_merchant/billing/gateways/paystation.rb
348
352
  - lib/active_merchant/billing/gateways/payu_in.rb
@@ -410,6 +414,7 @@ files:
410
414
  - lib/active_merchant/billing/payment_token.rb
411
415
  - lib/active_merchant/billing/rails.rb
412
416
  - lib/active_merchant/billing/response.rb
417
+ - lib/active_merchant/billing/three_d_secure_eci_mapper.rb
413
418
  - lib/active_merchant/connection.rb
414
419
  - lib/active_merchant/country.rb
415
420
  - lib/active_merchant/empty.rb
@@ -445,7 +450,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
445
450
  - !ruby/object:Gem::Version
446
451
  version: '0'
447
452
  requirements: []
448
- rubygems_version: 3.2.17
453
+ rubygems_version: 3.2.20
449
454
  signing_key:
450
455
  specification_version: 4
451
456
  summary: Framework and tools for dealing with credit card transactions.