activemerchant 1.133.0 → 1.137.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 (183) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +240 -0
  3. data/lib/active_merchant/billing/check.rb +2 -2
  4. data/lib/active_merchant/billing/compatibility.rb +4 -4
  5. data/lib/active_merchant/billing/credit_card.rb +11 -8
  6. data/lib/active_merchant/billing/credit_card_formatting.rb +4 -0
  7. data/lib/active_merchant/billing/credit_card_methods.rb +59 -6
  8. data/lib/active_merchant/billing/gateway.rb +9 -0
  9. data/lib/active_merchant/billing/gateways/adyen.rb +162 -43
  10. data/lib/active_merchant/billing/gateways/airwallex.rb +26 -12
  11. data/lib/active_merchant/billing/gateways/alelo.rb +23 -5
  12. data/lib/active_merchant/billing/gateways/authorize_net.rb +43 -35
  13. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +10 -6
  14. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +1 -3
  15. data/lib/active_merchant/billing/gateways/axcessms.rb +6 -2
  16. data/lib/active_merchant/billing/gateways/banwire.rb +4 -2
  17. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +7 -3
  18. data/lib/active_merchant/billing/gateways/blue_pay.rb +13 -5
  19. data/lib/active_merchant/billing/gateways/blue_snap.rb +5 -5
  20. data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +65 -20
  21. data/lib/active_merchant/billing/gateways/braintree_blue.rb +226 -73
  22. data/lib/active_merchant/billing/gateways/braintree_orange.rb +1 -1
  23. data/lib/active_merchant/billing/gateways/card_connect.rb +5 -2
  24. data/lib/active_merchant/billing/gateways/card_stream.rb +4 -6
  25. data/lib/active_merchant/billing/gateways/cashnet.rb +1 -1
  26. data/lib/active_merchant/billing/gateways/cecabank/cecabank_common.rb +36 -0
  27. data/lib/active_merchant/billing/gateways/cecabank/cecabank_json.rb +316 -0
  28. data/lib/active_merchant/billing/gateways/cecabank/cecabank_xml.rb +220 -0
  29. data/lib/active_merchant/billing/gateways/cecabank.rb +7 -240
  30. data/lib/active_merchant/billing/gateways/checkout_v2.rb +238 -34
  31. data/lib/active_merchant/billing/gateways/commerce_hub.rb +63 -6
  32. data/lib/active_merchant/billing/gateways/credorax.rb +3 -5
  33. data/lib/active_merchant/billing/gateways/cyber_source.rb +185 -47
  34. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +102 -58
  35. data/lib/active_merchant/billing/gateways/d_local.rb +26 -15
  36. data/lib/active_merchant/billing/gateways/data_cash.rb +21 -17
  37. data/lib/active_merchant/billing/gateways/datatrans.rb +279 -0
  38. data/lib/active_merchant/billing/gateways/decidir.rb +53 -18
  39. data/lib/active_merchant/billing/gateways/decidir_plus.rb +4 -1
  40. data/lib/active_merchant/billing/gateways/deepstack.rb +382 -0
  41. data/lib/active_merchant/billing/gateways/ebanx.rb +40 -36
  42. data/lib/active_merchant/billing/gateways/efsnet.rb +6 -2
  43. data/lib/active_merchant/billing/gateways/elavon.rb +99 -33
  44. data/lib/active_merchant/billing/gateways/element.rb +36 -7
  45. data/lib/active_merchant/billing/gateways/epay.rb +6 -2
  46. data/lib/active_merchant/billing/gateways/evo_ca.rb +6 -2
  47. data/lib/active_merchant/billing/gateways/eway.rb +4 -2
  48. data/lib/active_merchant/billing/gateways/eway_managed.rb +6 -2
  49. data/lib/active_merchant/billing/gateways/exact.rb +6 -2
  50. data/lib/active_merchant/billing/gateways/fat_zebra.rb +31 -3
  51. data/lib/active_merchant/billing/gateways/federated_canada.rb +6 -2
  52. data/lib/active_merchant/billing/gateways/first_pay/first_pay_common.rb +15 -0
  53. data/lib/active_merchant/billing/gateways/first_pay/first_pay_json.rb +190 -0
  54. data/lib/active_merchant/billing/gateways/first_pay/first_pay_xml.rb +183 -0
  55. data/lib/active_merchant/billing/gateways/first_pay.rb +6 -172
  56. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +6 -2
  57. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +7 -3
  58. data/lib/active_merchant/billing/gateways/flex_charge.rb +347 -0
  59. data/lib/active_merchant/billing/gateways/garanti.rb +4 -2
  60. data/lib/active_merchant/billing/gateways/global_collect.rb +45 -37
  61. data/lib/active_merchant/billing/gateways/hi_pay.rb +286 -0
  62. data/lib/active_merchant/billing/gateways/hps.rb +1 -1
  63. data/lib/active_merchant/billing/gateways/iats_payments.rb +7 -2
  64. data/lib/active_merchant/billing/gateways/inspire.rb +6 -4
  65. data/lib/active_merchant/billing/gateways/instapay.rb +7 -4
  66. data/lib/active_merchant/billing/gateways/ipg.rb +9 -5
  67. data/lib/active_merchant/billing/gateways/iridium.rb +15 -5
  68. data/lib/active_merchant/billing/gateways/itransact.rb +6 -2
  69. data/lib/active_merchant/billing/gateways/iveri.rb +3 -3
  70. data/lib/active_merchant/billing/gateways/ixopay.rb +2 -2
  71. data/lib/active_merchant/billing/gateways/jetpay.rb +4 -2
  72. data/lib/active_merchant/billing/gateways/jetpay_v2.rb +4 -2
  73. data/lib/active_merchant/billing/gateways/kushki.rb +72 -12
  74. data/lib/active_merchant/billing/gateways/linkpoint.rb +6 -2
  75. data/lib/active_merchant/billing/gateways/litle.rb +33 -50
  76. data/lib/active_merchant/billing/gateways/mastercard.rb +4 -4
  77. data/lib/active_merchant/billing/gateways/maxipago.rb +2 -2
  78. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +8 -5
  79. data/lib/active_merchant/billing/gateways/merchant_ware.rb +11 -4
  80. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +11 -4
  81. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +19 -3
  82. data/lib/active_merchant/billing/gateways/mercury.rb +6 -2
  83. data/lib/active_merchant/billing/gateways/metrics_global.rb +8 -6
  84. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +1 -0
  85. data/lib/active_merchant/billing/gateways/migs.rb +6 -2
  86. data/lib/active_merchant/billing/gateways/mit.rb +8 -3
  87. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +18 -10
  88. data/lib/active_merchant/billing/gateways/monei.rb +1 -1
  89. data/lib/active_merchant/billing/gateways/moneris.rb +9 -3
  90. data/lib/active_merchant/billing/gateways/money_movers.rb +6 -2
  91. data/lib/active_merchant/billing/gateways/nab_transact.rb +12 -4
  92. data/lib/active_merchant/billing/gateways/net_registry.rb +6 -2
  93. data/lib/active_merchant/billing/gateways/netbanx.rb +1 -3
  94. data/lib/active_merchant/billing/gateways/netbilling.rb +6 -2
  95. data/lib/active_merchant/billing/gateways/network_merchants.rb +6 -2
  96. data/lib/active_merchant/billing/gateways/nmi.rb +18 -6
  97. data/lib/active_merchant/billing/gateways/ogone.rb +6 -2
  98. data/lib/active_merchant/billing/gateways/openpay.rb +4 -2
  99. data/lib/active_merchant/billing/gateways/opp.rb +1 -2
  100. data/lib/active_merchant/billing/gateways/optimal_payment.rb +6 -2
  101. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +1 -3
  102. data/lib/active_merchant/billing/gateways/orbital.rb +83 -24
  103. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +7 -4
  104. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +6 -2
  105. data/lib/active_merchant/billing/gateways/pay_hub.rb +4 -2
  106. data/lib/active_merchant/billing/gateways/pay_junction.rb +6 -2
  107. data/lib/active_merchant/billing/gateways/pay_secure.rb +6 -2
  108. data/lib/active_merchant/billing/gateways/pay_trace.rb +31 -18
  109. data/lib/active_merchant/billing/gateways/payeezy.rb +19 -8
  110. data/lib/active_merchant/billing/gateways/payex.rb +4 -2
  111. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -1
  112. data/lib/active_merchant/billing/gateways/payflow.rb +1 -3
  113. data/lib/active_merchant/billing/gateways/payment_express.rb +8 -4
  114. data/lib/active_merchant/billing/gateways/paymentez.rb +23 -11
  115. data/lib/active_merchant/billing/gateways/paysafe.rb +12 -11
  116. data/lib/active_merchant/billing/gateways/payscout.rb +7 -4
  117. data/lib/active_merchant/billing/gateways/paystation.rb +7 -3
  118. data/lib/active_merchant/billing/gateways/payway.rb +6 -2
  119. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +2 -2
  120. data/lib/active_merchant/billing/gateways/pin.rb +22 -4
  121. data/lib/active_merchant/billing/gateways/plexo.rb +49 -10
  122. data/lib/active_merchant/billing/gateways/plugnpay.rb +6 -2
  123. data/lib/active_merchant/billing/gateways/priority.rb +6 -5
  124. data/lib/active_merchant/billing/gateways/psigate.rb +6 -2
  125. data/lib/active_merchant/billing/gateways/psl_card.rb +6 -2
  126. data/lib/active_merchant/billing/gateways/qbms.rb +6 -2
  127. data/lib/active_merchant/billing/gateways/quantum.rb +6 -2
  128. data/lib/active_merchant/billing/gateways/quickbooks.rb +6 -5
  129. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +7 -4
  130. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +6 -2
  131. data/lib/active_merchant/billing/gateways/rapyd.rb +148 -46
  132. data/lib/active_merchant/billing/gateways/reach.rb +11 -4
  133. data/lib/active_merchant/billing/gateways/redsys.rb +2 -10
  134. data/lib/active_merchant/billing/gateways/redsys_rest.rb +507 -0
  135. data/lib/active_merchant/billing/gateways/s5.rb +3 -3
  136. data/lib/active_merchant/billing/gateways/safe_charge.rb +36 -16
  137. data/lib/active_merchant/billing/gateways/sage.rb +12 -4
  138. data/lib/active_merchant/billing/gateways/sage_pay.rb +79 -5
  139. data/lib/active_merchant/billing/gateways/sallie_mae.rb +6 -2
  140. data/lib/active_merchant/billing/gateways/secure_net.rb +6 -2
  141. data/lib/active_merchant/billing/gateways/secure_pay.rb +8 -6
  142. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +12 -4
  143. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +6 -2
  144. data/lib/active_merchant/billing/gateways/securion_pay.rb +24 -10
  145. data/lib/active_merchant/billing/gateways/shift4.rb +17 -20
  146. data/lib/active_merchant/billing/gateways/shift4_v2.rb +117 -0
  147. data/lib/active_merchant/billing/gateways/simetrik.rb +17 -11
  148. data/lib/active_merchant/billing/gateways/skip_jack.rb +6 -2
  149. data/lib/active_merchant/billing/gateways/smart_ps.rb +7 -4
  150. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +4 -2
  151. data/lib/active_merchant/billing/gateways/spreedly_core.rb +2 -4
  152. data/lib/active_merchant/billing/gateways/stripe.rb +53 -21
  153. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +199 -50
  154. data/lib/active_merchant/billing/gateways/sum_up.rb +223 -0
  155. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +4 -2
  156. data/lib/active_merchant/billing/gateways/telr.rb +3 -4
  157. data/lib/active_merchant/billing/gateways/trans_first.rb +1 -2
  158. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +8 -16
  159. data/lib/active_merchant/billing/gateways/transact_pro.rb +1 -1
  160. data/lib/active_merchant/billing/gateways/trust_commerce.rb +6 -2
  161. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +9 -8
  162. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +6 -2
  163. data/lib/active_merchant/billing/gateways/vanco.rb +2 -4
  164. data/lib/active_merchant/billing/gateways/vantiv_express.rb +587 -0
  165. data/lib/active_merchant/billing/gateways/verifi.rb +6 -2
  166. data/lib/active_merchant/billing/gateways/viaklix.rb +6 -2
  167. data/lib/active_merchant/billing/gateways/visanet_peru.rb +2 -2
  168. data/lib/active_merchant/billing/gateways/vpos.rb +3 -3
  169. data/lib/active_merchant/billing/gateways/wirecard.rb +7 -3
  170. data/lib/active_merchant/billing/gateways/wompi.rb +5 -0
  171. data/lib/active_merchant/billing/gateways/worldpay.rb +140 -73
  172. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +13 -10
  173. data/lib/active_merchant/billing/gateways/xpay.rb +242 -0
  174. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  175. data/lib/active_merchant/billing/response.rb +2 -2
  176. data/lib/active_merchant/connection.rb +3 -17
  177. data/lib/active_merchant/country.rb +1 -0
  178. data/lib/active_merchant/errors.rb +10 -0
  179. data/lib/active_merchant/version.rb +1 -1
  180. data/lib/support/gateway_support.rb +2 -2
  181. data/lib/support/ssl_verify.rb +4 -4
  182. data/lib/support/ssl_version.rb +6 -6
  183. metadata +30 -9
