activemerchant 1.126.0 → 1.129.0

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