activemerchant 1.90.0 → 1.99.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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +202 -0
  3. data/README.md +6 -2
  4. data/lib/active_merchant/billing/avs_result.rb +4 -5
  5. data/lib/active_merchant/billing/credit_card.rb +8 -0
  6. data/lib/active_merchant/billing/credit_card_methods.rb +81 -5
  7. data/lib/active_merchant/billing/gateway.rb +10 -0
  8. data/lib/active_merchant/billing/gateways/adyen.rb +206 -54
  9. data/lib/active_merchant/billing/gateways/bambora_apac.rb +226 -0
  10. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +43 -10
  11. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +3 -0
  12. data/lib/active_merchant/billing/gateways/beanstream.rb +11 -6
  13. data/lib/active_merchant/billing/gateways/blue_pay.rb +10 -8
  14. data/lib/active_merchant/billing/gateways/blue_snap.rb +211 -36
  15. data/lib/active_merchant/billing/gateways/bpoint.rb +4 -4
  16. data/lib/active_merchant/billing/gateways/braintree_blue.rb +79 -18
  17. data/lib/active_merchant/billing/gateways/card_connect.rb +6 -1
  18. data/lib/active_merchant/billing/gateways/cecabank.rb +20 -9
  19. data/lib/active_merchant/billing/gateways/checkout_v2.rb +98 -61
  20. data/lib/active_merchant/billing/gateways/credorax.rb +69 -4
  21. data/lib/active_merchant/billing/gateways/cyber_source.rb +85 -14
  22. data/lib/active_merchant/billing/gateways/d_local.rb +3 -3
  23. data/lib/active_merchant/billing/gateways/decidir.rb +245 -0
  24. data/lib/active_merchant/billing/gateways/elavon.rb +9 -0
  25. data/lib/active_merchant/billing/gateways/epay.rb +13 -2
  26. data/lib/active_merchant/billing/gateways/eway_rapid.rb +42 -12
  27. data/lib/active_merchant/billing/gateways/fat_zebra.rb +26 -7
  28. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +42 -3
  29. data/lib/active_merchant/billing/gateways/global_collect.rb +3 -7
  30. data/lib/active_merchant/billing/gateways/hps.rb +46 -1
  31. data/lib/active_merchant/billing/gateways/ipp.rb +1 -0
  32. data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
  33. data/lib/active_merchant/billing/gateways/litle.rb +61 -3
  34. data/lib/active_merchant/billing/gateways/mastercard.rb +30 -5
  35. data/lib/active_merchant/billing/gateways/mercado_pago.rb +1 -1
  36. data/lib/active_merchant/billing/gateways/migs.rb +8 -0
  37. data/lib/active_merchant/billing/gateways/monei.rb +31 -0
  38. data/lib/active_merchant/billing/gateways/moneris.rb +3 -4
  39. data/lib/active_merchant/billing/gateways/mundipagg.rb +37 -9
  40. data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
  41. data/lib/active_merchant/billing/gateways/netbanx.rb +4 -0
  42. data/lib/active_merchant/billing/gateways/nmi.rb +45 -5
  43. data/lib/active_merchant/billing/gateways/openpay.rb +1 -1
  44. data/lib/active_merchant/billing/gateways/opp.rb +20 -1
  45. data/lib/active_merchant/billing/gateways/orbital.rb +92 -11
  46. data/lib/active_merchant/billing/gateways/payflow.rb +64 -14
  47. data/lib/active_merchant/billing/gateways/payment_express.rb +7 -0
  48. data/lib/active_merchant/billing/gateways/paymentez.rb +7 -11
  49. data/lib/active_merchant/billing/gateways/paymill.rb +5 -0
  50. data/lib/active_merchant/billing/gateways/paypal.rb +14 -1
  51. data/lib/active_merchant/billing/gateways/paypal_express.rb +3 -1
  52. data/lib/active_merchant/billing/gateways/payu_latam.rb +6 -2
  53. data/lib/active_merchant/billing/gateways/pin.rb +19 -6
  54. data/lib/active_merchant/billing/gateways/pro_pay.rb +1 -1
  55. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +7 -1
  56. data/lib/active_merchant/billing/gateways/qvalent.rb +54 -1
  57. data/lib/active_merchant/billing/gateways/realex.rb +42 -5
  58. data/lib/active_merchant/billing/gateways/redsys.rb +113 -30
  59. data/lib/active_merchant/billing/gateways/spreedly_core.rb +43 -29
  60. data/lib/active_merchant/billing/gateways/stripe.rb +66 -34
  61. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +271 -0
  62. data/lib/active_merchant/billing/gateways/tns.rb +10 -5
  63. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +5 -5
  64. data/lib/active_merchant/billing/gateways/trust_commerce.rb +46 -6
  65. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +19 -8
  66. data/lib/active_merchant/billing/gateways/visanet_peru.rb +22 -10
  67. data/lib/active_merchant/billing/gateways/worldpay.rb +237 -34
  68. data/lib/active_merchant/country.rb +2 -1
  69. data/lib/active_merchant/version.rb +1 -1
  70. metadata +20 -4
