activemerchant 1.126.0 → 1.129.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +241 -0
  3. data/lib/active_merchant/billing/check.rb +40 -8
  4. data/lib/active_merchant/billing/credit_card.rb +28 -1
  5. data/lib/active_merchant/billing/credit_card_methods.rb +79 -23
  6. data/lib/active_merchant/billing/gateways/adyen.rb +67 -8
  7. data/lib/active_merchant/billing/gateways/airwallex.rb +40 -11
  8. data/lib/active_merchant/billing/gateways/alelo.rb +256 -0
  9. data/lib/active_merchant/billing/gateways/authorize_net.rb +21 -4
  10. data/lib/active_merchant/billing/gateways/beanstream.rb +18 -0
  11. data/lib/active_merchant/billing/gateways/blue_snap.rb +22 -1
  12. data/lib/active_merchant/billing/gateways/bogus.rb +4 -0
  13. data/lib/active_merchant/billing/gateways/borgun.rb +56 -16
  14. data/lib/active_merchant/billing/gateways/braintree_blue.rb +64 -17
  15. data/lib/active_merchant/billing/gateways/card_connect.rb +27 -9
  16. data/lib/active_merchant/billing/gateways/card_stream.rb +23 -0
  17. data/lib/active_merchant/billing/gateways/checkout_v2.rb +228 -57
  18. data/lib/active_merchant/billing/gateways/commerce_hub.rb +361 -0
  19. data/lib/active_merchant/billing/gateways/credorax.rb +47 -27
  20. data/lib/active_merchant/billing/gateways/cyber_source/cyber_source_common.rb +36 -0
  21. data/lib/active_merchant/billing/gateways/cyber_source.rb +100 -26
  22. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +456 -0
  23. data/lib/active_merchant/billing/gateways/d_local.rb +44 -5
  24. data/lib/active_merchant/billing/gateways/decidir.rb +15 -4
  25. data/lib/active_merchant/billing/gateways/ebanx.rb +36 -24
  26. data/lib/active_merchant/billing/gateways/element.rb +21 -1
  27. data/lib/active_merchant/billing/gateways/global_collect.rb +73 -22
  28. data/lib/active_merchant/billing/gateways/ipg.rb +13 -8
  29. data/lib/active_merchant/billing/gateways/iveri.rb +39 -3
  30. data/lib/active_merchant/billing/gateways/kushki.rb +21 -1
  31. data/lib/active_merchant/billing/gateways/litle.rb +25 -5
  32. data/lib/active_merchant/billing/gateways/mastercard.rb +1 -8
  33. data/lib/active_merchant/billing/gateways/mercado_pago.rb +17 -0
  34. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +44 -10
  35. data/lib/active_merchant/billing/gateways/monei.rb +2 -0
  36. data/lib/active_merchant/billing/gateways/moneris.rb +20 -5
  37. data/lib/active_merchant/billing/gateways/mundipagg.rb +3 -0
  38. data/lib/active_merchant/billing/gateways/ogone.rb +35 -7
  39. data/lib/active_merchant/billing/gateways/openpay.rb +20 -3
  40. data/lib/active_merchant/billing/gateways/orbital.rb +43 -22
  41. data/lib/active_merchant/billing/gateways/pay_trace.rb +64 -18
  42. data/lib/active_merchant/billing/gateways/payeezy.rb +59 -4
  43. data/lib/active_merchant/billing/gateways/paymentez.rb +18 -6
  44. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +4 -0
  45. data/lib/active_merchant/billing/gateways/paysafe.rb +22 -14
  46. data/lib/active_merchant/billing/gateways/payu_latam.rb +3 -0
  47. data/lib/active_merchant/billing/gateways/plexo.rb +308 -0
  48. data/lib/active_merchant/billing/gateways/priority.rb +29 -6
  49. data/lib/active_merchant/billing/gateways/rapyd.rb +110 -49
  50. data/lib/active_merchant/billing/gateways/reach.rb +277 -0
  51. data/lib/active_merchant/billing/gateways/redsys.rb +9 -5
  52. data/lib/active_merchant/billing/gateways/sage_pay.rb +1 -1
  53. data/lib/active_merchant/billing/gateways/securion_pay.rb +40 -0
  54. data/lib/active_merchant/billing/gateways/shift4.rb +342 -0
  55. data/lib/active_merchant/billing/gateways/simetrik.rb +28 -22
  56. data/lib/active_merchant/billing/gateways/stripe.rb +21 -1
  57. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +62 -22
  58. data/lib/active_merchant/billing/gateways/tns.rb +2 -5
  59. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +1 -1
  60. data/lib/active_merchant/billing/gateways/trust_commerce.rb +14 -3
  61. data/lib/active_merchant/billing/gateways/vanco.rb +12 -3
  62. data/lib/active_merchant/billing/gateways/visanet_peru.rb +1 -1
  63. data/lib/active_merchant/billing/gateways/vpos.rb +7 -4
  64. data/lib/active_merchant/billing/gateways/wompi.rb +8 -4
  65. data/lib/active_merchant/billing/gateways/worldpay.rb +117 -9
  66. data/lib/active_merchant/billing/response.rb +15 -1
  67. data/lib/active_merchant/connection.rb +0 -2
  68. data/lib/active_merchant/country.rb +1 -0
  69. data/lib/active_merchant/errors.rb +4 -1
  70. data/lib/active_merchant/version.rb +1 -1
  71. metadata +24 -3
