activemerchant 1.121.0 → 1.123.0

Sign up to get free protection for your applications and to get access to all the features.
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.