activemerchant 1.123.0 → 1.126.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +206 -0
  3. data/lib/active_merchant/billing/check.rb +5 -8
  4. data/lib/active_merchant/billing/credit_card.rb +10 -0
  5. data/lib/active_merchant/billing/credit_card_methods.rb +18 -3
  6. data/lib/active_merchant/billing/gateway.rb +3 -2
  7. data/lib/active_merchant/billing/gateways/adyen.rb +66 -11
  8. data/lib/active_merchant/billing/gateways/airwallex.rb +341 -0
  9. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +2 -1
  10. data/lib/active_merchant/billing/gateways/blue_pay.rb +1 -1
  11. data/lib/active_merchant/billing/gateways/blue_snap.rb +31 -21
  12. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +6 -1
  13. data/lib/active_merchant/billing/gateways/braintree/token_nonce.rb +113 -0
  14. data/lib/active_merchant/billing/gateways/braintree_blue.rb +87 -15
  15. data/lib/active_merchant/billing/gateways/card_connect.rb +1 -1
  16. data/lib/active_merchant/billing/gateways/card_stream.rb +17 -13
  17. data/lib/active_merchant/billing/gateways/cashnet.rb +15 -5
  18. data/lib/active_merchant/billing/gateways/checkout_v2.rb +34 -5
  19. data/lib/active_merchant/billing/gateways/credorax.rb +10 -0
  20. data/lib/active_merchant/billing/gateways/cyber_source.rb +24 -36
  21. data/lib/active_merchant/billing/gateways/d_local.rb +61 -6
  22. data/lib/active_merchant/billing/gateways/decidir.rb +17 -1
  23. data/lib/active_merchant/billing/gateways/decidir_plus.rb +344 -0
  24. data/lib/active_merchant/billing/gateways/ebanx.rb +19 -3
  25. data/lib/active_merchant/billing/gateways/elavon.rb +6 -3
  26. data/lib/active_merchant/billing/gateways/element.rb +20 -2
  27. data/lib/active_merchant/billing/gateways/global_collect.rb +137 -32
  28. data/lib/active_merchant/billing/gateways/ipg.rb +415 -0
  29. data/lib/active_merchant/billing/gateways/kushki.rb +7 -0
  30. data/lib/active_merchant/billing/gateways/litle.rb +93 -1
  31. data/lib/active_merchant/billing/gateways/mercado_pago.rb +3 -1
  32. data/lib/active_merchant/billing/gateways/mit.rb +260 -0
  33. data/lib/active_merchant/billing/gateways/moka.rb +24 -11
  34. data/lib/active_merchant/billing/gateways/moneris.rb +35 -8
  35. data/lib/active_merchant/billing/gateways/mundipagg.rb +8 -6
  36. data/lib/active_merchant/billing/gateways/nmi.rb +27 -8
  37. data/lib/active_merchant/billing/gateways/orbital.rb +357 -319
  38. data/lib/active_merchant/billing/gateways/pay_arc.rb +9 -7
  39. data/lib/active_merchant/billing/gateways/pay_conex.rb +3 -1
  40. data/lib/active_merchant/billing/gateways/pay_trace.rb +1 -1
  41. data/lib/active_merchant/billing/gateways/payflow.rb +76 -6
  42. data/lib/active_merchant/billing/gateways/paymentez.rb +35 -9
  43. data/lib/active_merchant/billing/gateways/paysafe.rb +155 -34
  44. data/lib/active_merchant/billing/gateways/payu_latam.rb +31 -16
  45. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +3 -3
  46. data/lib/active_merchant/billing/gateways/pin.rb +31 -4
  47. data/lib/active_merchant/billing/gateways/priority.rb +369 -0
  48. data/lib/active_merchant/billing/gateways/rapyd.rb +258 -0
  49. data/lib/active_merchant/billing/gateways/realex.rb +18 -0
  50. data/lib/active_merchant/billing/gateways/safe_charge.rb +7 -6
  51. data/lib/active_merchant/billing/gateways/simetrik.rb +362 -0
  52. data/lib/active_merchant/billing/gateways/stripe.rb +30 -8
  53. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +175 -72
  54. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -1
  55. data/lib/active_merchant/billing/gateways/trust_commerce.rb +2 -1
  56. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +20 -6
  57. data/lib/active_merchant/billing/gateways/visanet_peru.rb +6 -2
  58. data/lib/active_merchant/billing/gateways/wompi.rb +193 -0
  59. data/lib/active_merchant/billing/gateways/worldpay.rb +196 -64
  60. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  61. data/lib/active_merchant/billing/response.rb +4 -0
  62. data/lib/active_merchant/version.rb +1 -1
  63. metadata +11 -2
