activemerchant 1.94.0 → 1.99.0

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