activemerchant 1.94.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +120 -1
  3. data/README.md +3 -0
  4. data/lib/active_merchant/billing/avs_result.rb +4 -5
  5. data/lib/active_merchant/billing/credit_card.rb +6 -0
  6. data/lib/active_merchant/billing/credit_card_methods.rb +65 -2
  7. data/lib/active_merchant/billing/gateway.rb +10 -0
  8. data/lib/active_merchant/billing/gateways/adyen.rb +119 -34
  9. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +43 -10
  10. data/lib/active_merchant/billing/gateways/beanstream.rb +11 -6
  11. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +3 -0
  12. data/lib/active_merchant/billing/gateways/blue_snap.rb +22 -2
  13. data/lib/active_merchant/billing/gateways/bpoint.rb +4 -4
  14. data/lib/active_merchant/billing/gateways/braintree_blue.rb +56 -9
  15. data/lib/active_merchant/billing/gateways/card_connect.rb +2 -1
  16. data/lib/active_merchant/billing/gateways/cecabank.rb +7 -7
  17. data/lib/active_merchant/billing/gateways/checkout_v2.rb +37 -27
  18. data/lib/active_merchant/billing/gateways/credorax.rb +69 -4
  19. data/lib/active_merchant/billing/gateways/cyber_source.rb +51 -11
  20. data/lib/active_merchant/billing/gateways/d_local.rb +1 -1
  21. data/lib/active_merchant/billing/gateways/decidir.rb +245 -0
  22. data/lib/active_merchant/billing/gateways/epay.rb +13 -2
  23. data/lib/active_merchant/billing/gateways/eway_rapid.rb +42 -12
  24. data/lib/active_merchant/billing/gateways/fat_zebra.rb +6 -0
  25. data/lib/active_merchant/billing/gateways/global_collect.rb +3 -7
  26. data/lib/active_merchant/billing/gateways/hps.rb +46 -1
  27. data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
  28. data/lib/active_merchant/billing/gateways/mastercard.rb +30 -5
  29. data/lib/active_merchant/billing/gateways/mercado_pago.rb +1 -1
  30. data/lib/active_merchant/billing/gateways/migs.rb +8 -0
  31. data/lib/active_merchant/billing/gateways/monei.rb +31 -0
  32. data/lib/active_merchant/billing/gateways/mundipagg.rb +33 -6
  33. data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
  34. data/lib/active_merchant/billing/gateways/nmi.rb +39 -1
  35. data/lib/active_merchant/billing/gateways/opp.rb +20 -1
  36. data/lib/active_merchant/billing/gateways/orbital.rb +60 -10
  37. data/lib/active_merchant/billing/gateways/payflow.rb +64 -14
  38. data/lib/active_merchant/billing/gateways/paymill.rb +5 -0
  39. data/lib/active_merchant/billing/gateways/paypal.rb +14 -1
  40. data/lib/active_merchant/billing/gateways/payu_latam.rb +6 -2
  41. data/lib/active_merchant/billing/gateways/qvalent.rb +43 -1
  42. data/lib/active_merchant/billing/gateways/realex.rb +32 -9
  43. data/lib/active_merchant/billing/gateways/redsys.rb +113 -30
  44. data/lib/active_merchant/billing/gateways/spreedly_core.rb +43 -29
  45. data/lib/active_merchant/billing/gateways/stripe.rb +38 -9
  46. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +271 -0
  47. data/lib/active_merchant/billing/gateways/tns.rb +10 -5
  48. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -2
  49. data/lib/active_merchant/billing/gateways/trust_commerce.rb +45 -6
  50. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +8 -5
  51. data/lib/active_merchant/billing/gateways/worldpay.rb +177 -39
  52. data/lib/active_merchant/country.rb +1 -0
  53. data/lib/active_merchant/version.rb +1 -1
  54. metadata +19 -4
@@ -13,7 +13,7 @@ module ActiveMerchant #:nodoc:
13
13
  self.homepage_url = 'https://www.barclaycardsmartpay.com/'