@@ -70,6 +70,7 @@ module ActiveMerchant #:nodoc:
70
70
  add_level_3_data(post, options)
71
71
  add_data_airline(post, options)
72
72
  add_data_lodging(post, options)
73
+ add_metadata(post, options)
73
74
  commit('authorise', post, options)
74
75
  end
75
76
 
@@ -93,12 +94,28 @@ module ActiveMerchant #:nodoc:
93
94
  end
94
95
 
95
96
  def credit(money, payment, options = {})
96
- action = 'refundWithData'
97
+ action = options[:payout] ? 'payout' : 'refundWithData'
97
98
  post = init_post(options)
98
99
  add_invoice(post, money, options)
99
100
  add_payment(post, payment, options, action)
100
101
  add_shopper_reference(post, options)
101
102
  add_network_transaction_reference(post, options)
103
+
104
+ if action == 'payout'
105
+ add_shopper_interaction(post, payment, options)
106
+ add_fraud_offset(post, options)
107
+ add_fund_source(post, options)
108
+ add_recurring_contract(post, options)
109
+ add_shopper_data(post, payment, options)
110
+
111
+ if (address = options[:billing_address] || options[:address]) && address[:country]
112
+ add_billing_address(post, options, address)
113
+ end
114
+
115
+ post[:dateOfBirth] = options[:date_of_birth] if options[:date_of_birth]
116
+ post[:nationality] = options[:nationality] if options[:nationality]
117
+ end
118
+
102
119
  commit(action, post, options)