@@ -5,9 +5,10 @@ module ActiveMerchant #:nodoc:
5
5
  class LitleGateway < Gateway
6
6
  SCHEMA_VERSION = '9.14'
7
7
 
8
- class_attribute :postlive_url
8
+ class_attribute :postlive_url, :prelive_url
9
9
 
10
10
  self.test_url = 'https://www.testvantivcnp.com/sandbox/communicator/online'
11
+ self.prelive_url = 'https://payments.vantivprelive.com/vap/communicator/online'
11
12
  self.postlive_url = 'https://payments.vantivpostlive.com/vap/communicator/online'
12
13
  self.live_url = 'https://payments.vantivcnp.com/vap/communicator/online'
13
14
 
@@ -15,7 +16,7 @@ module ActiveMerchant #:nodoc:
15
16
  self.default_currency = 'USD'
16
17
  self.supported_cardtypes = %i[visa master american_express discover diners_club jcb]
17
18
 
18
- self.homepage_url = 'http://www.vantiv.com/'
19
+ self.homepage_url = 'https://www.fisglobal.com/'
19
20
  self.display_name = 'Vantiv eCommerce'
20
21
 
21
22
  def initialize(options = {})
@@ -320,6 +321,7 @@ module ActiveMerchant #:nodoc:
320
321
  add_merchant_data(doc, options)
321
322
  add_debt_repayment(doc, options)
322
323
  add_stored_credential_params(doc, options)
324
+ add_fraud_filter_override(doc, options)
323
325
  end
324
326
 
325
327
  def add_credit_params(doc, money, payment_method, options)
@@ -365,6 +367,10 @@ module ActiveMerchant #:nodoc:
365
367
  doc.debtRepayment(true) if options[:debt_repayment] == true
366
368
  end
367
369
 
370
+ def add_fraud_filter_override(doc, options)
371
+ doc.fraudFilterOverride(options[:fraud_filter_override]) if options[:fraud_filter_override]
372
+ end
373
+
368
374
  def add_payment_method(doc, payment_method, options)
369
375
  if payment_method.is_a?(String)
370
376
  doc.token do
@@ -532,8 +538,10 @@ module ActiveMerchant #:nodoc:
532
538
 
533
539
  def parse(kind, xml)
534
540
  parsed = {}
535
-
536
541
  doc = Nokogiri::XML(xml).remove_namespaces!
542
+
543
+ parsed['duplicate'] = doc.at_xpath('//saleResponse').try(:[], 'duplicate') == 'true' if kind == :sale
544
+
537
545
  doc.xpath("//litleOnlineResponse/#{kind}Response/*").each do |node|
538
546
  if node.elements.empty?
539
547
  parsed[node.name.to_sym] = node.text
@@ -564,15 +572,26 @@ module ActiveMerchant #:nodoc:
564
572
  cvv_result: parsed[:fraudResult_cardValidationResult]
565
573
  }
566
574
 
567
- Response.new(success_from(kind, parsed), parsed[:message], parsed, options)
575
+ Response.new(success_from(kind, parsed), message_from(parsed), parsed, options)
568
576
  end
569
577
 
570
578
  def success_from(kind, parsed)
571
- return (parsed[:response] == '000') unless kind == :registerToken
579
+ return %w(000 001 010).any?(parsed[:response]) unless kind == :registerToken
572
580
 
573
581
  %w(000 801 802).include?(parsed[:response])
574
582
  end
575
583
 
584
+ def message_from(parsed)
585
+ case parsed[:response]
586
+ when '010'
587
+ return "#{parsed[:message]}: The authorized amount is less than the requested amount."
588
+ when '001'
589
+ return "#{parsed[:message]}: This is sent to acknowledge that the submitted transaction has been received."
590
+ else
591
+ parsed[:message]
592
+ end
593
+ end
594
+
576
595
  def authorization_from(kind, parsed, money)
577
596
  kind == :registerToken ? parsed[:litleToken] : "#{parsed[:litleTxnId]};#{kind};#{money}"
578
597
  end
@@ -609,6 +628,7 @@ module ActiveMerchant #:nodoc:
609
628
 
610
629
  def url
611
630
  return postlive_url if @options[:url_override].to_s == 'postlive'
631
+ return prelive_url if @options[:url_override].to_s == 'prelive'
612
632
 
613
633
  test? ? test_url : live_url
614
634
  end