14
14
  self.display_name = 'Barclaycard Smartpay'
15
15
 
16
- API_VERSION = 'v30'
16
+ API_VERSION = 'v40'
17
17
 
18
18
  def initialize(options = {})
19
19
  requires!(options, :company, :merchant, :password)
@@ -37,7 +37,9 @@ module ActiveMerchant #:nodoc:
37
37
  post[:card] = credit_card_hash(creditcard)
38
38
  post[:billingAddress] = billing_address_hash(options) if options[:billing_address]
39
39
  post[:deliveryAddress] = shipping_address_hash(options) if options[:shipping_address]
40
- add_3ds(post, options) if options[:execute_threed]
40
+ post[:shopperStatement] = options[:shopper_statement] if options[:shopper_statement]
41
+
42
+ add_3ds(post, options)
41
43
  commit('authorise', post)
42
44
  end
43
45
 
@@ -186,7 +188,7 @@ module ActiveMerchant #:nodoc:
186
188
  end
187
189
 
188
190
  def parse_avs_code(response)
189
- AVS_MAPPING[response['avsResult'][0..1].strip] if response['avsResult']
191
+ AVS_MAPPING[response['additionalData']['avsResult'][0..1].strip] if response.dig('additionalData', 'avsResult')
190
192
  end
191
193
 
192
194
  def flatten_hash(hash, prefix = nil)
@@ -210,12 +212,18 @@ module ActiveMerchant #:nodoc:
210
212
  end
211
213
 
212
214
  def parse(response)
213
- Hash[
214
- response.split('&').map do |x|
215
- key, val = x.split('=', 2)
216
- [key.split('.').last, CGI.unescape(val)]
215
+ parsed_response = {}
216
+ params = CGI.parse(response)
217
+ params.each do |key, value|
218
+ parsed_key = key.split('.', 2)
219
+ if parsed_key.size > 1
220
+ parsed_response[parsed_key[0]] ||= {}
221
+ parsed_response[parsed_key[0]][parsed_key[1]] = value[0]
222
+ else
223
+ parsed_response[parsed_key[0]] = value[0]
217
224
  end
218
- ]
225
+ end
226
+ parsed_response
219
227
  end
220
228
 
221
229
  def post_data(data)
@@ -343,8 +351,33 @@ module ActiveMerchant #:nodoc:
343
351
  end
344
352
 
345
353
  def add_3ds(post, options)
346
- post[:additionalData] = { executeThreeD: 'true' }
347
- post[:browserInfo] = { userAgent: options[:user_agent], acceptHeader: options[:accept_header] }
354
+ if three_ds_2_options = options[:three_ds_2]
355
+ device_channel = three_ds_2_options[:channel]
356
+ if device_channel == 'app'
357
+ post[:threeDS2RequestData] = { deviceChannel: device_channel }
358
+ else
359
+ add_browser_info(three_ds_2_options[:browser_info], post)
360
+ post[:threeDS2RequestData] = { deviceChannel: device_channel, notificationURL: three_ds_2_options[:notification_url] }
361
+ end
362
+ else
363
+ return unless options[:execute_threed] || options[:threed_dynamic]
364
+ post[:browserInfo] = { userAgent: options[:user_agent], acceptHeader: options[:accept_header] }
365
+ post[:additionalData] = { executeThreeD: 'true' } if options[:execute_threed]
366
+ end
367
+ end
368
+
369
+ def add_browser_info(browser_info, post)
370
+ return unless browser_info
371
+ post[:browserInfo] = {
372
+ acceptHeader: browser_info[:accept_header],
373
+ colorDepth: browser_info[:depth],
374
+ javaEnabled: browser_info[:java],
375
+ language: browser_info[:language],
376
+ screenHeight: browser_info[:height],
377
+ screenWidth: browser_info[:width],
378
+ timeZoneOffset: browser_info[:timezone],
379
+ userAgent: browser_info[:user_agent]
380
+ }
348
381
  end
349
382
  end
350
383
  end
@@ -93,12 +93,15 @@ module ActiveMerchant #:nodoc:
93
93
 