103
120
  end
104
121
 
@@ -230,12 +247,30 @@ module ActiveMerchant #:nodoc:
230
247
 
231
248
  def add_extra_data(post, payment, options)
232
249
  post[:telephoneNumber] = (options[:billing_address][:phone_number] if options.dig(:billing_address, :phone_number)) || (options[:billing_address][:phone] if options.dig(:billing_address, :phone)) || ''
233
- post[:fraudOffset] = options[:fraud_offset] if options[:fraud_offset]
234
250
  post[:selectedBrand] = options[:selected_brand] if options[:selected_brand]
235
251
  post[:selectedBrand] ||= NETWORK_TOKENIZATION_CARD_SOURCE[payment.source.to_s] if payment.is_a?(NetworkTokenizationCreditCard)
236
252
  post[:deliveryDate] = options[:delivery_date] if options[:delivery_date]
237
253
  post[:merchantOrderReference] = options[:merchant_order_reference] if options[:merchant_order_reference]
238
254
  post[:captureDelayHours] = options[:capture_delay_hours] if options[:capture_delay_hours]
255
+ post[:deviceFingerprint] = options[:device_fingerprint] if options[:device_fingerprint]
256
+ post[:shopperIP] = options[:shopper_ip] || options[:ip] if options[:shopper_ip] || options[:ip]
257
+ post[:shopperStatement] = options[:shopper_statement] if options[:shopper_statement]
258
+ post[:store] = options[:store] if options[:store]
259
+ post[:mcc] = options[:mcc] if options[:mcc]
260
+
261
+ add_shopper_data(post, payment, options)
262
+ add_additional_data(post, payment, options)
263
+ add_risk_data(post, options)
264
+ add_shopper_reference(post, options)
265
+ add_merchant_data(post, options)
266
+ add_fraud_offset(post, options)
267
+ end
268
+
269
+ def add_fraud_offset(post, options)
270
+ post[:fraudOffset] = options[:fraud_offset] if options[:fraud_offset]
271
+ end
272
+
273
+ def add_additional_data(post, payment, options)
239
274
  post[:additionalData] ||= {}
240
275
  post[:additionalData][:overwriteBrand] = normalize(options[:overwrite_brand]) if options[:overwrite_brand]
241
276
  post[:additionalData][:customRoutingFlag] = options[:custom_routing_flag] if options[:custom_routing_flag]