@@ -324,15 +324,15 @@ module ActiveMerchant #:nodoc:
324
324
  :region => address[:state],
325
325
  :postal_code => scrub_zip(address[:zip]),
326
326
  }
327
- if address[:country] || address[:country_code_alpha2]
328
- mapped[:country_code_alpha2] = (address[:country] || address[:country_code_alpha2])
329
- elsif address[:country_name]
330
- mapped[:country_name] = address[:country_name]
331
- elsif address[:country_code_alpha3]
332
- mapped[:country_code_alpha3] = address[:country_code_alpha3]
333
- elsif address[:country_code_numeric]
334
- mapped[:country_code_numeric] = address[:country_code_numeric]
327
+
328
+ mapped[:country_code_alpha2] = (address[:country] || address[:country_code_alpha2]) if address[:country] || address[:country_code_alpha2]
329
+ mapped[:country_name] = address[:country_name] if address[:country_name]
330
+ mapped[:country_code_alpha3] = address[:country_code_alpha3] if address[:country_code_alpha3]
331
+ unless address[:country].blank?
332
+ mapped[:country_code_alpha3] ||= Country.find(address[:country]).code(:alpha3).value
335
333
  end
334
+ mapped[:country_code_numeric] = address[:country_code_numeric] if address[:country_code_numeric]
335
+
336
336
  mapped
337
337
  end
338
338
 
@@ -419,7 +419,9 @@ module ActiveMerchant #:nodoc:
419
419
  'street: A, zip: N' => 'C',
420
420
  'street: A, zip: U' => 'I',
421
421
  'street: A, zip: I' => 'I',
422
- 'street: A, zip: A' => 'I'
422
+ 'street: A, zip: A' => 'I',
423
+
424
+ 'street: B, zip: B' => 'B'
423
425
  }
424
426
  end
425
427
 
@@ -445,7 +447,6 @@ module ActiveMerchant #:nodoc:
445
447
 
446
448
  def create_transaction(transaction_type, money, credit_card_or_vault_id, options)
447
449
  transaction_params = create_transaction_parameters(money, credit_card_or_vault_id, options)
448
-
449
450
  commit do
450
451
  result = @braintree_gateway.transaction.send(transaction_type, transaction_params)
451
452
  response = Response.new(result.success?, message_from_transaction_result(result), response_params(result), response_options(result))
@@ -543,6 +544,17 @@ module ActiveMerchant #:nodoc:
543
544
  'token' => transaction.credit_card_details.token
544
545
  }
545
546
 
547
+ if transaction.risk_data
548
+ risk_data = {
549
+ 'id' => transaction.risk_data.id,
550
+ 'decision' => transaction.risk_data.decision,
551
+ 'device_data_captured' => transaction.risk_data.device_data_captured,
552
+ 'fraud_service_provider' => transaction.risk_data.fraud_service_provider
553
+ }
554
+ else
555
+ risk_data = nil
556
+ end
557
+
546
558
  {
547
559
  'order_id' => transaction.order_id,
548
560
  'amount' => transaction.amount.to_s,
@@ -553,6 +565,8 @@ module ActiveMerchant #:nodoc:
553
565
  'shipping_details' => shipping_details,
554
566
  'vault_customer' => vault_customer,
555
567
  'merchant_account_id' => transaction.merchant_account_id,
568
+ 'risk_data' => risk_data,
569
+ 'network_transaction_id' => transaction.network_transaction_id || nil,
556
570
  'processor_response_code' => response_code_from_result(result)
557
571
  }