94
94
  def void(authorization, options = {})
95
95
  reference, amount, type = split_auth(authorization)
96
-
97
- post = {}
98
- add_reference(post, reference)
99
- add_original_amount(post, amount)
100
- add_transaction_type(post, void_action(type))
101
- commit(post)
96
+ if type == TRANSACTIONS[:authorization]
97
+ capture(0, authorization, options)
98
+ else
99
+ post = {}
100
+ add_reference(post, reference)
101
+ add_original_amount(post, amount)
102
+ add_transaction_type(post, void_action(type))
103
+ commit(post)
104
+ end
102
105
  end
103
106
 
104
107
  def verify(source, options={})
@@ -153,6 +156,8 @@ module ActiveMerchant #:nodoc:
153
156
 
154
157
  # To match the other stored-value gateways, like TrustCommerce,
155
158
  # store and unstore need to be defined
159
+ #
160
+ # When passing a single-use token the :name option is required
156
161
  def store(payment_method, options = {})
157
162
  post = {}
158
163
  add_address(post, options)
@@ -315,6 +315,9 @@ module ActiveMerchant #:nodoc:
315
315
  post[:operationType] = options[:operationType] || options[:operation] || secure_profile_action(:new)
316
316
  post[:customerCode] = options[:billing_id] || options[:vault_id] || false
317
317
  post[:status] = options[:status]
318
+
319
+ billing_address = options[:billing_address] || options[:address]
320
+ post[:trnCardOwner] = billing_address ? billing_address[:name] : nil
318
321
  end
319
322
 
320
323
  def add_recurring_amount(post, money)
@@ -8,7 +8,7 @@ module ActiveMerchant
8
8
  self.supported_countries = %w(US CA GB AT BE BG HR CY CZ DK EE FI FR DE GR HU IE IT LV LT LU MT NL PL PT RO SK SI ES SE AR BO BR BZ CL CO CR DO EC GF GP GT HN HT MF MQ MX NI PA PE PR PY SV UY VE)
9
9
 
10
10
  self.default_currency = 'USD'
11
- self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro]
11
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club, :maestro, :naranja, :cabal]
12
12
 
13
13
  self.homepage_url = 'https://home.bluesnap.com/'
14
14
  self.display_name = 'BlueSnap'
@@ -66,6 +66,8 @@ module ActiveMerchant
66
66
  'business_savings' => 'CORPORATE_SAVINGS'
67
67
  }
68
68
 
69
+ STATE_CODE_COUNTRIES = %w(US CA)
70
+
69
71
  def initialize(options={})
70
72
  requires!(options, :api_username, :api_password)
71
73
  super
@@ -93,6 +95,7 @@ module ActiveMerchant
93
95
  commit(:capture, :put) do |doc|
94
96
  add_authorization(doc, authorization)
95
97
  add_order(doc, options)
98
+ add_amount(doc, money, options) if options[:include_capture_amount] == true
96
99
  end
97
100
  end
98
101
 
@@ -220,6 +223,7 @@ module ActiveMerchant
220
223
  doc.send('merchant-transaction-id', truncate(options[:order_id], 50)) if options[:order_id]
221
224
  doc.send('soft-descriptor', options[:soft_descriptor]) if options[:soft_descriptor]
222
225
  add_description(doc, options[:description]) if options[:description]
226
+ add_3ds(doc, options[:three_d_secure]) if options[:three_d_secure]
223
227
  add_level_3_data(doc, options)
224
228
  end
225
229
 
@@ -228,12 +232,28 @@ module ActiveMerchant
228
232
  return unless address
229
233
 
230
234
  doc.country(address[:country]) if address[:country]
231
- doc.state(address[:state]) if address[:state]
235
+ doc.state(address[:state]) if address[:state] && STATE_CODE_COUNTRIES.include?(address[:country])
232
236
  doc.address(address[:address]) if address[:address]
233
237
  doc.city(address[:city]) if address[:city]
234
238
  doc.zip(address[:zip]) if address[:zip]
235
239
  end
236
240
 