@@ -244,11 +279,7 @@ module ActiveMerchant #:nodoc:
244
279
  post[:additionalData][:adjustAuthorisationData] = options[:adjust_authorisation_data] if options[:adjust_authorisation_data]
245
280
  post[:additionalData][:industryUsage] = options[:industry_usage] if options[:industry_usage]
246
281
  post[:additionalData][:RequestedTestAcquirerResponseCode] = options[:requested_test_acquirer_response_code] if options[:requested_test_acquirer_response_code] && test?
247
- post[:deviceFingerprint] = options[:device_fingerprint] if options[:device_fingerprint]
248
- add_shopper_data(post, options)
249
- add_risk_data(post, options)
250
- add_shopper_reference(post, options)
251
- add_merchant_data(post, options)
282
+ post[:additionalData][:updateShopperStatement] = options[:update_shopper_statement] if options[:update_shopper_statement]
252
283
  end
253
284
 
254
285
  def extract_and_transform(mapper, from)
@@ -371,15 +402,6 @@ module ActiveMerchant #:nodoc:
371
402
  post[:additionalData].compact!
372
403
  end
373
404
 
374
- def add_shopper_data(post, options)
375
- post[:shopperEmail] = options[:email] if options[:email]
376
- post[:shopperEmail] = options[:shopper_email] if options[:shopper_email]
377
- post[:shopperIP] = options[:ip] if options[:ip]
378
- post[:shopperIP] = options[:shopper_ip] if options[:shopper_ip]
379
- post[:shopperStatement] = options[:shopper_statement] if options[:shopper_statement]
380
- post[:additionalData][:updateShopperStatement] = options[:update_shopper_statement] if options[:update_shopper_statement]
381
- end
382
-
383
405
  def add_shopper_statement(post, options)
384
406
  return unless options[:shopper_statement]
385
407
 
@@ -403,7 +425,7 @@ module ActiveMerchant #:nodoc:
403
425
 
404
426
  def add_risk_data(post, options)
405
427
  if (risk_data = options[:risk_data])
406
- risk_data = Hash[risk_data.map { |k, v| ["riskdata.#{k}", v] }]
428
+ risk_data = risk_data.map { |k, v| ["riskdata.#{k}", v] }.to_h
407
429
  post[:additionalData].merge!(risk_data)
408
430
  end
409
431
  end
@@ -473,30 +495,39 @@ module ActiveMerchant #:nodoc:
473
495
  def add_address(post, options)
474
496
  if address = options[:shipping_address]
475
497
  post[:deliveryAddress] = {}
476
- post[:deliveryAddress][:street] = address[:address1] || 'NA'
477
- post[:deliveryAddress][:houseNumberOrName] = address[:address2] || 'NA'
498
+ post[:deliveryAddress][:street] = options[:address_override] == true ? address[:address2] : address[:address1] || 'NA'
499
+ post[:deliveryAddress][:houseNumberOrName] = options[:address_override] == true ? address[:address1] : address[:address2] || 'NA'
478
500
  post[:deliveryAddress][:postalCode] = address[:zip] if address[:zip]
479
501
  post[:deliveryAddress][:city] = address[:city] || 'NA'
480
502
  post[:deliveryAddress][:stateOrProvince] = get_state(address)
481
- post[:deliveryAddress][:country] = address[:country] if address[:country]
503
+ post[:deliveryAddress][:country] = get_country(address)
482
504
  end
483
505
  return unless post[:bankAccount]&.kind_of?(Hash) || post[:card]&.kind_of?(Hash)
484
506
 
485
507
  if (address = options[:billing_address] || options[:address]) && address[:country]
486
- post[:billingAddress] = {}
487
- post[:billingAddress][:street] = address[:address1] || 'NA'
488
- post[:billingAddress][:houseNumberOrName] = address[:address2] || 'NA'
489
- post[:billingAddress][:postalCode] = address[:zip] if address[:zip]
490
- post[:billingAddress][:city] = address[:city] || 'NA'
491
- post[:billingAddress][:stateOrProvince] = get_state(address)
492
- post[:billingAddress][:country] = address[:country] if address[:country]
508
+ add_billing_address(post, options, address)
493
509
  end
494
510
  end
495
511
 
512
+ def add_billing_address(post, options, address)
513
+ post[:billingAddress] = {}
514
+ post[:billingAddress][:street] = options[:address_override] == true ? address[:address2] : address[:address1] || 'NA'
515
+ post[:billingAddress][:houseNumberOrName] = options[:address_override] == true ? address[:address1] : address[:address2] || 'NA'
516
+ post[:billingAddress][:postalCode] = address[:zip] if address[:zip]
517
+ post[:billingAddress][:city] = address[:city] || 'NA'
518
+ post[:billingAddress][:stateOrProvince] = get_state(address)
519
+ post[:billingAddress][:country] = get_country(address)
520
+ post[:telephoneNumber] = address[:phone_number] || address[:phone] || ''
521
+ end
522
+
496
523
  def get_state(address)
497
524
  address[:state] && !address[:state].blank? ? address[:state] : 'NA'
498
525
  end
499
526
 
527
+ def get_country(address)
528
+ address[:country].present? ? address[:country] : 'ZZ'
529
+ end
530
+
500
531
  def add_invoice(post, money, options)
501
532
  currency = options[:currency] || currency(money)