558
572
  end
@@ -578,6 +592,14 @@ module ActiveMerchant #:nodoc:
578
592
  parameters[:options][:skip_advanced_fraud_checking] = options[:skip_advanced_fraud_checking]
579
593
  end
580
594
 
595
+ if options[:skip_avs]
596
+ parameters[:options][:skip_avs] = options[:skip_avs]
597
+ end
598
+
599
+ if options[:skip_cvv]
600
+ parameters[:options][:skip_cvv] = options[:skip_cvv]
601
+ end
602
+
581
603
  parameters[:custom_fields] = options[:custom_fields]
582
604
  parameters[:device_data] = options[:device_data] if options[:device_data]
583
605
  parameters[:service_fee_amount] = options[:service_fee_amount] if options[:service_fee_amount]
@@ -585,11 +607,14 @@ module ActiveMerchant #:nodoc:
585
607
  parameters[:merchant_account_id] = merchant_account_id
586
608
  end
587
609
 
588
- if options[:recurring]
610
+ if options[:transaction_source]
611
+ parameters[:transaction_source] = options[:transaction_source]
612
+ elsif options[:recurring]
589
613
  parameters[:recurring] = true
590
614
  end
591
615
 
592
616
  add_payment_method(parameters, credit_card_or_vault_id, options)
617
+ add_stored_credential_data(parameters, credit_card_or_vault_id, options)
593
618
 
594
619
  parameters[:billing] = map_address(options[:billing_address]) if options[:billing_address]
595
620
  parameters[:shipping] = map_address(options[:shipping_address]) if options[:shipping_address]
@@ -605,13 +630,7 @@ module ActiveMerchant #:nodoc:
605
630
  }
606
631
  end
607
632
 
608
- if options[:three_d_secure]
609
- parameters[:three_d_secure_pass_thru] = {
610
- cavv: options[:three_d_secure][:cavv],
611
- eci_flag: options[:three_d_secure][:eci],
612
- xid: options[:three_d_secure][:xid],
613
- }
614
- end
633
+ add_3ds_info(parameters, options[:three_d_secure])
615
634
 
616
635
  parameters[:tax_amount] = options[:tax_amount] if options[:tax_amount]
617
636
  parameters[:tax_exempt] = options[:tax_exempt] if options[:tax_exempt]
@@ -626,6 +645,48 @@ module ActiveMerchant #:nodoc:
626
645
  parameters
627
646
  end
628
647
 
648
+ def add_3ds_info(parameters, three_d_secure_opts)
649
+ return if empty?(three_d_secure_opts)
650
+ pass_thru = {}
651
+
652
+ pass_thru[:three_d_secure_version] = three_d_secure_opts[:version] if three_d_secure_opts[:version]
653
+ pass_thru[:eci_flag] = three_d_secure_opts[:eci] if three_d_secure_opts[:eci]
654
+ pass_thru[:cavv_algorithm] = three_d_secure_opts[:cavv_algorithm] if three_d_secure_opts[:cavv_algorithm]
655
+ pass_thru[:cavv] = three_d_secure_opts[:cavv] if three_d_secure_opts[:cavv]
656
+ pass_thru[:directory_response] = three_d_secure_opts[:directory_response_status] if three_d_secure_opts[:directory_response_status]
657
+ pass_thru[:authentication_response] = three_d_secure_opts[:authentication_response_status] if three_d_secure_opts[:authentication_response_status]
658
+
659
+ parameters[:three_d_secure_pass_thru] = pass_thru.merge(xid_or_ds_trans_id(three_d_secure_opts))
660
+ end
661
+
662
+ def xid_or_ds_trans_id(three_d_secure_opts)
663
+ if three_d_secure_opts[:version].to_f >= 2
664
+ { ds_transaction_id: three_d_secure_opts[:ds_transaction_id] }
665
+ else
666
+ { xid: three_d_secure_opts[:xid] }
667
+ end
668
+ end
669
+
670
+ def add_stored_credential_data(parameters, credit_card_or_vault_id, options)
671
+ return unless (stored_credential = options[:stored_credential])
672
+ parameters[:external_vault] = {}
673
+ if stored_credential[:initial_transaction]
674
+ parameters[:external_vault][:status] = 'will_vault'
675
+ else
676
+ parameters[:external_vault][:status] = 'vaulted'
677
+ parameters[:external_vault][:previous_network_transaction_id] = stored_credential[:network_transaction_id]
678
+ end
679
+ if stored_credential[:initiator] == 'merchant'
680
+ if stored_credential[:reason_type] == 'installment'
681
+ parameters[:transaction_source] = 'recurring'
682
+ else
683
+ parameters[:transaction_source] = stored_credential[:reason_type]
684
+ end
685
+ else
686
+ parameters[:transaction_source] = ''
687
+ end
688
+ end
689
+
629
690
  def add_payment_method(parameters, credit_card_or_vault_id, options)