241
+ def add_3ds(doc, three_d_secure_options)
242
+ eci = three_d_secure_options[:eci]
243
+ cavv = three_d_secure_options[:cavv]
244
+ xid = three_d_secure_options[:xid]
245
+ ds_transaction_id = three_d_secure_options[:ds_transaction_id]
246
+ version = three_d_secure_options[:version]
247
+
248
+ doc.send('three-d-secure') do
249
+ doc.eci(eci) if eci
250
+ doc.cavv(cavv) if cavv
251
+ doc.xid(xid) if xid
252
+ doc.send('three-d-secure-version', version) if version
253
+ doc.send('ds-transaction-id', ds_transaction_id) if ds_transaction_id
254
+ end
255
+ end
256
+
237
257
  def add_level_3_data(doc, options)
238
258
  return unless options[:customer_reference_number]
239
259
  doc.send('level-3-data') do
@@ -163,10 +163,10 @@ module ActiveMerchant #:nodoc:
163
163
  xml.send('PaymentType', payment_type)
164
164
  xml.send('TxnType', 'WEB_SHOP')
165
165
  xml.send('BillerCode', options.fetch(:biller_code, ''))
166
- xml.send('MerchantReference', '')
167
- xml.send('CRN1', '')
168
- xml.send('CRN2', '')
169
- xml.send('CRN3', '')
166
+ xml.send('MerchantReference', options[:order_id]) if options[:order_id]
167
+ xml.send('CRN1', options[:crn1]) if options[:crn1]
168
+ xml.send('CRN2', options[:crn2]) if options[:crn2]
169
+ xml.send('CRN3', options[:crn3]) if options[:crn3]
170
170
  xml.send('Amount', amount)
171
171
  end
172
172
 
@@ -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))
@@ -565,6 +566,7 @@ module ActiveMerchant #:nodoc:
565
566
  'vault_customer' => vault_customer,
566
567
  'merchant_account_id' => transaction.merchant_account_id,
567
568
  'risk_data' => risk_data,
569
+ 'network_transaction_id' => transaction.network_transaction_id || nil,
568
570
  'processor_response_code' => response_code_from_result(result)
569
571
  }
570
572
  end
@@ -590,6 +592,14 @@ module ActiveMerchant #:nodoc:
590
592
  parameters[:options][:skip_advanced_fraud_checking] = options[:skip_advanced_fraud_checking]
591
593
  end
592
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
+
593
603
  parameters[:custom_fields] = options[:custom_fields]
594
604
  parameters[:device_data] = options[:device_data] if options[:device_data]
595
605
  parameters[:service_fee_amount] = options[:service_fee_amount] if options[:service_fee_amount]
@@ -604,6 +614,7 @@ module ActiveMerchant #:nodoc:
604
614
  end
605
615
 
606
616
  add_payment_method(parameters, credit_card_or_vault_id, options)
617
+ add_stored_credential_data(parameters, credit_card_or_vault_id, options)
607
618
 
608
619
  parameters[:billing] = map_address(options[:billing_address]) if options[:billing_address]
609
620
  parameters[:shipping] = map_address(options[:shipping_address]) if options[:shipping_address]
@@ -619,13 +630,7 @@ module ActiveMerchant #:nodoc:
619
630
  }
620
631
  end
621
632
 
622
- if options[:three_d_secure]
623
- parameters[:three_d_secure_pass_thru] = {
624
- cavv: options[:three_d_secure][:cavv],
625
- eci_flag: options[:three_d_secure][:eci],
626
- xid: options[:three_d_secure][:xid],
627
- }
628
- end
633
+ add_3ds_info(parameters, options[:three_d_secure])
629
634
 
630
635
  parameters[:tax_amount] = options[:tax_amount] if options[:tax_amount]
631
636
  parameters[:tax_exempt] = options[:tax_exempt] if options[:tax_exempt]
@@ -640,6 +645,48 @@ module ActiveMerchant #:nodoc:
640
645
  parameters
641
646
  end
642
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
+
643
690
  def add_payment_method(parameters, credit_card_or_vault_id, options)