502
533
  amount = {
@@ -557,6 +588,17 @@ module ActiveMerchant #:nodoc:
557
588
  post[:card] = card
558
589
  end
559
590
 
591
+ def add_shopper_data(post, payment, options)
592
+ if payment && !payment.is_a?(String)
593
+ post[:shopperName] = {}
594
+ post[:shopperName][:firstName] = payment.first_name
595
+ post[:shopperName][:lastName] = payment.last_name
596
+ end
597
+
598
+ post[:shopperEmail] = options[:email] if options[:email]
599
+ post[:shopperEmail] = options[:shopper_email] if options[:shopper_email]
600
+ end
601
+
560
602
  def capture_options(options)
561
603
  return options.merge(idempotency_key: "#{options[:idempotency_key]}-cap") if options[:idempotency_key]
562
604
 
@@ -588,11 +630,12 @@ module ActiveMerchant #:nodoc:
588
630
  def add_recurring_contract(post, options = {})
589
631
  return unless options[:recurring_contract_type]
590
632
 
591
- recurring = {
592
- contract: options[:recurring_contract_type]
593
- }
594
-
595
- post[:recurring] = recurring
633
+ post[:recurring] = {}
634
+ post[:recurring][:contract] = options[:recurring_contract_type]
635
+ post[:recurring][:recurringDetailName] = options[:recurring_detail_name] if options[:recurring_detail_name]
636
+ post[:recurring][:recurringExpiry] = options[:recurring_expiry] if options[:recurring_expiry]
637
+ post[:recurring][:recurringFrequency] = options[:recurring_frequency] if options[:recurring_frequency]
638
+ post[:recurring][:tokenService] = options[:token_service] if options[:token_service]
596
639
  end
597
640
 
598
641
  def add_application_info(post, options)
@@ -688,10 +731,58 @@ module ActiveMerchant #:nodoc:
688
731
  }
689
732
  end
690
733
 
734
+ def add_fund_source(post, options)
735
+ return unless fund_source = options[:fund_source]
736
+
737
+ post[:fundSource] = {}
738
+ post[:fundSource][:additionalData] = fund_source[:additional_data] if fund_source[:additional_data]
739
+
740
+ if fund_source[:first_name] && fund_source[:last_name]
741
+ post[:fundSource][:shopperName] = {}
742
+ post[:fundSource][:shopperName][:firstName] = fund_source[:first_name]
743
+ post[:fundSource][:shopperName][:lastName] = fund_source[:last_name]
744
+ end
745
+
746
+ if (address = fund_source[:billing_address])
747
+ add_billing_address(post[:fundSource], options, address)
748
+ end
749
+ end
750
+
751
+ def add_metadata(post, options = {})
752
+ return unless options[:metadata]
753
+
754
+ post[:metadata] ||= {}
755
+ post[:metadata].merge!(options[:metadata]) if options[:metadata]
756
+ end
757
+
758
+ def add_header_fields(response)
759
+ return unless @response_headers.present?
760
+
761
+ headers = {}
762
+ headers['response_headers'] = {}
763
+ headers['response_headers']['transient_error'] = @response_headers['transient-error'] if @response_headers['transient-error']
764
+
765
+ response.merge!(headers)
766
+ end
767
+
691
768
  def parse(body)
692
769
  return {} if body.blank?
693
770
 
694
- JSON.parse(body)
771
+ response = JSON.parse(body)
772
+ add_header_fields(response)
773
+ response
774
+ end
775
+
776
+ # Override the regular handle response so we can access the headers
777
+ # set header fields and values so we can add them to the response body
778
+ def handle_response(response)
779
+ @response_headers = response.each_header.to_h if response.respond_to?(:header)
780
+ case response.code.to_i
781
+ when 200...300
782
+ response.body
783
+ else
784
+ raise ResponseError.new(response)
785
+ end
695
786
  end
696
787
 
697
788
  def commit(action, parameters, options)
@@ -706,7 +797,7 @@ module ActiveMerchant #:nodoc:
706
797
  success = success_from(action, response, options)