630
691
  if credit_card_or_vault_id.is_a?(String) || credit_card_or_vault_id.is_a?(Integer)
631
692
  if options[:payment_method_token]
@@ -68,7 +68,7 @@ module ActiveMerchant #:nodoc:
68
68
  end
69
69
 
70
70
  def require_valid_domain!(options, param)
71
- if options.key?(param)
71
+ if options[param]
72
72
  raise ArgumentError.new('not a valid cardconnect domain') unless /\Dcardconnect.com:\d{1,}\D/ =~ options[param]
73
73
  end
74
74
  end
@@ -233,6 +233,7 @@ module ActiveMerchant #:nodoc:
233
233
  item.each_pair do |k, v|
234
234
  updated.merge!(k.to_s.gsub(/_/, '') => v)
235
235
  end
236
+ updated
236
237
  end
237
238
  end
238
239
  end
@@ -267,6 +268,7 @@ module ActiveMerchant #:nodoc:
267
268
  end
268
269
 
269
270
  def commit(action, parameters, verb: :put, path: '')
271
+ parameters[:frontendid] = application_id
270
272
  parameters[:merchid] = @options[:merchant_id]
271
273
  url = url(action, path)
272
274
  response = parse(ssl_request(verb, url, post_data(parameters), headers))
@@ -281,6 +283,9 @@ module ActiveMerchant #:nodoc:
281
283
  test: test?,
282
284
  error_code: error_code_from(response)
283
285
  )
286
+ rescue ResponseError => e
287
+ return Response.new(false, 'Unable to authenticate. Please check your credentials.', {}, :test => test?) if e.response.code == '401'
288
+ raise
284
289
  end
285
290
 
286
291
  def success_from(response)
@@ -1,7 +1,7 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class CecabankGateway < Gateway
4
- self.test_url = 'http://tpv.ceca.es:8000'
4
+ self.test_url = 'https://tpv.ceca.es'
5
5
  self.live_url = 'https://pgw.ceca.es'
6
6
 
7
7
  self.supported_countries = ['ES']
@@ -13,14 +13,14 @@ module ActiveMerchant #:nodoc:
13
13
 
14
14
  #### CECA's MAGIC NUMBERS
15
15
  CECA_NOTIFICATIONS_URL = 'NONE'
16
- CECA_ENCRIPTION = 'SHA1'
16
+ CECA_ENCRIPTION = 'SHA2'
17
17
  CECA_DECIMALS = '2'
18
18
  CECA_MODE = 'SSL'
19
19
  CECA_UI_LESS_LANGUAGE = 'XML'
20
20
  CECA_UI_LESS_LANGUAGE_REFUND = '1'
21
21
  CECA_UI_LESS_REFUND_PAGE = 'anulacion_xml'
22
- CECA_ACTION_REFUND = 'tpvanularparcialmente' # use partial refund's URL to avoid time frame limitations and decision logic on client side
23
- CECA_ACTION_PURCHASE = 'tpv'
22
+ CECA_ACTION_REFUND = 'anulaciones/anularParcial' # use partial refund's URL to avoid time frame limitations and decision logic on client side
23
+ CECA_ACTION_PURCHASE = 'tpv/compra'
24
24
  CECA_CURRENCIES_DICTIONARY = {'EUR' => 978, 'USD' => 840, 'GBP' => 826}