@@ -218,14 +218,7 @@ module ActiveMerchant
218
218
 
219
219
  def base_url
220
220
  if test?
221
- case @options[:region]
222
- when 'asia_pacific'
223
- test_ap_url
224
- when 'europe'
225
- test_eu_url
226
- when 'north_america', nil
227
- test_na_url
228
- end
221
+ test_url
229
222
  else
230
223
  case @options[:region]
231
224
  when 'asia_pacific'
@@ -61,6 +61,10 @@ module ActiveMerchant #:nodoc:
61
61
  end
62
62
  end
63
63
 
64
+ def inquire(authorization, options = {})
65
+ commit('inquire', inquire_path(authorization, options), {})
66
+ end
67
+
64
68
  def supports_scrubbing?
65
69
  true
66
70
  end
@@ -261,6 +265,10 @@ module ActiveMerchant #:nodoc:
261
265
  def commit(action, path, parameters)
262
266
  if %w[capture void].include?(action)
263
267
  response = parse(ssl_request(:put, url(path), post_data(parameters), headers))
268
+ elsif action == 'inquire'
269
+ response = parse(ssl_get(url(path), headers))
270
+
271
+ response = response[0]['results'][0] if response.is_a?(Array)
264
272
  else
265
273
  response = parse(ssl_post(url(path), post_data(parameters), headers(parameters)))
266
274
  end
@@ -295,6 +303,15 @@ module ActiveMerchant #:nodoc:
295
303
  parameters.clone.tap { |p| p.delete(:device_id) }.to_json
296
304
  end
297
305
 
306
+ def inquire_path(authorization, options)
307
+ if authorization
308
+ authorization, = authorization.split('|')
309
+ "payments/#{authorization}"
310
+ else
311
+ "payments/search?external_reference=#{options[:order_id] || options[:external_reference]}"
312
+ end
313
+ end
314
+
298
315
  def error_code_from(action, response)
299
316
  unless success_from(action, response)
300
317
  if cause = response['cause']
@@ -18,6 +18,8 @@ module ActiveMerchant #:nodoc:
18
18
  # The name of the gateway
19
19
  self.display_name = 'Merchant e-Solutions'
20
20
 
21
+ SUCCESS_RESPONSE_CODES = %w(000 085)
22
+
21
23
  def initialize(options = {})
22
24
  requires!(options, :login, :password)
23
25
  super
@@ -25,23 +27,21 @@ module ActiveMerchant #:nodoc:
25
27
 
26
28
  def authorize(money, creditcard_or_card_id, options = {})
27
29
  post = {}
28
- post[:client_reference_number] = options[:customer] if options.has_key?(:customer)
29
- post[:moto_ecommerce_ind] = options[:moto_ecommerce_ind] if options.has_key?(:moto_ecommerce_ind)
30
30
  add_invoice(post, options)
31
31
  add_payment_source(post, creditcard_or_card_id, options)
32
32
  add_address(post, options)
33
33
  add_3dsecure_params(post, options)
34
+ add_stored_credentials(post, options)
34
35
  commit('P', money, post)
35
36
  end
36
37
 
37
38
  def purchase(money, creditcard_or_card_id, options = {})
38
39
  post = {}
39
- post[:client_reference_number] = options[:customer] if options.has_key?(:customer)
40
- post[:moto_ecommerce_ind] = options[:moto_ecommerce_ind] if options.has_key?(:moto_ecommerce_ind)
41
40
  add_invoice(post, options)
42
41
  add_payment_source(post, creditcard_or_card_id, options)
43
42
  add_address(post, options)
44
43
  add_3dsecure_params(post, options)
44
+ add_stored_credentials(post, options)
45
45
  commit('D', money, post)
46
46
  end
47
47
 
@@ -55,10 +55,10 @@ module ActiveMerchant #:nodoc:
55
55
  end
56
56
 
57
57
  def store(creditcard, options = {})
58
- post = {}
59
- post[:client_reference_number] = options[:customer] if options.has_key?(:customer)
60
- add_creditcard(post, creditcard, options)
61
- commit('T', nil, post)
58
+ MultiResponse.run do |r|
59
+ r.process { temporary_store(creditcard, options) }
60
+ r.process { verify(r.authorization, { store_card: 'y' }) }
61
+ end
62
62
  end
63
63
 
64
64
  def unstore(card_id, options = {})
@@ -94,6 +94,13 @@ module ActiveMerchant #:nodoc:
94
94
  commit('V', nil, options.merge(post))
95
95
  end
96
96
 
97
+ def verify(credit_card, options = {})
98
+ post = {}
99
+ post[:store_card] = options[:store_card] if options[:store_card]
100
+ add_payment_source(post, credit_card, options)
101
+ commit('A', 0, post)
102
+ end
103
+
97
104
  def supports_scrubbing?
98
105
  true
99
106
  end
@@ -107,6 +114,13 @@ module ActiveMerchant #:nodoc:
107
114
 