644
691
  if credit_card_or_vault_id.is_a?(String) || credit_card_or_vault_id.is_a?(Integer)
645
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
@@ -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,8 +168,8 @@ 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],
@@ -242,7 +242,7 @@ module ActiveMerchant #:nodoc:
242
242
  CECA_NOTIFICATIONS_URL +
243
243
  CECA_NOTIFICATIONS_URL
244
244
  end
245
- Digest::SHA1.hexdigest(signature_fields)
245
+ Digest::SHA2.hexdigest(signature_fields)
246
246
  end
247
247
  end
248
248
  end
@@ -9,14 +9,14 @@ module ActiveMerchant #:nodoc:
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, :maestro, :discover]
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,11 +28,11 @@ 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
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
38
  add_3ds(post, options)
@@ -40,7 +40,7 @@ module ActiveMerchant #:nodoc:
40
40
  commit(:authorize, post)
41
41
  end
42
42
 
43
- def capture(amount, authorization, options={})
43
+ def capture(amount, authorization, options = {})
44
44
  post = {}
45
45
  add_invoice(post, amount, options)
46
46
  add_customer_data(post, options)
@@ -48,12 +48,12 @@ module ActiveMerchant #:nodoc:
48
48
  commit(:capture, post, authorization)
49
49
  end
50
50
 
51
- def void(authorization, options={})
51
+ def void(authorization, _options = {})
52
52
  post = {}
53
53
  commit(:void, post, authorization)
54
54
  end
55
55
 
56
- def refund(amount, authorization, options={})
56
+ def refund(amount, authorization, options = {})
57
57
  post = {}
58
58
  add_invoice(post, amount, options)
59
59
  add_customer_data(post, options)
@@ -61,22 +61,26 @@ module ActiveMerchant #:nodoc:
61
61
  commit(:refund, post, authorization)
62
62
  end
63
63
 
64
- def verify(credit_card, options={})
64
+ def verify(credit_card, options = {})
65
65
  MultiResponse.run(:use_first_response) do |r|
66
66
  r.process { authorize(100, credit_card, options) }
67
67
  r.process(:ignore_result) { void(r.authorization, options) }
68
68
  end
69
69
  end
70
70
 
71
+ def verify_payment(authorization, option={})
72
+ commit(:verify_payment, authorization)
73
+ end
74
+
71
75
  def supports_scrubbing?
72
76
  true
73
77
  end
74
78
 
75
79
  def scrub(transcript)
76
80
  transcript.