25
25
 
26
26
  # Creates a new CecabankGateway
@@ -168,18 +168,29 @@ module ActiveMerchant #:nodoc:
168
168
  'AcquirerBIN' => options[:acquirer_bin],
169
169
  'TerminalID' => options[:terminal_id]
170
170
  )
171
- url = (test? ? self.test_url : self.live_url) + "/cgi-bin/#{action}"
172
- xml = ssl_post(url, post_data(parameters))
171
+ url = (test? ? self.test_url : self.live_url) + "/tpvweb/#{action}.action"
172
+ xml = ssl_post("#{url}?", post_data(parameters))
173
173
  response = parse(xml)
174
174
  Response.new(
175
175
  response[:success],
176
- response[:message],
176
+ message_from(response),
177
177
  response,
178
178
  :test => test?,
179
- :authorization => build_authorization(response)
179
+ :authorization => build_authorization(response),
180
+ :error_code => response[:error_code]
180
181
  )
181
182
  end
182
183
 
184
+ def message_from(response)
185
+ if response[:message] == 'ERROR' && response[:error_message]
186
+ response[:error_message]
187
+ elsif response[:error_message]
188
+ "#{response[:message]} #{response[:error_message]}"
189
+ else
190
+ response[:message]
191
+ end
192
+ end
193
+
183
194
  def post_data(params)
184
195
  return nil unless params
185
196
 
@@ -231,7 +242,7 @@ module ActiveMerchant #:nodoc:
231
242
  CECA_NOTIFICATIONS_URL +
232
243
  CECA_NOTIFICATIONS_URL
233
244
  end
234
- Digest::SHA1.hexdigest(signature_fields)
245
+ Digest::SHA2.hexdigest(signature_fields)
235
246
  end
236
247
  end
237
248
  end
@@ -1,22 +1,22 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class CheckoutV2Gateway < Gateway
4
- self.display_name = 'Checkout.com V2 Gateway'
4
+ self.display_name = 'Checkout.com Unified Payments'
5
5
  self.homepage_url = 'https://www.checkout.com/'
6
- self.live_url = 'https://api2.checkout.com/v2'
7
- self.test_url = 'https://sandbox.checkout.com/api2/v2'
6
+ self.live_url = 'https://api.checkout.com'
7
+ self.test_url = 'https://api.sandbox.checkout.com'
8
8
 
9
9
  self.supported_countries = ['AD', 'AE', 'AT', 'BE', 'BG', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FO', 'FI', 'FR', 'GB', 'GI', 'GL', 'GR', 'HR', 'HU', 'IE', 'IS', 'IL', 'IT', 'LI', 'LT', 'LU', 'LV', 'MC', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SM', 'SK', 'SJ', 'TR', 'VA']
10
10
  self.default_currency = 'USD'
11
11
  self.money_format = :cents
12
- self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
12
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :maestro, :discover]
13
13
 
14
- def initialize(options={})
14
+ def initialize(options = {})
15
15
  requires!(options, :secret_key)
16
16
  super
17
17
  end
18
18
 
19
- def purchase(amount, payment_method, options={})
19
+ def purchase(amount, payment_method, options = {})
20
20
  multi = MultiResponse.run do |r|
21
21
  r.process { authorize(amount, payment_method, options) }
22
22
  r.process { capture(amount, r.authorization, options) }
@@ -28,18 +28,19 @@ module ActiveMerchant #:nodoc:
28
28
  response(:purchase, succeeded, merged_params)
29
29
  end
30
30
 
31
- def authorize(amount, payment_method, options={})
31
+ def authorize(amount, payment_method, options = {})
32
32
  post = {}
33
- post[:autoCapture] = 'n'
33
+ post[:capture] = false
34
34
  add_invoice(post, amount, options)
35
- add_payment_method(post, payment_method)
35
+ add_payment_method(post, payment_method, options)
36
36
  add_customer_data(post, options)
37
37
  add_transaction_data(post, options)
38
+ add_3ds(post, options)
38
39
 