108
115
  private
109
116
 
117
+ def temporary_store(creditcard, options = {})
118
+ post = {}
119
+ post[:client_reference_number] = options[:customer] if options.has_key?(:customer)
120
+ add_creditcard(post, creditcard, options)
121
+ commit('T', nil, post)
122
+ end
123
+
110
124
  def add_address(post, options)
111
125
  if address = options[:billing_address] || options[:address]
112
126
  post[:cardholder_street_address] = address[:address1].to_s.gsub(/[^\w.]/, '+')
@@ -145,6 +159,16 @@ module ActiveMerchant #:nodoc:
145
159
  post[:ucaf_auth_data] = options[:ucaf_auth_data] unless empty?(options[:ucaf_auth_data])
146
160
  end
147
161
 
162
+ def add_stored_credentials(post, options)
163
+ post[:client_reference_number] = options[:client_reference_number] if options[:client_reference_number]
164
+ post[:moto_ecommerce_ind] = options[:moto_ecommerce_ind] if options[:moto_ecommerce_ind]
165
+ post[:recurring_pmt_num] = options[:recurring_pmt_num] if options[:recurring_pmt_num]
166
+ post[:recurring_pmt_count] = options[:recurring_pmt_count] if options[:recurring_pmt_count]
167
+ post[:card_on_file] = options[:card_on_file] if options[:card_on_file]
168
+ post[:cit_mit_indicator] = options[:cit_mit_indicator] if options[:cit_mit_indicator]
169
+ post[:account_data_source] = options[:account_data_source] if options[:account_data_source]
170
+ end
171
+
148
172
  def parse(body)
149
173
  results = {}
150
174
  body.split(/&/).each do |pair|
@@ -165,13 +189,23 @@ module ActiveMerchant #:nodoc:
165
189
  { 'error_code' => '404', 'auth_response_text' => e.to_s }
166
190
  end
167
191
 