77
- gsub(%r((Authorization: )[^\\]*)i, '\1[FILTERED]').
78
- gsub(%r(("number\\":\\")\d+), '\1[FILTERED]').
79
- gsub(%r(("cvv\\":\\")\d+), '\1[FILTERED]')
81
+ gsub(/(Authorization: )[^\\]*/i, '\1[FILTERED]').
82
+ gsub(/("number\\":\\")\d+/, '\1[FILTERED]').
83
+ gsub(/("cvv\\":\\")\d+/, '\1[FILTERED]')
80
84
  end
81
85
 
82
86
  private
@@ -94,7 +98,7 @@ module ActiveMerchant #:nodoc:
94
98
  post[:metadata][:udf5] = application_id || 'ActiveMerchant'
95
99
  end
96
100
 
97
- def add_payment_method(post, payment_method)
101
+ def add_payment_method(post, payment_method, options)
98
102
  post[:source] = {}
99
103
  post[:source][:type] = 'card'
100
104
  post[:source][:name] = payment_method.name
@@ -102,6 +106,7 @@ module ActiveMerchant #:nodoc:
102
106
  post[:source][:cvv] = payment_method.verification_value
103
107
  post[:source][:expiry_year] = format(payment_method.year, :four_digits)
104
108
  post[:source][:expiry_month] = format(payment_method.month, :two_digits)
109
+ post[:source][:stored] = 'true' if options[:card_on_file] == true
105
110
  end
106
111
 
107
112
  def add_customer_data(post, options)
@@ -109,7 +114,7 @@ module ActiveMerchant #:nodoc:
109
114
  post[:customer][:email] = options[:email] || nil
110
115
  post[:payment_ip] = options[:ip] if options[:ip]
111
116
  address = options[:billing_address]
112
- if(address && post[:source])
117
+ if address && post[:source]
113
118
  post[:source][:billing_address] = {}
114
119
  post[:source][:billing_address][:address_line1] = address[:address1] unless address[:address1].blank?
115
120
  post[:source][:billing_address][:address_line2] = address[:address2] unless address[:address2].blank?
@@ -117,36 +122,41 @@ module ActiveMerchant #:nodoc:
117
122
  post[:source][:billing_address][:state] = address[:state] unless address[:state].blank?
118
123
  post[:source][:billing_address][:country] = address[:country] unless address[:country].blank?
119
124
  post[:source][:billing_address][:zip] = address[:zip] unless address[:zip].blank?
120
- post[:source][:phone] = { number: address[:phone] } unless address[:phone].blank?
121
125
  end
122
126
  end
123
127
 
124
- def add_transaction_data(post, options={})
125
- post[:card_on_file] = true if options[:card_on_file] == true
128
+ def add_transaction_data(post, options = {})
126
129
  post[:payment_type] = 'Regular' if options[:transaction_indicator] == 1
127
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)
128
132
  post[:previous_payment_id] = options[:previous_charge_id] if options[:previous_charge_id]
129
133
  end
130
134
 
131
135
  def add_3ds(post, options)
132
- if options[:three_d_secure]
136
+ if options[:three_d_secure] || options[:execute_threed]
133
137
  post[:'3ds'] = {}
134
138
  post[:'3ds'][:enabled] = true
135
- post[:'3ds'][:eci] = options[:eci] if options[:eci]
136
- post[:'3ds'][:cryptogram] = options[:cavv] if options[:cavv]
137
- post[:'3ds'][:xid] = options[:xid] if options[:xid]
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]
138
148
  end
139
149
  end
140
150
 
141
151
  def commit(action, post, authorization = nil)
142
152
  begin
143
- 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))
144
154
  response = parse(raw_response)
145
155
  if action == :capture && response.key?('_links')
146
156
  response['id'] = response['_links']['payment']['href'].split('/')[-1]
147
157
  end
148
158
  rescue ResponseError => e
149
- raise unless(e.response.code.to_s =~ /4\d\d/)
159
+ raise unless e.response.code.to_s =~ /4\d\d/
150
160
  response = parse(e.response.body)
151
161
  end
152
162
 
@@ -175,11 +185,11 @@ module ActiveMerchant #:nodoc:
175
185
  def headers
176
186
  {
177
187
  'Authorization' => @options[:secret_key],
178
- 'Content-Type' => 'application/json;charset=UTF-8'
188
+ 'Content-Type' => 'application/json;charset=UTF-8',
179
189
  }
180
190
  end
181
191
 
182
- def url(post, action, authorization)
192
+ def url(_post, action, authorization)
183
193
  if action == :authorize
184
194
  "#{base_url}/payments"
185
195
  elsif action == :capture
@@ -215,7 +225,7 @@ module ActiveMerchant #:nodoc:
215
225
  end
216
226
 
217
227
  def success_from(response)
218
- response['response_summary'] == 'Approved' || !response.key?('response_summary') && response.key?('action_id')
228
+ response['response_summary'] == 'Approved' || response['approved'] == true || !response.key?('response_summary') && response.key?('action_id')
219
229
  end
220
230
 
221
231
  def message_from(succeeded, response)
@@ -248,7 +258,7 @@ module ActiveMerchant #:nodoc:
248
258
  def error_code_from(succeeded, response)
249
259
  return if succeeded
250
260
  if response['error_type'] && response['error_codes']
251
- "#{response["error_type"]}: #{response["error_codes"].join(", ")}"
261
+ "#{response['error_type']}: #{response['error_codes'].join(', ')}"
252
262
  elsif response['error_type']
253
263
  response['error_type']
254
264
  else