39
40
  commit(:authorize, post)
40
41
  end
41
42
 
42
- def capture(amount, authorization, options={})
43
+ def capture(amount, authorization, options = {})
43
44
  post = {}
44
45
  add_invoice(post, amount, options)
45
46
  add_customer_data(post, options)
@@ -47,12 +48,12 @@ module ActiveMerchant #:nodoc:
47
48
  commit(:capture, post, authorization)
48
49
  end
49
50
 
50
- def void(authorization, options={})
51
+ def void(authorization, _options = {})
51
52
  post = {}
52
53
  commit(:void, post, authorization)
53
54
  end
54
55
 
55
- def refund(amount, authorization, options={})
56
+ def refund(amount, authorization, options = {})
56
57
  post = {}
57
58
  add_invoice(post, amount, options)
58
59
  add_customer_data(post, options)
@@ -60,72 +61,102 @@ module ActiveMerchant #:nodoc:
60
61
  commit(:refund, post, authorization)
61
62
  end
62
63
 
63
- def verify(credit_card, options={})
64
+ def verify(credit_card, options = {})
64
65
  MultiResponse.run(:use_first_response) do |r|
65
66
  r.process { authorize(100, credit_card, options) }
66
67
  r.process(:ignore_result) { void(r.authorization, options) }
67
68
  end
68
69
  end
69
70
 
71
+ def verify_payment(authorization, option={})
72
+ commit(:verify_payment, authorization)
73
+ end
74
+
70
75
  def supports_scrubbing?
71
76
  true
72
77
  end
73
78
 
74
79
  def scrub(transcript)
75
80
  transcript.