168
- Response.new(response['error_code'] == '000', message_from(response), response,
169
- authorization: response['transaction_id'],
192
+ Response.new(success_from(response), message_from(response), response,
193
+ authorization: authorization_from(response),
170
194
  test: test?,
171
195
  cvv_result: response['cvv2_result'],
172
196
  avs_result: { code: response['avs_result'] })
173
197
  end
174
198
 
199
+ def authorization_from(response)
200
+ return response['card_id'] if response['card_id']
201
+
202
+ response['transaction_id']
203
+ end
204
+
205
+ def success_from(response)
206
+ SUCCESS_RESPONSE_CODES.include?(response['error_code'])
207
+ end
208
+
175
209
  def message_from(response)
176
210
  if response['error_code'] == '000'
177
211
  'This transaction has been approved'
@@ -201,6 +201,7 @@ module ActiveMerchant #:nodoc:
201
201
  request[:paymentMethod][:card][:expMonth] = format(payment_method.month, :two_digits)
202
202
  request[:paymentMethod][:card][:expYear] = format(payment_method.year, :two_digits)
203
203
  request[:paymentMethod][:card][:cvc] = payment_method.verification_value.to_s
204
+ request[:paymentMethod][:card][:cardholderName] = payment_method.name
204
205
  end
205
206
  end
206
207
 
@@ -293,6 +294,7 @@ module ActiveMerchant #:nodoc:
293
294
  def add_browser_info(request, options)
294
295
  request[:sessionDetails][:ip] = options[:ip] if options[:ip]
295
296
  request[:sessionDetails][:userAgent] = options[:user_agent] if options[:user_agent]
297
+ request[:sessionDetails][:lang] = options[:lang] if options[:lang]
296
298
  end
297
299
 
298
300
  # Private: Parse JSON response from Monei servers
@@ -9,6 +9,8 @@ module ActiveMerchant #:nodoc:
9
9
  # Response Values", available at Moneris' {eSelect Plus Documentation
10
10
  # Centre}[https://www3.moneris.com/connect/en/documents/index.html].
11
11
  class MonerisGateway < Gateway
12
+ WALLETS = %w(APP GPP)
13
+
12
14
  self.test_url = 'https://esqa.moneris.com/gateway2/servlet/MpgRequest'
13
15
  self.live_url = 'https://www3.moneris.com/gateway2/servlet/MpgRequest'
14
16
 
@@ -47,7 +49,7 @@ module ActiveMerchant #:nodoc:
47
49
  post = {}
48
50
  add_payment_source(post, creditcard_or_datakey, options)
49
51
  post[:amount] = amount(money)
50
- post[:order_id] = options[:order_id]
52
+ post[:order_id] = format_order_id(post[:wallet_indicator], options[:order_id])
51
53
  post[:address] = options[:billing_address] || options[:address]
52
54
  post[:crypt_type] = options[:crypt_type] || @options[:crypt_type]
53
55
  add_external_mpi_fields(post, options)
@@ -71,7 +73,7 @@ module ActiveMerchant #:nodoc:
71
73
  post = {}
72
74
  add_payment_source(post, creditcard_or_datakey, options)
73
75
  post[:amount] = amount(money)
74
- post[:order_id] = options[:order_id]
76
+ post[:order_id] = format_order_id(post[:wallet_indicator], options[:order_id])
75
77
  post[:address] = options[:billing_address] || options[:address]
76
78
  post[:crypt_type] = options[:crypt_type] || @options[:crypt_type]
77
79
  add_external_mpi_fields(post, options)
@@ -431,10 +433,23 @@ module ActiveMerchant #:nodoc:
431
433
  end
432
434
 
433
435
  def wallet_indicator(token_source)
434
- return 'APP' if token_source == 'apple_pay'
435
- return 'ANP' if token_source == 'android_pay'
436
+ return {
437
+ 'apple_pay' => 'APP',
438
+ 'google_pay' => 'GPP',
439
+ 'android_pay' => 'ANP'
440
+ }[token_source]
441
+ end
442
+
443
+ def format_order_id(wallet_indicator_code, order_id = nil)
444
+ # Truncate (max 100 characters) order id for
445
+ # google pay and apple pay (specific wallets / token sources)
446
+ return truncate_order_id(order_id) if WALLETS.include?(wallet_indicator_code)
447
+
448
+ order_id
449
+ end
436
450
 
437
- nil
451
+ def truncate_order_id(order_id = nil)
452
+ order_id.present? ? order_id[0, 100] : SecureRandom.alphanumeric(100)
438
453
  end
439
454
 
440
455
  def message_from(message)
@@ -60,11 +60,13 @@ module ActiveMerchant #:nodoc:
60
60
  post = {}
61
61
  post[:code] = authorization
62
62
  add_invoice(post, money, options)
63
+ add_auth_key(post, options)
63
64
  commit('capture', post, authorization)
64
65
  end
65
66
 
66
67
  def refund(money, authorization, options = {})
67
68
  add_invoice(post = {}, money, options)
69
+ add_auth_key(post, options)
68
70
  commit('refund', post, authorization)
69
71
  end
70
72
 
@@ -77,6 +79,7 @@ module ActiveMerchant #:nodoc:
77
79
  options.update(name: payment.name)
78
80
  options = add_customer(options) unless options[:customer_id]
79
81
  add_payment(post, payment, options)
82
+ add_auth_key(post, options)
80
83
  commit('store', post, options[:customer_id])
81
84
  end
82
85
 
@@ -136,7 +136,7 @@ module ActiveMerchant #:nodoc:
136
136
  self.supported_countries = %w[BE DE FR NL AT CH]
137
137
  # also supports Airplus and UATP
138
138
  self.supported_cardtypes = %i[visa master american_express diners_club discover jcb maestro]
139
- self.homepage_url = 'http://www.ogone.com/'
139
+ self.homepage_url = 'https://www.ingenico.com/login/ogone/'
140
140
  self.display_name = 'Ogone'
141
141
  self.default_currency = 'EUR'
142
142
  self.money_format = :cents
@@ -264,7 +264,6 @@ module ActiveMerchant #:nodoc:
264
264
 
265
265
  def add_payment_source(post, payment_source, options)
266
266
  add_d3d(post, options) if options[:d3d]
267
-
268
267
  if payment_source.is_a?(String)
269
268
  add_alias(post, payment_source, options[:alias_operation])
270
269
  add_eci(post, options[:eci] || '9')
@@ -285,8 +284,6 @@ module ActiveMerchant #:nodoc:
285
284
  THREE_D_SECURE_DISPLAY_WAYS[options[:win_3ds]] :
286
285
  THREE_D_SECURE_DISPLAY_WAYS[:main_window]
287
286
  add_pair post, 'WIN3DS', win_3ds
288
-
289
- add_pair post, 'HTTP_ACCEPT', options[:http_accept] || '*/*'
290
287
  add_pair post, 'HTTP_USER_AGENT', options[:http_user_agent] if options[:http_user_agent]
291
288
  add_pair post, 'ACCEPTURL', options[:accept_url] if options[:accept_url]
292
289
  add_pair post, 'DECLINEURL', options[:decline_url] if options[:decline_url]
@@ -296,6 +293,37 @@ module ActiveMerchant #:nodoc:
296
293
  add_pair post, 'PARAMPLUS', options[:paramplus] if options[:paramplus]
297
294
  add_pair post, 'COMPLUS', options[:complus] if options[:complus]
298
295
  add_pair post, 'LANGUAGE', options[:language] if options[:language]
296
+ if options[:three_ds_2]
297
+ browser_info = options[:three_ds_2][:browser_info]
298
+ ecom_postal = options[:billing_address]
299
+ if browser_info
300
+ add_pair post, 'BROWSERACCEPTHEADER', browser_info[:accept_header]
301
+ add_pair post, 'BROWSERCOLORDEPTH', browser_info[:depth]
302
+
303
+ # for 3ds v2.1 to v2.2 add BROWSERJAVASCRIPTENABLED: This boolean indicates whether your customers have enabled JavaScript in their browsers when making a purchase.
304
+ # the following BROWSER<tag> parameters will remain mandatory unless browser_info[:javascript] = false
305
+ # her documentation https://epayments-support.ingenico.com/en/integration-solutions/integrations/directlink#directlink_integration_guides_secure_payment_with_3_d_secure
306
+ add_pair post, 'BROWSERJAVASCRIPTENABLED', browser_info[:javascript]
307
+ add_pair post, 'BROWSERJAVAENABLED', browser_info[:java]
308
+ add_pair post, 'BROWSERLANGUAGE', browser_info[:language]
309
+ add_pair post, 'BROWSERSCREENHEIGHT', browser_info[:height]
310
+ add_pair post, 'BROWSERSCREENWIDTH', browser_info[:width]
311
+ add_pair post, 'BROWSERTIMEZONE', browser_info[:timezone]
312
+ add_pair post, 'BROWSERUSERAGENT', browser_info[:user_agent]
313
+ end
314
+ # recommended
315
+ if ecom_postal
316
+ add_pair post, 'ECOM_BILLTO_POSTAL_CITY', ecom_postal[:city]
317
+ add_pair post, 'ECOM_BILLTO_POSTAL_COUNTRYCODE', ecom_postal[:country]
318
+ add_pair post, 'ECOM_BILLTO_POSTAL_STREET_LINE1', ecom_postal[:address1]
319
+ add_pair post, 'ECOM_BILLTO_POSTAL_STREET_LINE2', ecom_postal[:address2]
320
+ add_pair post, 'ECOM_BILLTO_POSTAL_POSTALCODE', ecom_postal[:zip]
321
+ end
322
+ # optional
323
+ add_pair post, 'Mpi.threeDSRequestorChallengeIndicator', options[:three_ds_reqchallengeind]
324
+ else
325
+ add_pair post, 'HTTP_ACCEPT', options[:http_accept] || '*/*'
326
+ end
299
327
  end
300
328
 
301
329
  def add_eci(post, eci)
@@ -414,7 +442,7 @@ module ActiveMerchant #:nodoc:
414
442
  return
415
443
  end
416
444
 
417
- add_pair parameters, 'SHASign', calculate_signature(parameters, @options[:signature_encryptor], @options[:signature])
445
+ add_pair parameters, 'SHASIGN', calculate_signature(parameters, @options[:signature_encryptor], @options[:signature])
418
446
  end
419
447
 
420
448
  def calculate_signature(signed_parameters, algorithm, secret)
@@ -432,7 +460,7 @@ module ActiveMerchant #:nodoc:
432
460
  raise "Unknown signature algorithm #{algorithm}"
433
461
  end
434
462
 
435
- filtered_params = signed_parameters.select { |_k, v| !v.blank? }
463
+ filtered_params = signed_parameters.compact
436
464
  sha_encryptor.hexdigest(
437
465
  filtered_params.sort_by { |k, _v| k.upcase }.map { |k, v| "#{k.upcase}=#{v}#{secret}" }.join('')
438
466
  ).upcase
@@ -456,7 +484,7 @@ module ActiveMerchant #:nodoc:
456
484
  end
457
485
 
458
486
  def add_pair(post, key, value)
459
- post[key] = value if !value.blank?
487
+ post[key] = value unless value.nil?
460
488
  end
461
489
 
462
490
  def convert_attributes_to_hash(rexml_attributes)
@@ -1,8 +1,15 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class OpenpayGateway < Gateway
4
- self.live_url = 'https://api.openpay.mx/v1/'
5
- self.test_url = 'https://sandbox-api.openpay.mx/v1/'
4
+ class_attribute :mx_live_url, :mx_test_url
5
+ class_attribute :co_live_url, :co_test_url
6
+
7
+ self.co_live_url = 'https://api.openpay.co/v1/'
8
+ self.co_test_url = 'https://sandbox-api.openpay.co/v1/'
9
+ self.mx_live_url = 'https://api.openpay.mx/v1/'
10
+ self.mx_test_url = 'https://sandbox-api.openpay.mx/v1/'
11
+ self.live_url = self.co_live_url
12
+ self.test_url = self.co_test_url
6
13
 
7
14
  self.supported_countries = %w(CO MX)
8
15
  self.supported_cardtypes = %i[visa master american_express carnet]
@@ -24,6 +31,16 @@ module ActiveMerchant #:nodoc:
24
31
  super
25
32
  end
26
33
 
34
+ def gateway_url(options = {})
35
+ country = options[:merchant_country] || @options[:merchant_country]
36
+
37
+ if country == 'MX'
38
+ test? ? mx_test_url : mx_live_url
39
+ else
40
+ test? ? co_test_url : co_live_url
41
+ end
42
+ end
43
+
27
44
  def purchase(money, creditcard, options = {})
28
45
  post = create_post_for_auth_or_purchase(money, creditcard, options)
29
46
  commit(:post, 'charges', post, options)
@@ -192,7 +209,7 @@ module ActiveMerchant #:nodoc:
192
209
  end
193
210
 
194
211
  def http_request(method, resource, parameters = {}, options = {})
195
- url = (test? ? self.test_url : self.live_url) + @merchant_id + '/' + resource
212
+ url = gateway_url(options) + @merchant_id + '/' + resource
196
213
  raw_response = nil
197
214
  begin
198
215
  raw_response = ssl_request(method, url, (parameters ? parameters.to_json : nil), headers(options))
@@ -30,7 +30,7 @@ module ActiveMerchant #:nodoc:
30
30
  class OrbitalGateway < Gateway
31
31
  include Empty
32
32
 
33
- API_VERSION = '8.1'
33
+ API_VERSION = '9.0'
34
34
 
35
35
  POST_HEADERS = {
36
36
  'MIME-Version' => '1.1',
@@ -98,6 +98,7 @@ module ActiveMerchant #:nodoc:
98
98
  'NZD' => '554',
99
99
  'NOK' => '578',
100
100
  'SGD' => '702',
101
+ 'ZAR' => '710',
101
102
  'SEK' => '752',
102
103
  'CHF' => '756',
103
104
  'GBP' => '826',
@@ -119,6 +120,7 @@ module ActiveMerchant #:nodoc:
119
120
  'NZD' => '2',
120
121
  'NOK' => '2',
121
122
  'SGD' => '2',
123
+ 'ZAR' => '2',
122
124
  'SEK' => '2',
123
125
  'CHF' => '2',
124
126
  'GBP' => '2',
@@ -196,6 +198,7 @@ module ActiveMerchant #:nodoc:
196
198
  requires!(options, :login, :password) unless options[:ip_authentication]
197
199
  super
198
200
  @options[:merchant_id] = @options[:merchant_id].to_s
201
+ @use_secondary_url = false
199
202
  end
200
203
 
201
204
  # A – Authorization request
@@ -235,11 +238,7 @@ module ActiveMerchant #:nodoc:
235
238
  def refund(money, authorization, options = {})
236
239
  payment_method = options[:payment_method]
237
240
  order = build_new_order_xml(REFUND, money, payment_method, options.merge(authorization: authorization)) do |xml|
238
- if payment_method.is_a?(Check)
239
- add_echeck(xml, payment_method, options)
240
- else
241
- add_refund_payment_source(xml, options[:currency])
242
- end
241
+ add_payment_source(xml, payment_method, options)
243
242
  xml.tag! :CustomerRefNum, options[:customer_ref_num] if @options[:customer_profiles] && options[:profile_txn]
244
243
  end
245
244
 
@@ -398,6 +397,12 @@ module ActiveMerchant #:nodoc:
398
397
  add_soft_descriptors_from_hash(xml, descriptors) if descriptors.is_a?(Hash)
399
398
  end
400
399
 
400
+ def add_payment_action_ind(xml, payment_action_ind)
401
+ return unless payment_action_ind
402
+
403
+ xml.tag! :PaymentActionInd, payment_action_ind
404
+ end
405
+
401
406
  def add_soft_descriptors_from_specialized_class(xml, soft_desc)
402
407
  xml.tag! :SDMerchantName, soft_desc.merchant_name if soft_desc.merchant_name
403
408
  xml.tag! :SDProductDescription, soft_desc.product_description if soft_desc.product_description
@@ -564,7 +569,7 @@ module ActiveMerchant #:nodoc:
564
569
  add_currency_fields(xml, options[:currency])
565
570
  xml.tag! :BCRtNum, check.routing_number
566
571
  xml.tag! :CheckDDA, check.account_number if check.account_number
567
- xml.tag! :BankAccountType, ACCOUNT_TYPE[check.account_type] if ACCOUNT_TYPE[check.account_type]
572
+ add_bank_account_type(xml, check)
568
573
  xml.tag! :ECPAuthMethod, options[:auth_method] if options[:auth_method]
569
574
  xml.tag! :BankPmtDelv, options[:payment_delivery] || 'B'
570
575
  xml.tag! :AVSname, (check&.name ? check.name[0..29] : nil) if get_address(options).blank?
@@ -577,12 +582,6 @@ module ActiveMerchant #:nodoc:
577
582
  add_verification_value(xml, credit_card) if credit_card
578
583
  end
579
584
 
580
- def add_refund_payment_source(xml, currency = nil)
581
- xml.tag! :AccountNum, nil
582
-
583
- add_currency_fields(xml, currency)
584
- end
585
-
586
585
  def add_verification_value(xml, credit_card)
587
586
  return unless credit_card&.verification_value?
588
587
 
@@ -595,7 +594,7 @@ module ActiveMerchant #:nodoc:
595
594
  # Null-fill this attribute OR
596
595
  # Do not submit the attribute at all.
597
596
  # - http://download.chasepaymentech.com/docs/orbital/orbital_gateway_xml_specification.pdf
598
- xml.tag! :CardSecValInd, '1' if %w(visa master discover).include?(credit_card.brand)
597
+ xml.tag! :CardSecValInd, '1' if %w(visa discover diners_club).include?(credit_card.brand)
599
598
  xml.tag! :CardSecVal, credit_card.verification_value
600
599
  end
601
600
 
@@ -604,6 +603,17 @@ module ActiveMerchant #:nodoc:
604
603
  xml.tag! :CurrencyExponent, currency_exponents(currency)
605
604
  end
606
605
 
606
+ def add_bank_account_type(xml, check)
607
+ bank_account_type =
608
+ if check.account_holder_type == 'business'
609
+ 'X'
610
+ else
611
+ ACCOUNT_TYPE[check.account_type]
612
+ end
613
+
614
+ xml.tag! :BankAccountType, bank_account_type if bank_account_type
615
+ end
616
+
607
617
  def add_card_indicators(xml, options)
608
618
  xml.tag! :CardIndicators, options[:card_indicators] if options[:card_indicators]
609
619
  end
@@ -752,16 +762,23 @@ module ActiveMerchant #:nodoc:
752
762
  xml.tag!(:AuthenticationECIInd, eci) if eci
753
763
  end
754
764
 
755
- def add_dpanind(xml, credit_card)
765
+ def add_dpanind(xml, credit_card, industry_type = nil)
756
766
  return unless credit_card.is_a?(NetworkTokenizationCreditCard)
757
767
 
758
- xml.tag! :DPANInd, 'Y'
768
+ xml.tag! :DPANInd, 'Y' unless industry_type == 'RC'
759
769
  end
760
770
 
761
- def add_digital_token_cryptogram(xml, credit_card)
762
- return unless credit_card.is_a?(NetworkTokenizationCreditCard)
771
+ def add_digital_token_cryptogram(xml, credit_card, three_d_secure)
772
+ return unless credit_card.is_a?(NetworkTokenizationCreditCard) || three_d_secure && credit_card.brand == 'discover'
763
773
 
764
- xml.tag! :DigitalTokenCryptogram, credit_card.payment_cryptogram
774
+ cryptogram =
775
+ if three_d_secure && credit_card.brand == 'discover'
776
+ three_d_secure[:cavv]
777
+ else
778
+ credit_card.payment_cryptogram
779
+ end
780
+
781
+ xml.tag!(:DigitalTokenCryptogram, cryptogram)
765
782
  end
766
783
 
767
784
  #=====OTHER FIELDS=====
@@ -862,6 +879,8 @@ module ActiveMerchant #:nodoc:
862
879
  # Failover URL will be attempted in the event of a connection error
863
880
  response =
864
881
  begin
882
+ raise ConnectionError.new 'Should use secondary url', 500 if @use_secondary_url
883
+
865
884
  request.call(remote_url)
866
885
  rescue ConnectionError
867
886
  request.call(remote_url(:secondary))
@@ -942,6 +961,7 @@ module ActiveMerchant #:nodoc:
942
961
 
943
962
  def build_new_order_xml(action, money, payment_source, parameters = {})
944
963
  requires!(parameters, :order_id)
964
+ @use_secondary_url = parameters[:use_secondary_url] if parameters[:use_secondary_url]
945
965
  xml = xml_envelope
946
966
  xml.tag! :Request do
947
967
  xml.tag! :NewOrder do
@@ -969,16 +989,17 @@ module ActiveMerchant #:nodoc:
969
989
  # CustomerAni, AVSPhoneType and AVSDestPhoneType could be added here.
970
990
 
971
991
  add_soft_descriptors(xml, parameters[:soft_descriptors])
972
- add_dpanind(xml, payment_source)
992
+ add_payment_action_ind(xml, parameters[:payment_action_ind])
993
+ add_dpanind(xml, payment_source, parameters[:industry_type])
973
994
  add_aevv(xml, payment_source, three_d_secure)
974
- add_digital_token_cryptogram(xml, payment_source)
995
+ add_digital_token_cryptogram(xml, payment_source, three_d_secure)
975
996
 
976
997
  xml.tag! :ECPSameDayInd, parameters[:same_day] if parameters[:same_day] && payment_source.is_a?(Check)
977
998
 
978
999
  set_recurring_ind(xml, parameters)
979
1000
 
980
1001
  # Append Transaction Reference Number at the end for Refund transactions
981
- add_tx_ref_num(xml, parameters[:authorization]) if action == REFUND
1002
+ add_tx_ref_num(xml, parameters[:authorization]) if action == REFUND && payment_source.nil?
982
1003
 
983
1004
  add_level2_purchase(xml, parameters)
984
1005
  add_level3_purchase(xml, parameters)