@@ -0,0 +1,193 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class WompiGateway < Gateway
4
+ self.test_url = 'https://sync.sandbox.wompi.co/v1'
5
+ self.live_url = 'https://sync.production.wompi.co/v1'
6
+
7
+ self.supported_countries = ['CO']
8
+ self.default_currency = 'COP'
9
+ self.supported_cardtypes = %i[visa master american_express]
10
+
11
+ self.homepage_url = 'https://wompi.co/'
12
+ self.display_name = 'Wompi'
13
+
14
+ self.money_format = :cents
15
+
16
+ def initialize(options = {})
17
+ ## Sandbox keys have prefix pub_test_ and prv_test_
18
+ ## Production keys have prefix pub_prod_ and prv_prod_
19
+ begin
20
+ requires!(options, :prod_private_key, :prod_public_key)
21
+ rescue ArgumentError
22
+ begin
23
+ requires!(options, :test_private_key, :test_public_key)
24
+ rescue ArgumentError
25
+ raise ArgumentError, 'Gateway requires both test_private_key and test_public_key, or both prod_private_key and prod_public_key'
26
+ end
27
+ end
28
+ super
29
+ end
30
+
31
+ def purchase(money, payment, options = {})
32
+ post = {
33
+ reference: options[:reference] || generate_reference,
34
+ public_key: public_key
35
+ }
36
+ add_invoice(post, money, options)
37
+ add_card(post, payment, options)
38
+
39
+ commit('sale', post, '/transactions_sync')
40
+ end
41
+
42
+ def authorize(money, payment, options = {})
43
+ post = {
44
+ public_key: public_key,
45
+ type: 'CARD',
46
+ financial_operation: 'PREAUTHORIZATION'
47
+ }
48
+ add_auth_params(post, money, payment, options)
49
+
50
+ commit('authorize', post, '/payment_sources_sync')
51
+ end
52
+
53
+ def capture(money, authorization, options = {})
54
+ post = {
55
+ reference: options[:reference] || generate_reference,
56
+ public_key: public_key,
57
+ payment_source_id: authorization.to_i
58
+ }
59
+ add_invoice(post, money, options)
60
+ commit('capture', post, '/transactions_sync')
61
+ end
62
+
63
+ def refund(money, authorization, options = {})
64
+ post = { amount_in_cents: amount(money).to_i, transaction_id: authorization.to_s }
65
+ commit('refund', post, '/refunds_sync')
66
+ end
67
+
68
+ def void(authorization, options = {})
69
+ commit('void', {}, "/transactions/#{authorization}/void_sync")
70
+ end
71
+
72
+ def supports_scrubbing?
73
+ true
74
+ end
75
+
76
+ def scrub(transcript)
77
+ transcript.gsub(/(Bearer )\w+/, '\1[REDACTED]').
78
+ gsub(/(\\\"number\\\":\\\")\d+/, '\1[REDACTED]').
79
+ gsub(/(\\\"cvc\\\":\\\")\d+/, '\1[REDACTED]').
80
+ gsub(/(\\\"phone_number\\\":\\\")\+?\d+/, '\1[REDACTED]').
81
+ gsub(/(\\\"email\\\":\\\")\S+\\\",/, '\1[REDACTED]\",').
82
+ gsub(/(\\\"legal_id\\\":\\\")\d+/, '\1[REDACTED]')
83
+ end
84
+
85
+ private
86
+
87
+ def headers
88
+ {
89
+ 'Authorization' => "Bearer #{private_key}",
90
+ 'Content-Type' => 'application/json'
91
+ }
92
+ end
93
+
94
+ def generate_reference
95
+ SecureRandom.alphanumeric(12)
96
+ end
97
+
98
+ def private_key
99
+ test? ? options[:test_private_key] : options[:prod_private_key]
100
+ end
101
+
102
+ def public_key
103
+ test? ? options[:test_public_key] : options[:prod_public_key]
104
+ end
105
+
106
+ def add_invoice(post, money, options)
107
+ post[:amount_in_cents] = amount(money).to_i
108
+ post[:currency] = (options[:currency] || currency(money))
109
+ end
110
+
111
+ def add_card(post, card, options)
112
+ payment_method = {
113
+ type: 'CARD'
114
+ }
115
+ add_basic_card_info(payment_method, card, options)
116
+ post[:payment_method] = payment_method
117
+ end
118
+
119
+ def add_auth_params(post, money, card, options)
120
+ data = {
121
+ amount_in_cents: amount(money).to_i,
122
+ currency: (options[:currency] || currency(money))
123
+ }
124
+ add_basic_card_info(data, card, options)
125
+ post[:data] = data
126
+ end
127
+
128
+ def add_basic_card_info(post, card, options)
129
+ installments = options[:installments] ? options[:installments].to_i : 1
130
+ cvc = card.verification_value || nil
131
+
132
+ post[:number] = card.number
133
+ post[:exp_month] = card.month.to_s.rjust(2, '0')
134
+ post[:exp_year] = card.year.to_s[2..3]
135
+ post[:installments] = installments
136
+ post[:card_holder] = card.name
137
+ post[:cvc] = cvc if cvc && !cvc.empty?
138
+ end
139
+
140
+ def parse(body)
141
+ JSON.parse(body)
142
+ end
143
+
144
+ def commit(action, parameters, endpoint)
145
+ url = (test? ? test_url : live_url) + endpoint
146
+ response = parse(ssl_post(url, post_data(action, parameters), headers))
147
+ Response.new(
148
+ success_from(response),
149
+ message_from(response),
150
+ response,
151
+ authorization: authorization_from(response),
152
+ avs_result: nil,
153
+ cvv_result: nil,
154
+ test: test?,
155
+ error_code: error_code_from(response)
156
+ )
157
+ end
158
+
159
+ def handle_response(response)
160
+ case response.code.to_i
161
+ when 200...300, 401, 404, 422
162
+ response.body
163
+ else
164
+ raise ResponseError.new(response)
165
+ end
166
+ end
167
+
168
+ def success_from(response)
169
+ success_statuses.include? response.dig('data', 'status')
170
+ end
171
+
172
+ def success_statuses
173
+ %w(APPROVED AVAILABLE)
174
+ end
175
+
176
+ def message_from(response)
177
+ response.dig('data', 'status_message') || response.dig('error', 'reason') || response.dig('error', 'messages').to_json
178
+ end
179
+
180
+ def authorization_from(response)
181
+ response.dig('data', 'transaction_id') || response.dig('data', 'id') || response.dig('data', 'transaction', 'id')
182
+ end
183
+
184
+ def post_data(action, parameters = {})
185
+ parameters.to_json
186
+ end
187
+
188
+ def error_code_from(response)
189
+ response.dig('error', 'type') unless success_from(response)
190
+ end
191
+ end
192
+ end
193
+ end
@@ -8,13 +8,26 @@ module ActiveMerchant #:nodoc:
8
8
 
9
9
  self.default_currency = 'GBP'
10
10
  self.money_format = :cents
11
- self.supported_countries = %w(HK GB AU AD AR BE BR CA CH CN CO CR CY CZ DE DK ES FI FR GI GR HU IE IN IT JP LI LU MC MT MY MX NL NO NZ PA PE PL PT SE SG SI SM TR UM VA)
11
+ self.supported_countries = %w(AD AE AG AI AL AM AO AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BM BN BO BR BS BT BW
12
+ BY BZ CA CC CF CH CK CL CM CN CO CR CV CX CY CZ DE DJ DK DO DZ EC EE EG EH ES ET FI FJ FK
13
+ FM FO FR GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GT GU GW GY HK HM HN HR HT HU ID IE IL
14
+ IM IN IO IS IT JE JM JO JP KE KG KH KI KM KN KR KW KY KZ LA LC LI LK LS LT LU LV MA MC MD
15
+ ME MG MH MK ML MN MO MP MQ MR MS MT MU MV MW MX MY MZ NA NC NE NF NG NI NL NO NP NR NU NZ
16
+ OM PA PE PF PH PK PL PN PR PT PW PY QA RE RO RS RU RW SA SB SC SE SG SI SK SL SM SN ST SV
17
+ SZ TC TD TF TG TH TJ TK TM TO TR TT TV TW TZ UA UG US UY UZ VA VC VE VI VN VU WF WS YE YT
18
+ ZA ZM)
12
19
  self.supported_cardtypes = %i[visa master american_express discover jcb maestro elo naranja cabal unionpay]
13
- self.currencies_without_fractions = %w(HUF IDR ISK JPY KRW)
14
- self.currencies_with_three_decimal_places = %w(BHD KWD OMR RSD TND)
20
+ self.currencies_without_fractions = %w(HUF IDR JPY KRW BEF XOF XAF XPF GRD GNF ITL LUF MGA MGF PYG PTE RWF ESP TRL VND KMF)
21
+ self.currencies_with_three_decimal_places = %w(BHD KWD OMR TND LYD JOD IQD)
15
22
  self.homepage_url = 'http://www.worldpay.com/'
16
23
  self.display_name = 'Worldpay Global'
17
24
 
25
+ NETWORK_TOKEN_TYPE = {
26
+ apple_pay: 'APPLEPAY',
27
+ google_pay: 'GOOGLEPAY',
28
+ network_token: 'NETWORKTOKEN'
29
+ }
30
+
18
31
  CARD_CODES = {
19
32
  'visa' => 'VISA-SSL',
20
33
  'master' => 'ECMC-SSL',
@@ -64,7 +77,7 @@ module ActiveMerchant #:nodoc:
64
77
 
65
78
  def authorize(money, payment_method, options = {})
66
79
  requires!(options, :order_id)
67
- payment_details = payment_details_from(payment_method)
80
+ payment_details = payment_details(payment_method)
68
81
  authorize_request(money, payment_method, payment_details.merge(options))
69
82
  end
70
83
 
@@ -110,8 +123,12 @@ module ActiveMerchant #:nodoc:
110
123
  # and other transactions should be performed on a normal eCom-flagged
111
124
  # merchant ID.
112
125
  def credit(money, payment_method, options = {})
113
- payment_details = payment_details_from(payment_method)
114
- credit_request(money, payment_method, payment_details.merge(credit: true, **options))
126
+ payment_details = payment_details(payment_method)
127
+ if options[:fast_fund_credit]
128
+ fast_fund_credit_request(money, payment_method, payment_details.merge(credit: true, **options))
129
+ else
130
+ credit_request(money, payment_method, payment_details.merge(credit: true, **options))
131
+ end
115
132
  end
116
133
 
117
134
  def verify(payment_method, options = {})
@@ -139,7 +156,9 @@ module ActiveMerchant #:nodoc:
139
156
  transcript.
140
157
  gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
141
158
  gsub(%r((<cardNumber>)\d+(</cardNumber>)), '\1[FILTERED]\2').
142
- gsub(%r((<cvc>)[^<]+(</cvc>)), '\1[FILTERED]\2')
159
+ gsub(%r((<cvc>)[^<]+(</cvc>)), '\1[FILTERED]\2').
160
+ gsub(%r((<tokenNumber>)\d+(</tokenNumber>)), '\1[FILTERED]\2').
161
+ gsub(%r((<cryptogram>)[^<]+(</cryptogram>)), '\1[FILTERED]\2')
143
162
  end
144
163
 
145
164
  private
@@ -168,6 +187,10 @@ module ActiveMerchant #:nodoc:
168
187
  commit('credit', build_authorization_request(money, payment_method, options), :ok, 'SENT_FOR_REFUND', options)
169
188
  end
170
189
 
190
+ def fast_fund_credit_request(money, payment_method, options)
191
+ commit('fast_credit', build_fast_fund_credit_request(money, payment_method, options), :ok, 'PUSH_APPROVED', options)
192
+ end
193
+
171
194
  def store_request(credit_card, options)
172
195
  commit('store', build_store_request(credit_card, options), options)
173
196
  end
@@ -206,15 +229,12 @@ module ActiveMerchant #:nodoc:
206
229
  xml.order order_tag_attributes(options) do
207
230
  xml.description(options[:description].blank? ? 'Purchase' : options[:description])
208
231
  add_amount(xml, money, options)
209
- if options[:order_content]
210
- xml.orderContent do
211
- xml.cdata! options[:order_content]
212
- end
213
- end
232
+ add_order_content(xml, options)
214
233
  add_payment_method(xml, money, payment_method, options)
215
234
  add_shopper(xml, options)
216
235
  add_statement_narrative(xml, options)
217
236
  add_risk_data(xml, options[:risk_data]) if options[:risk_data]
237
+ add_sub_merchant_data(xml, options[:sub_merchant_data]) if options[:sub_merchant_data]
218
238
  add_hcg_additional_data(xml, options) if options[:hcg_additional_data]
219
239
  add_instalments_data(xml, options) if options[:instalments]
220
240
  add_moto_flag(xml, options) if options.dig(:metadata, :manual_entry)
@@ -226,7 +246,19 @@ module ActiveMerchant #:nodoc:
226
246
  end
227
247
 
228
248
  def order_tag_attributes(options)
229
- { 'orderCode' => options[:order_id], 'installationId' => options[:inst_id] || @options[:inst_id] }.reject { |_, v| !v.present? }
249
+ { 'orderCode' => clean_order_id(options[:order_id]), 'installationId' => options[:inst_id] || @options[:inst_id] }.reject { |_, v| !v.present? }
250
+ end
251
+
252
+ def clean_order_id(order_id)
253
+ order_id.to_s.gsub(/(\s|\||<|>|'|")/, '')[0..64]
254
+ end
255
+
256
+ def add_order_content(xml, options)
257
+ return unless options[:order_content]
258
+
259
+ xml.orderContent do
260
+ xml.cdata! options[:order_content]
261
+ end
230
262
  end
231
263
 
232
264
  def build_capture_request(money, authorization, options)
@@ -271,11 +303,69 @@ module ActiveMerchant #:nodoc:
271
303
  add_card(xml, credit_card, options)
272
304
  end
273
305
  end
306
+ add_transaction_identifier(xml, options) if network_transaction_id(options)
274
307
  end
275
308
  end
276
309
  end
277
310
  end
278
311
 
312
+ def network_transaction_id(options)
313
+ options[:stored_credential_transaction_id] || options.dig(:stored_credential, :network_transaction_id)
314
+ end
315
+
316
+ def add_transaction_identifier(xml, options)
317
+ xml.storedCredentials 'usage' => 'FIRST' do
318
+ xml.schemeTransactionIdentifier network_transaction_id(options)
319
+ end
320
+ end
321
+
322
+ def build_fast_fund_credit_request(money, payment_method, options)
323
+ build_request do |xml|
324
+ xml.submit do
325
+ xml.order order_tag_attributes(options) do
326
+ xml.description(options[:description].blank? ? 'Fast Fund Credit' : options[:description])
327
+ add_amount(xml, money, options)
328
+ add_order_content(xml, options)
329
+ add_payment_details_for_ff_credit(xml, payment_method, options)
330
+ add_shopper_id(xml, options)
331
+ end
332
+ end
333
+ end
334
+ end
335
+
336
+ def add_payment_details_for_ff_credit(xml, payment_method, options)
337
+ xml.paymentDetails do
338
+ xml.tag! 'FF_DISBURSE-SSL' do
339
+ if payment_method.is_a?(CreditCard)
340
+ add_card_for_ff_credit(xml, payment_method, options)
341
+ else
342
+ add_token_for_ff_credit(xml, payment_method, options)
343
+ end
344
+ end
345
+ end
346
+ end
347
+
348
+ def add_card_for_ff_credit(xml, payment_method, options)
349
+ xml.recipient do
350
+ xml.paymentInstrument do
351
+ xml.cardDetails do
352
+ add_card(xml, payment_method, options)
353
+ end
354
+ end
355
+ end
356
+ end
357
+
358
+ def add_token_for_ff_credit(xml, payment_method, options)
359
+ return unless payment_method.is_a?(String)
360
+
361
+ token_details = token_details_from_authorization(payment_method)
362
+
363
+ xml.tag! 'recipient', 'tokenScope' => token_details[:token_scope] do
364
+ xml.paymentTokenID token_details[:token_id]
365
+ add_authenticated_shopper_id(xml, token_details)
366
+ end
367
+ end
368
+
279
369
  def add_additional_3ds_data(xml, options)
280
370
  additional_data = { 'dfReferenceId' => options[:session_id] }
281
371
  additional_data['challengeWindowSize'] = options[:browser_size] if options[:browser_size]
@@ -314,6 +404,20 @@ module ActiveMerchant #:nodoc:
314
404
  end
315
405
  end
316
406
 
407
+ def add_sub_merchant_data(xml, options)
408
+ xml.subMerchantData do
409
+ xml.pfId options[:pf_id] if options[:pf_id]
410
+ xml.subName options[:sub_name] if options[:sub_name]
411
+ xml.subId options[:sub_id] if options[:sub_id]
412
+ xml.subStreet options[:sub_street] if options[:sub_street]
413
+ xml.subCity options[:sub_city] if options[:sub_city]
414
+ xml.subState options[:sub_state] if options[:sub_state]
415
+ xml.subCountryCode options[:sub_country_code] if options[:sub_country_code]
416
+ xml.subPostalCode options[:sub_postal_code] if options[:sub_postal_code]
417
+ xml.subTaxId options[:sub_tax_id] if options[:sub_tax_id]
418
+ end
419
+ end
420
+
317
421
  def add_shopper_account_risk_data(xml, shopper_account_risk_data)
318
422
  return unless shopper_account_risk_data
319
423
 
@@ -388,46 +492,33 @@ module ActiveMerchant #:nodoc:
388
492
  end
389
493
 
390
494
  def add_payment_method(xml, amount, payment_method, options)
391
- if options[:payment_type] == :pay_as_order
392
- if options[:merchant_code]
393
- xml.payAsOrder 'orderCode' => payment_method, 'merchantCode' => options[:merchant_code] do
394
- add_amount(xml, amount, options)
395
- end
396
- else
397
- xml.payAsOrder 'orderCode' => payment_method do
398
- add_amount(xml, amount, options)
399
- end
400
- end
401
- elsif options[:payment_type] == :network_token
495
+ case options[:payment_type]
496
+ when :pay_as_order
497
+ add_amount_for_pay_as_order(xml, amount, payment_method, options)
498
+ when :network_token
402
499
  add_network_tokenization_card(xml, payment_method)
403
500
  else
404
- xml.paymentDetails credit_fund_transfer_attribute(options) do
405
- if options[:payment_type] == :token
406
- xml.tag! 'TOKEN-SSL', 'tokenScope' => options[:token_scope] do
407
- xml.paymentTokenID options[:token_id]
408
- end
409
- else
410
- xml.tag! card_code_for(payment_method) do
411
- add_card(xml, payment_method, options)
412
- end
413
- end
414
- add_stored_credential_options(xml, options)
415
- if options[:ip] && options[:session_id]
416
- xml.session 'shopperIPAddress' => options[:ip], 'id' => options[:session_id]
417
- else
418
- xml.session 'shopperIPAddress' => options[:ip] if options[:ip]
419
- xml.session 'id' => options[:session_id] if options[:session_id]
420
- end
421
- if three_d_secure = options[:three_d_secure]
422
- add_three_d_secure(three_d_secure, xml)
423
- end
501
+ add_card_or_token(xml, payment_method, options)
502
+ end
503
+ end
504
+
505
+ def add_amount_for_pay_as_order(xml, amount, payment_method, options)
506
+ if options[:merchant_code]
507
+ xml.payAsOrder 'orderCode' => payment_method, 'merchantCode' => options[:merchant_code] do
508
+ add_amount(xml, amount, options)
509
+ end
510
+ else
511
+ xml.payAsOrder 'orderCode' => payment_method do
512
+ add_amount(xml, amount, options)
424
513
  end
425
514
  end
426
515
  end
427
516
 
428
517
  def add_network_tokenization_card(xml, payment_method)
518
+ token_type = NETWORK_TOKEN_TYPE.fetch(payment_method.source, 'NETWORKTOKEN')
519
+
429
520
  xml.paymentDetails do
430
- xml.tag! 'EMVCO_TOKEN-SSL', 'type' => 'NETWORKTOKEN' do
521
+ xml.tag! 'EMVCO_TOKEN-SSL', 'type' => token_type do
431
522
  xml.tokenNumber payment_method.number
432
523
  xml.expiryDate do
433
524
  xml.date(
@@ -435,13 +526,52 @@ module ActiveMerchant #:nodoc:
435
526
  'year' => format(payment_method.year, :four_digits_year)
436
527
  )
437
528
  end
529
+ name = card_holder_name(payment_method, options)
530
+ eci = format(payment_method.eci, :two_digits)
531
+ xml.cardHolderName name if name.present?
438
532
  xml.cryptogram payment_method.payment_cryptogram
439
- xml.eciIndicator format(payment_method.eci, :two_digits)
533
+ xml.eciIndicator eci.empty? ? '07' : eci
440
534
  end
441
535
  end
442
536
  end
443
537
 
444
- def add_three_d_secure(three_d_secure, xml)
538
+ def add_card_or_token(xml, payment_method, options)
539
+ xml.paymentDetails credit_fund_transfer_attribute(options) do
540
+ if options[:payment_type] == :token
541
+ add_token_details(xml, options)
542
+ else
543
+ add_card_details(xml, payment_method, options)
544
+ end
545
+ add_stored_credential_options(xml, options)
546
+ add_shopper_id(xml, options)
547
+ add_three_d_secure(xml, options)
548
+ end
549
+ end
550
+
551
+ def add_token_details(xml, options)
552
+ xml.tag! 'TOKEN-SSL', 'tokenScope' => options[:token_scope] do
553
+ xml.paymentTokenID options[:token_id]
554
+ end
555
+ end
556
+
557
+ def add_card_details(xml, payment_method, options)
558
+ xml.tag! card_code_for(payment_method) do
559
+ add_card(xml, payment_method, options)
560
+ end
561
+ end
562
+
563
+ def add_shopper_id(xml, options)
564
+ if options[:ip] && options[:session_id]
565
+ xml.session 'shopperIPAddress' => options[:ip], 'id' => options[:session_id]
566
+ else
567
+ xml.session 'shopperIPAddress' => options[:ip] if options[:ip]
568
+ xml.session 'id' => options[:session_id] if options[:session_id]
569
+ end
570
+ end
571
+
572
+ def add_three_d_secure(xml, options)
573
+ return unless three_d_secure = options[:three_d_secure]
574
+
445
575
  xml.info3DSecure do
446
576
  xml.threeDSVersion three_d_secure[:version]
447
577
  if three_d_secure[:version] && three_d_secure[:ds_transaction_id]
@@ -462,9 +592,7 @@ module ActiveMerchant #:nodoc:
462
592
  'year' => format(payment_method.year, :four_digits_year)
463
593
  )
464
594
  end
465
-
466
- card_holder_name = test? && options[:execute_threed] && !options[:three_ds_version]&.start_with?('2') ? '3D' : payment_method.name
467
- xml.cardHolderName card_holder_name
595
+ xml.cardHolderName card_holder_name(payment_method, options)
468
596
  xml.cvc payment_method.verification_value
469
597
 
470
598
  add_address(xml, (options[:billing_address] || options[:address]), options)
@@ -626,6 +754,7 @@ module ActiveMerchant #:nodoc:
626
754
  def commit(action, request, *success_criteria, options)
627
755
  xml = ssl_post(url, request, headers(options))
628
756
  raw = parse(action, xml)
757
+
629
758
  if options[:execute_threed]
630
759
  raw[:cookie] = @cookie if defined?(@cookie)
631
760
  raw[:session_id] = options[:session_id]
@@ -754,23 +883,22 @@ module ActiveMerchant #:nodoc:
754
883
  token_details
755
884
  end
756
885
 
757
- def payment_details_from(payment_method)
758
- payment_details = {}
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)
762
- payment_details[:payment_type] = :credit
886
+ def payment_details(payment_method)
887
+ case payment_method
888
+ when String
889
+ token_type_and_details(payment_method)
890
+ when NetworkTokenizationCreditCard
891
+ { payment_type: :network_token }
763
892
  else
764
- token_details = token_details_from_authorization(payment_method)
765
- payment_details.merge!(token_details)
766
- if token_details.has_key?(:token_id)
767
- payment_details[:payment_type] = :token
768
- else
769
- payment_details[:payment_type] = :pay_as_order
770
- end
893
+ { payment_type: :credit }
771
894
  end
895
+ end
896
+
897
+ def token_type_and_details(token)
898
+ token_details = token_details_from_authorization(token)
899
+ token_details[:payment_type] = token_details.has_key?(:token_id) ? :token : :pay_as_order
772
900
 
773
- payment_details
901
+ token_details
774
902
  end
775
903
 
776
904
  def credit_fund_transfer_attribute(options)
@@ -798,6 +926,10 @@ module ActiveMerchant #:nodoc:
798
926
  def eligible_for_0_auth?(payment_method, options = {})
799
927
  payment_method.is_a?(CreditCard) && %w(visa master).include?(payment_method.brand) && options[:zero_dollar_auth]
800
928
  end
929
+
930
+ def card_holder_name(payment_method, options)
931
+ test? && options[:execute_threed] && !options[:three_ds_version]&.start_with?('2') ? '3D' : payment_method.name
932
+ end
801
933
  end
802
934
  end
803
935
  end
@@ -14,7 +14,7 @@ module ActiveMerchant #:nodoc:
14
14
  self.require_verification_value = false
15
15
  self.require_name = false
16
16
 
17
- attr_accessor :payment_cryptogram, :eci, :transaction_id
17
+ attr_accessor :payment_cryptogram, :eci, :transaction_id, :metadata
18
18
  attr_writer :source
19
19
 
20
20
  SOURCES = %i(apple_pay android_pay google_pay network_token)
@@ -10,6 +10,10 @@ module ActiveMerchant #:nodoc:
10
10
  @success
11
11
  end
12
12
 
13
+ def failure?
14
+ !success?
15
+ end
16
+
13
17
  def test?
14
18
  @test
15
19
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveMerchant
2
- VERSION = '1.123.0'
2
+ VERSION = '1.126.0'
3
3
  end