76
- gsub(%r((Authorization: )[^\\]*)i, '\1[FILTERED]').
77
- gsub(%r(("number\\":\\")\d+), '\1[FILTERED]').
78
- gsub(%r(("cvv\\":\\")\d+), '\1[FILTERED]')
81
+ gsub(/(Authorization: )[^\\]*/i, '\1[FILTERED]').
82
+ gsub(/("number\\":\\")\d+/, '\1[FILTERED]').
83
+ gsub(/("cvv\\":\\")\d+/, '\1[FILTERED]')
79
84
  end
80
85
 
81
86
  private
82
87
 
83
88
  def add_invoice(post, money, options)
84
- post[:value] = localized_amount(money, options[:currency])
85
- post[:trackId] = options[:order_id]
89
+ post[:amount] = localized_amount(money, options[:currency])
90
+ post[:reference] = options[:order_id]
86
91
  post[:currency] = options[:currency] || currency(money)
87
- post[:descriptor] = {}
88
- post[:descriptor][:name] = options[:descriptor_name] if options[:descriptor_name]
89
- post[:descriptor][:city] = options[:descriptor_city] if options[:descriptor_city]
92
+ if options[:descriptor_name] || options[:descriptor_city]
93
+ post[:billing_descriptor] = {}
94
+ post[:billing_descriptor][:name] = options[:descriptor_name] if options[:descriptor_name]
95
+ post[:billing_descriptor][:city] = options[:descriptor_city] if options[:descriptor_city]
96
+ end
97
+ post[:metadata] = {}
98
+ post[:metadata][:udf5] = application_id || 'ActiveMerchant'
90
99
  end
91
100
 
92
- def add_payment_method(post, payment_method)
93
- post[:card] = {}
94
- post[:card][:name] = payment_method.name
95
- post[:card][:number] = payment_method.number
96
- post[:card][:cvv] = payment_method.verification_value
97
- post[:card][:expiryYear] = format(payment_method.year, :four_digits)
98
- post[:card][:expiryMonth] = format(payment_method.month, :two_digits)
101
+ def add_payment_method(post, payment_method, options)
102
+ post[:source] = {}
103
+ post[:source][:type] = 'card'
104
+ post[:source][:name] = payment_method.name
105
+ post[:source][:number] = payment_method.number
106
+ post[:source][:cvv] = payment_method.verification_value
107
+ post[:source][:expiry_year] = format(payment_method.year, :four_digits)
108
+ post[:source][:expiry_month] = format(payment_method.month, :two_digits)
109
+ post[:source][:stored] = 'true' if options[:card_on_file] == true
99
110
  end
100
111
 
101
112
  def add_customer_data(post, options)
102
- post[:email] = options[:email] || 'unspecified@example.com'
103
- post[:customerIp] = options[:ip] if options[:ip]
113
+ post[:customer] = {}
114
+ post[:customer][:email] = options[:email] || nil
115
+ post[:payment_ip] = options[:ip] if options[:ip]
104
116
  address = options[:billing_address]
105
- if(address && post[:card])
106
- post[:card][:billingDetails] = {}
107
- post[:card][:billingDetails][:addressLine1] = address[:address1]
108
- post[:card][:billingDetails][:addressLine2] = address[:address2]
109
- post[:card][:billingDetails][:city] = address[:city]
110
- post[:card][:billingDetails][:state] = address[:state]
111
- post[:card][:billingDetails][:country] = address[:country]
112
- post[:card][:billingDetails][:postcode] = address[:zip]
113
- post[:card][:billingDetails][:phone] = { number: address[:phone] } unless address[:phone].blank?
117
+ if address && post[:source]
118
+ post[:source][:billing_address] = {}
119
+ post[:source][:billing_address][:address_line1] = address[:address1] unless address[:address1].blank?
120
+ post[:source][:billing_address][:address_line2] = address[:address2] unless address[:address2].blank?
121
+ post[:source][:billing_address][:city] = address[:city] unless address[:city].blank?
122
+ post[:source][:billing_address][:state] = address[:state] unless address[:state].blank?
123
+ post[:source][:billing_address][:country] = address[:country] unless address[:country].blank?
124
+ post[:source][:billing_address][:zip] = address[:zip] unless address[:zip].blank?
114
125
  end
115
126
  end
116
127
 
117
- def add_transaction_data(post, options={})
118
- post[:cardOnFile] = true if options[:card_on_file] == true
119
- post[:transactionIndicator] = options[:transaction_indicator] || 1
120
- post[:previousChargeId] = options[:previous_charge_id] if options[:previous_charge_id]
128
+ def add_transaction_data(post, options = {})
129
+ post[:payment_type] = 'Regular' if options[:transaction_indicator] == 1
130
+ post[:payment_type] = 'Recurring' if options[:transaction_indicator] == 2
131
+ post[:payment_type] = 'MOTO' if options[:transaction_indicator] == 3 || options.dig(:metadata, :manual_entry)
132
+ post[:previous_payment_id] = options[:previous_charge_id] if options[:previous_charge_id]
133
+ end
134
+
135
+ def add_3ds(post, options)
136
+ if options[:three_d_secure] || options[:execute_threed]
137
+ post[:'3ds'] = {}
138
+ post[:'3ds'][:enabled] = true
139
+ post[:success_url] = options[:callback_url] if options[:callback_url]
140
+ post[:failure_url] = options[:callback_url] if options[:callback_url]
141
+ end
142
+
143
+ if options[:three_d_secure]
144
+ post[:'3ds'][:eci] = options[:three_d_secure][:eci] if options[:three_d_secure][:eci]
145
+ post[:'3ds'][:cryptogram] = options[:three_d_secure][:cavv] if options[:three_d_secure][:cavv]
146
+ post[:'3ds'][:version] = options[:three_d_secure][:version] if options[:three_d_secure][:version]
147
+ post[:'3ds'][:xid] = options[:three_d_secure][:ds_transaction_id] || options[:three_d_secure][:xid]
148
+ end
121
149
  end
122
150
 
123
151
  def commit(action, post, authorization = nil)
124
152
  begin
125
- raw_response = ssl_post(url(post, action, authorization), post.to_json, headers)
153
+ raw_response = (action == :verify_payment ? ssl_get("#{base_url}/payments/#{post}", headers) : ssl_post(url(post, action, authorization), post.to_json, headers))
126
154
  response = parse(raw_response)
155
+ if action == :capture && response.key?('_links')
156
+ response['id'] = response['_links']['payment']['href'].split('/')[-1]
157
+ end
127
158
  rescue ResponseError => e
128
- raise unless(e.response.code.to_s =~ /4\d\d/)
159
+ raise unless e.response.code.to_s =~ /4\d\d/
129
160
  response = parse(e.response.body)
130
161
  end
131
162
 
@@ -154,15 +185,21 @@ module ActiveMerchant #:nodoc:
154
185
  def headers
155
186
  {
156
187
  'Authorization' => @options[:secret_key],
157
- 'Content-Type' => 'application/json;charset=UTF-8'
188
+ 'Content-Type' => 'application/json;charset=UTF-8',
158
189
  }
159
190
  end
160
191
 
161
- def url(post, action, authorization)
192
+ def url(_post, action, authorization)
162
193
  if action == :authorize
163
- "#{base_url}/charges/card"
194
+ "#{base_url}/payments"
195
+ elsif action == :capture
196
+ "#{base_url}/payments/#{authorization}/captures"
197
+ elsif action == :refund
198
+ "#{base_url}/payments/#{authorization}/refunds"
199
+ elsif action == :void
200
+ "#{base_url}/payments/#{authorization}/voids"
164
201
  else
165
- "#{base_url}/charges/#{authorization}/#{action}"
202
+ "#{base_url}/payments/#{authorization}/#{action}"
166
203
  end
167
204
  end
168
205
 
@@ -171,33 +208,33 @@ module ActiveMerchant #:nodoc:
171
208
  end
172
209
 
173
210
  def avs_result(response)
174
- response['card'] && response['card']['avsCheck'] ? AVSResult.new(code: response['card']['avsCheck']) : nil
211
+ response['source'] && response['source']['avs_check'] ? AVSResult.new(code: response['source']['avs_check']) : nil
175
212
  end
176
213
 
177
214
  def cvv_result(response)
178
- response['card'] && response['card']['cvvCheck'] ? CVVResult.new(response['card']['cvvCheck']) : nil
215
+ response['source'] && response['source']['cvv_check'] ? CVVResult.new(response['source']['cvv_check']) : nil
179
216
  end
180
217
 
181
218
  def parse(body)
182
219
  JSON.parse(body)
183
220
  rescue JSON::ParserError
184
221
  {
185
- 'message' => 'Invalid JSON response received from CheckoutV2Gateway. Please contact CheckoutV2Gateway if you continue to receive this message.',
222
+ 'message' => 'Invalid JSON response received from Checkout.com Unified Payments Gateway. Please contact Checkout.com if you continue to receive this message.',
186
223
  'raw_response' => scrub(body)
187
224
  }
188
225
  end
189
226
 
190
227
  def success_from(response)
191
- (response['responseCode'] == '10000' && !response['responseMessage'].start_with?('40')) || response['responseCode'] == '10100'
228
+ response['response_summary'] == 'Approved' || response['approved'] == true || !response.key?('response_summary') && response.key?('action_id')
192
229
  end
193
230
 
194
231
  def message_from(succeeded, response)
195
232
  if succeeded
196
233
  'Succeeded'
197
- elsif response['errors']
198
- response['message'] + ': ' + response['errors'].first
234
+ elsif response['error_type']
235
+ response['error_type'] + ': ' + response['error_codes'].first
199
236
  else
200
- response['responseMessage'] || response['message'] || 'Unable to read error message'
237
+ response['response_summary'] || response['response_code'] || 'Unable to read error message'
201
238
  end
202
239
  end
203
240
 
@@ -220,12 +257,12 @@ module ActiveMerchant #:nodoc:
220
257
 
221
258
  def error_code_from(succeeded, response)
222
259
  return if succeeded
223
- if response['errorCode'] && response['errorMessageCodes']
224
- "#{response["errorCode"]}: #{response["errorMessageCodes"].join(", ")}"
225
- elsif response['errorCode']
226
- response['errorCode']
260
+ if response['error_type'] && response['error_codes']
261
+ "#{response['error_type']}: #{response['error_codes'].join(', ')}"
262
+ elsif response['error_type']
263
+ response['error_type']
227
264
  else
228
- STANDARD_ERROR_CODE_MAPPING[response['responseCode']]
265
+ STANDARD_ERROR_CODE_MAPPING[response['response_code']]
229
266
  end
230
267
  end
231
268
  end