707
798
  Response.new(
708
799
  success,
709
- message_from(action, response),
800
+ message_from(action, response, options),
710
801
  response,
711
802
  authorization: authorization_from(action, parameters, response),
712
803
  test: test?,
@@ -726,8 +817,14 @@ module ActiveMerchant #:nodoc:
726
817
  end
727
818
 
728
819
  def endpoint(action)
729
- recurring = %w(disable storeToken).include?(action)
730
- recurring ? "Recurring/#{RECURRING_API_VERSION}/#{action}" : "Payment/#{PAYMENT_API_VERSION}/#{action}"
820
+ case action
821
+ when 'disable', 'storeToken'
822
+ "Recurring/#{RECURRING_API_VERSION}/#{action}"
823
+ when 'payout'
824
+ "Payout/#{PAYMENT_API_VERSION}/#{action}"
825
+ else
826
+ "Payment/#{PAYMENT_API_VERSION}/#{action}"
827
+ end
731
828
  end
732
829
 
733
830
  def url(action)
@@ -754,7 +851,7 @@ module ActiveMerchant #:nodoc:
754
851
  end
755
852
 
756
853
  def success_from(action, response, options)
757
- if %w[RedirectShopper ChallengeShopper].include?(response.dig('resultCode')) && !options[:execute_threed] && !options[:threed_dynamic]
854
+ if %w[RedirectShopper ChallengeShopper].include?(response.dig('resultCode')) && !options[:execute_threed] && (!options[:threed_dynamic] || options[:ignore_threed_dynamic])
758
855
  response['refusalReason'] = 'Received unexpected 3DS authentication response, but a 3DS initiation flag was not included in the request.'
759
856
  return false
760
857
  end
@@ -771,18 +868,29 @@ module ActiveMerchant #:nodoc:
771
868
  response['response'] == '[detail-successfully-disabled]'
772
869
  when 'refundWithData'
773
870
  response['resultCode'] == 'Received'
871
+ when 'payout'
872
+ return false unless response['resultCode'] && response['authCode']
873
+
874
+ %[AuthenticationFinished Authorised Received].include?(response['resultCode'])
774
875
  else
775
876
  false
776
877
  end
777
878
  end
778
879
 
779
- def message_from(action, response)
780
- return authorize_message_from(response) if %w(authorise authorise3d authorise3ds2).include?(action.to_s)
781
-
782
- response['response'] || response['message'] || response['result'] || response['resultCode']
880
+ def message_from(action, response, options = {})
881
+ case action.to_s
882
+ when 'authorise', 'authorise3d', 'authorise3ds2'
883
+ authorize_message_from(response, options)
884
+ when 'payout'
885
+ response['refusalReason'] || response['resultCode'] || response['message']
886
+ else
887
+ response['response'] || response['message'] || response['result'] || response['resultCode']
888
+ end
783
889
  end
784
890
 
785
- def authorize_message_from(response)
891
+ def authorize_message_from(response, options = {})
892
+ return raw_authorize_error_message(response) if options[:raw_error_message]
893
+
786
894
  if response['refusalReason'] && response['additionalData'] && (response['additionalData']['merchantAdviceCode'] || response['additionalData']['refusalReasonRaw'])
787
895
  "#{response['refusalReason']} | #{response['additionalData']['merchantAdviceCode'] || response['additionalData']['refusalReasonRaw']}"
788
896
  else
@@ -790,6 +898,14 @@ module ActiveMerchant #:nodoc:
790
898
  end
791
899
  end
792
900
 
901
+ def raw_authorize_error_message(response)
902
+ if response['refusalReason'] && response['additionalData'] && response['additionalData']['refusalReasonRaw']
903
+ "#{response['refusalReason']} | #{response['additionalData']['refusalReasonRaw']}"
904
+ else
905
+ response['refusalReason'] || response['resultCode'] || response['message'] || response['result']
906
+ end
907
+ end
908
+
793
909
  def authorization_from(action, parameters, response)
794
910
  return nil if response['pspReference'].nil?
795
911
 
@@ -811,7 +927,10 @@ module ActiveMerchant #:nodoc:
811
927
  end
812
928
 
813
929
  def error_code_from(response)
814
- STANDARD_ERROR_CODE_MAPPING[response['errorCode']] || response['errorCode']
930
+ response.dig('additionalData', 'refusalReasonRaw').try(:match, /^([a-zA-Z0-9 ]{1,5})(?=:)/).try(:[], 1).try(:strip) ||
931
+ STANDARD_ERROR_CODE_MAPPING[response['errorCode']] ||
932
+ response['errorCode'] ||
933
+ response['refusalReason']
815
934
  end
816
935
 
817
936
  def network_transaction_id_from(response)
@@ -32,7 +32,7 @@ module ActiveMerchant #:nodoc:
32
32
  @client_id = options[:client_id]
33
33
  @client_api_key = options[:client_api_key]
34
34
  super
35
- @access_token = setup_access_token
35
+ @access_token = options[:access_token] || setup_access_token
36
36
  end
37
37
 
38
38
  def purchase(money, card, options = {})
@@ -133,13 +133,27 @@ module ActiveMerchant #:nodoc:
133
133
  'x-client-id' => @client_id,
134
134
  'x-api-key' => @client_api_key
135
135
  }
136
- response = ssl_post(build_request_url(:login), nil, token_headers)
137
- JSON.parse(response)['token']
136
+
137
+ begin
138
+ raw_response = ssl_post(build_request_url(:login), nil, token_headers)
139
+ rescue ResponseError => e
140
+ raise OAuthResponseError.new(e)
141
+ else
142
+ response = JSON.parse(raw_response)
143
+ if (token = response['token'])
144
+ token
145
+ else
146
+ oauth_response = Response.new(false, response['message'])
147
+ raise OAuthResponseError.new(oauth_response)
148
+ end
149
+ end
138
150
  end
139
151
 
140
152
  def build_request_url(action, id = nil)
141
153
  base_url = (test? ? test_url : live_url)
142
- base_url + ENDPOINTS[action].to_s % { id: id }
154
+ endpoint = ENDPOINTS[action].to_s
155
+ endpoint = id.present? ? endpoint % { id: id } : endpoint
156
+ base_url + endpoint
143
157
  end
144
158
 
145
159
  def add_referrer_data(post)
@@ -278,11 +292,11 @@ module ActiveMerchant #:nodoc:
278
292
  pm_options = post.dig('payment_method_options', 'card')
279
293
 
280
294
  external_three_ds = {
281
- 'version': format_three_ds_version(three_d_secure),
282
- 'eci': three_d_secure[:eci]
295
+ version: format_three_ds_version(three_d_secure),
296
+ eci: three_d_secure[:eci]
283
297
  }.merge(three_ds_version_specific_fields(three_d_secure))
284
298
 
285
- pm_options ? pm_options.merge!('external_three_ds': external_three_ds) : post['payment_method_options'] = { 'card': { 'external_three_ds': external_three_ds } }
299
+ pm_options ? pm_options.merge!(external_three_ds: external_three_ds) : post['payment_method_options'] = { card: { external_three_ds: external_three_ds } }
286
300
  end
287
301
 
288
302
  def format_three_ds_version(three_d_secure)
@@ -295,14 +309,14 @@ module ActiveMerchant #:nodoc:
295
309
  def three_ds_version_specific_fields(three_d_secure)
296
310
  if three_d_secure[:version].to_f >= 2
297
311
  {
298
- 'authentication_value': three_d_secure[:cavv],
299
- 'ds_transaction_id': three_d_secure[:ds_transaction_id],
300
- 'three_ds_server_transaction_id': three_d_secure[:three_ds_server_trans_id]
312
+ authentication_value: three_d_secure[:cavv],
313
+ ds_transaction_id: three_d_secure[:ds_transaction_id],
314
+ three_ds_server_transaction_id: three_d_secure[:three_ds_server_trans_id]
301
315
  }
302
316
  else
303
317
  {
304
- 'cavv': three_d_secure[:cavv],
305
- 'xid': three_d_secure[:xid]
318
+ cavv: three_d_secure[:cavv],
319
+ xid: three_d_secure[:xid]
306
320
  }
307
321
  end
308
322
  end
@@ -110,8 +110,18 @@ module ActiveMerchant #:nodoc:
110
110
  'Content-Type' => 'application/x-www-form-urlencoded'
111
111
  }
112
112
 
113
- parsed = parse(ssl_post(url('captura-oauth-provider/oauth/token'), post_data(params), headers))
114
- Response.new(true, parsed[:access_token], parsed)
113
+ begin
114
+ raw_response = ssl_post(url('captura-oauth-provider/oauth/token'), post_data(params), headers)
115
+ rescue ResponseError => e
116
+ raise OAuthResponseError.new(e)
117
+ else
118
+ response = parse(raw_response)
119
+ if (access_token = response[:access_token])
120
+ Response.new(true, access_token, response)
121
+ else
122
+ raise OAuthResponseError.new(response)
123
+ end
124
+ end
115
125
  end
116
126
 
117
127
  def remote_encryption_key(access_token)
@@ -144,9 +154,11 @@ module ActiveMerchant #:nodoc:
144
154
  access_token: access_token,
145
155
  multiresp: multiresp.responses.present? ? multiresp : nil
146
156
  }
147
- rescue ResponseError => error
157
+ rescue ActiveMerchant::OAuthResponseError => e
158
+ raise e
159
+ rescue ResponseError => e
148
160
  # retry to generate a new access_token when the provided one is expired
149
- raise error unless try_again && %w(401 404).include?(error.response.code) && @options[:access_token].present?
161
+ raise e unless retry?(try_again, e, :access_token)
150
162
 
151
163
  @options.delete(:access_token)
152
164
  @options.delete(:encryption_key)
@@ -206,9 +218,11 @@ module ActiveMerchant #:nodoc:
206
218
  multiresp.process { resp }
207
219
 
208
220
  multiresp
221
+ rescue ActiveMerchant::OAuthResponseError => e
222
+ raise OAuthResponseError.new(e)
209
223
  rescue ActiveMerchant::ResponseError => e
210
224
  # Retry on a possible expired encryption key
211
- if try_again && %w(401 404).include?(e.response.code) && @options[:encryption_key].present?
225
+ if retry?(try_again, e, :encryption_key)
212
226
  @options.delete(:encryption_key)
213
227
  commit(action, body, options, false)
214
228
  else
@@ -217,6 +231,10 @@ module ActiveMerchant #:nodoc:
217
231
  end
218
232
  end
219
233
 
234
+ def retry?(try_again, error, key)
235
+ try_again && %w(401 404).include?(error.response.code) && @options[key].present?
236
+ end
237
+
220
238
  def success_from(action, response)
221
239
  case action
222
240
  when 'capture/transaction/refund'
@@ -85,11 +85,10 @@ module ActiveMerchant
85
85
  AVS_REASON_CODES = %w(27 45)
86
86
 
87
87
  TRACKS = {
88
- 1 => /^%(?<format_code>.)(?<pan>[\d]{1,19}+)\^(?<name>.{2,26})\^(?<expiration>[\d]{0,4}|\^)(?<service_code>[\d]{0,3}|\^)(?<discretionary_data>.*)\?\Z/,
89
- 2 => /\A;(?<pan>[\d]{1,19}+)=(?<expiration>[\d]{0,4}|=)(?<service_code>[\d]{0,3}|=)(?<discretionary_data>.*)\?\Z/
88
+ 1 => /^%(?<format_code>.)(?<pan>\d{1,19}+)\^(?<name>.{2,26})\^(?<expiration>\d{0,4}|\^)(?<service_code>\d{0,3}|\^)(?<discretionary_data>.*)\?\Z/,
89
+ 2 => /\A;(?<pan>\d{1,19}+)=(?<expiration>\d{0,4}|=)(?<service_code>\d{0,3}|=)(?<discretionary_data>.*)\?\Z/
90
90
  }.freeze
91
91
 
92
- APPLE_PAY_DATA_DESCRIPTOR = 'COMMON.APPLE.INAPP.PAYMENT'
93
92
  PAYMENT_METHOD_NOT_SUPPORTED_ERROR = '155'
94
93
  INELIGIBLE_FOR_ISSUING_CREDIT_ERROR = '54'
95
94
 
@@ -165,7 +164,7 @@ module ActiveMerchant
165
164
  xml.transactionType('refundTransaction')
166
165
  xml.amount(amount(amount))
167
166
 
168
- add_payment_source(xml, payment, options, :credit)
167
+ add_payment_method(xml, payment, options, :credit)
169
168
  xml.refTransId(transaction_id_from(options[:transaction_id])) if options[:transaction_id]
170
169
  add_invoice(xml, 'refundTransaction', options)
171
170
  add_customer_data(xml, payment, options)
@@ -262,7 +261,7 @@ module ActiveMerchant
262
261
  xml.transactionRequest do
263
262
  xml.transactionType(transaction_type)
264
263
  xml.amount(amount(amount))
265
- add_payment_source(xml, payment, options)
264
+ add_payment_method(xml, payment, options)
266
265
  add_invoice(xml, transaction_type, options)
267
266
  add_tax_fields(xml, options)
268
267
  add_duty_fields(xml, options)
@@ -273,6 +272,7 @@ module ActiveMerchant
273
272
  add_market_type_device_type(xml, payment, options)
274
273
  add_settings(xml, payment, options)
275
274
  add_user_fields(xml, amount, options)
275
+ add_surcharge_fields(xml, options)
276
276
  add_ship_from_address(xml, options)
277
277
  add_processing_options(xml, options)
278
278
  add_subsequent_auth_information(xml, options)
@@ -287,8 +287,9 @@ module ActiveMerchant
287
287
  add_tax_fields(xml, options)
288
288
  add_shipping_fields(xml, options)
289
289
  add_duty_fields(xml, options)
290
- add_payment_source(xml, payment, options)
290
+ add_payment_method(xml, payment, options)
291
291
  add_invoice(xml, transaction_type, options)
292
+ add_surcharge_fields(xml, options)
292
293
  add_tax_exempt_status(xml, options)
293
294
  end
294
295
  end
@@ -407,20 +408,27 @@ module ActiveMerchant
407
408
  end
408
409
  end
409
410
 
410
- def add_payment_source(xml, source, options, action = nil)
411
- return unless source
411
+ def add_payment_method(xml, payment_method, options, action = nil)
412
+ return unless payment_method
412
413
 
413
- if source.is_a?(String)
414
- add_token_payment_method(xml, source, options)
415
- elsif card_brand(source) == 'check'
416
- add_check(xml, source)
417
- elsif card_brand(source) == 'apple_pay'
418
- add_apple_pay_payment_token(xml, source)
414
+ case payment_method
415
+ when String
416
+ add_token_payment_method(xml, payment_method, options)
417
+ when Check
418
+ add_check(xml, payment_method)
419
419
  else
420
- add_credit_card(xml, source, action)
420
+ if network_token?(payment_method, options, action)
421
+ add_network_token(xml, payment_method)
422
+ else
423
+ add_credit_card(xml, payment_method, action)
424
+ end
421
425
  end
422
426
  end
423
427
 
428
+ def network_token?(payment_method, options, action)
429
+ payment_method.instance_of?(NetworkTokenizationCreditCard) && action != :credit
430
+ end
431
+
424
432
  def camel_case_lower(key)
425
433
  String(key).split('_').inject([]) { |buffer, e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
426
434
  end
@@ -499,7 +507,6 @@ module ActiveMerchant
499
507
  xml.cardNumber(truncate(credit_card.number, 16))
500
508
  xml.expirationDate(format(credit_card.month, :two_digits) + '/' + format(credit_card.year, :four_digits))
501
509
  xml.cardCode(credit_card.verification_value) if credit_card.valid_card_verification_value?(credit_card.verification_value, credit_card.brand)
502
- xml.cryptogram(credit_card.payment_cryptogram) if credit_card.is_a?(NetworkTokenizationCreditCard) && action != :credit
503
510
  end
504
511
  end
505
512
  end
@@ -526,17 +533,20 @@ module ActiveMerchant
526
533
  xml.customerPaymentProfileId(customer_payment_profile_id)
527
534
  end
528
535
 
529
- def add_apple_pay_payment_token(xml, apple_pay_payment_token)
536
+ def add_network_token(xml, payment_method)
530
537
  xml.payment do
531
- xml.opaqueData do
532
- xml.dataDescriptor(APPLE_PAY_DATA_DESCRIPTOR)
533
- xml.dataValue(Base64.strict_encode64(apple_pay_payment_token.payment_data.to_json))
538
+ xml.creditCard do
539
+ xml.cardNumber(truncate(payment_method.number, 16))
540
+ xml.expirationDate(format(payment_method.month, :two_digits) + '/' + format(payment_method.year, :four_digits))
541
+ xml.isPaymentToken(true)
542
+ xml.cryptogram(payment_method.payment_cryptogram)
534
543
  end
535
544
  end
536
545
  end
537
546
 
538
547
  def add_market_type_device_type(xml, payment, options)
539
- return if payment.is_a?(String) || card_brand(payment) == 'check' || card_brand(payment) == 'apple_pay'
548
+ return unless payment.is_a?(CreditCard)
549
+ return if payment.is_a?(NetworkTokenizationCreditCard)
540
550
 
541
551
  if valid_track_data
542
552
  xml.retail do
@@ -701,6 +711,16 @@ module ActiveMerchant
701
711
  end
702
712
  end
703
713
 
714
+ def add_surcharge_fields(xml, options)
715
+ surcharge = options[:surcharge] if options[:surcharge]
716
+ if surcharge.is_a?(Hash)
717
+ xml.surcharge do
718
+ xml.amount(amount(surcharge[:amount].to_i)) if surcharge[:amount]
719
+ xml.description(surcharge[:description]) if surcharge[:description]
720
+ end
721
+ end
722
+ end
723
+
704
724
  def add_shipping_fields(xml, options)
705
725
  shipping = options[:shipping]
706
726
  if shipping.is_a?(Hash)
@@ -754,13 +774,7 @@ module ActiveMerchant
754
774
  xml.customerProfileId options[:customer_profile_id]
755
775
  xml.paymentProfile do
756
776
  add_billing_address(xml, credit_card, options)
757
- xml.payment do
758
- xml.creditCard do
759
- xml.cardNumber(truncate(credit_card.number, 16))
760
- xml.expirationDate(format(credit_card.year, :four_digits) + '-' + format(credit_card.month, :two_digits))
761
- xml.cardCode(credit_card.verification_value) if credit_card.verification_value
762
- end
763
- end
777
+ add_credit_card(xml, credit_card, :cim_store_update)
764
778
  end
765
779
  end
766
780
  end
@@ -776,13 +790,7 @@ module ActiveMerchant
776
790
  xml.customerType('individual')
777
791
  add_billing_address(xml, credit_card, options)
778
792
  add_shipping_address(xml, options, 'shipToList')
779
- xml.payment do
780
- xml.creditCard do
781
- xml.cardNumber(truncate(credit_card.number, 16))
782
- xml.expirationDate(format(credit_card.year, :four_digits) + '-' + format(credit_card.month, :two_digits))
783
- xml.cardCode(credit_card.verification_value) if credit_card.verification_value
784
- end
785
- end
793
+ add_credit_card(xml, credit_card, :cim_store)
786
794
  end
787
795
  end
788
796
  end