activemerchant 1.106.0 → 1.108.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +79 -0
  3. data/README.md +2 -2
  4. data/lib/active_merchant/billing/gateways/adyen.rb +1 -1
  5. data/lib/active_merchant/billing/gateways/authorize_net.rb +1 -1
  6. data/lib/active_merchant/billing/gateways/blue_pay.rb +2 -2
  7. data/lib/active_merchant/billing/gateways/borgun.rb +15 -4
  8. data/lib/active_merchant/billing/gateways/braintree_blue.rb +11 -9
  9. data/lib/active_merchant/billing/gateways/checkout_v2.rb +20 -9
  10. data/lib/active_merchant/billing/gateways/clearhaus.rb +1 -1
  11. data/lib/active_merchant/billing/gateways/cyber_source.rb +74 -21
  12. data/lib/active_merchant/billing/gateways/d_local.rb +17 -5
  13. data/lib/active_merchant/billing/gateways/decidir.rb +29 -0
  14. data/lib/active_merchant/billing/gateways/ebanx.rb +13 -1
  15. data/lib/active_merchant/billing/gateways/elavon.rb +58 -5
  16. data/lib/active_merchant/billing/gateways/element.rb +13 -5
  17. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +2 -2
  18. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +2 -2
  19. data/lib/active_merchant/billing/gateways/forte.rb +7 -6
  20. data/lib/active_merchant/billing/gateways/global_collect.rb +30 -24
  21. data/lib/active_merchant/billing/gateways/hps.rb +4 -2
  22. data/lib/active_merchant/billing/gateways/iats_payments.rb +31 -14
  23. data/lib/active_merchant/billing/gateways/iridium.rb +4 -2
  24. data/lib/active_merchant/billing/gateways/iveri.rb +4 -1
  25. data/lib/active_merchant/billing/gateways/ixopay.rb +1 -0
  26. data/lib/active_merchant/billing/gateways/kushki.rb +34 -5
  27. data/lib/active_merchant/billing/gateways/litle.rb +6 -1
  28. data/lib/active_merchant/billing/gateways/mercado_pago.rb +1 -0
  29. data/lib/active_merchant/billing/gateways/netaxept.rb +1 -1
  30. data/lib/active_merchant/billing/gateways/netbanx.rb +1 -1
  31. data/lib/active_merchant/billing/gateways/opp.rb +13 -7
  32. data/lib/active_merchant/billing/gateways/optimal_payment.rb +4 -0
  33. data/lib/active_merchant/billing/gateways/orbital.rb +44 -2
  34. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -1
  35. data/lib/active_merchant/billing/gateways/payment_express.rb +2 -2
  36. data/lib/active_merchant/billing/gateways/payu_latam.rb +1 -1
  37. data/lib/active_merchant/billing/gateways/pin.rb +1 -1
  38. data/lib/active_merchant/billing/gateways/quantum.rb +1 -1
  39. data/lib/active_merchant/billing/gateways/realex.rb +10 -3
  40. data/lib/active_merchant/billing/gateways/redsys.rb +1 -1
  41. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +1 -1
  42. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +1 -1
  43. data/lib/active_merchant/billing/gateways/stripe.rb +7 -2
  44. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +40 -6
  45. data/lib/active_merchant/billing/gateways/transact_pro.rb +2 -2
  46. data/lib/active_merchant/billing/gateways/trexle.rb +1 -1
  47. data/lib/active_merchant/billing/gateways/worldpay.rb +8 -6
  48. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  49. data/lib/active_merchant/connection.rb +40 -42
  50. data/lib/active_merchant/network_connection_retries.rb +10 -12
  51. data/lib/active_merchant/version.rb +1 -1
  52. metadata +5 -4
@@ -93,8 +93,10 @@ module ActiveMerchant #:nodoc:
93
93
  post[:country] = lookup_country_code(address[:country])
94
94
  end
95
95
 
96
- def lookup_country_code(country)
97
- Country.find(country).code(:alpha2).value
96
+ def lookup_country_code(country_field)
97
+ Country.find(country_field).code(:alpha2).value
98
+ rescue InvalidCountryCodeError
99
+ nil
98
100
  end
99
101
 
100
102
  def add_payer(post, card, options)
@@ -116,12 +118,22 @@ module ActiveMerchant #:nodoc:
116
118
  address_object = {}
117
119
  address_object[:state] = address[:state] if address[:state]
118
120
  address_object[:city] = address[:city] if address[:city]
119
- address_object[:zip_code] = address[:zip_code] if address[:zip_code]
120
- address_object[:street] = address[:street] if address[:street]
121
- address_object[:number] = address[:number] if address[:number]
121
+ address_object[:zip_code] = address[:zip] if address[:zip]
122
+ address_object[:street] = address[:street] || parse_street(address) if parse_street(address)
123
+ address_object[:number] = address[:number] || parse_house_number(address) if parse_house_number(address)
122
124
  address_object
123
125
  end
124
126
 
127
+ def parse_street(address)
128
+ street = address[:address1].split(/\s+/).keep_if { |x| x !~ /\d/ }.join(' ')
129
+ street.empty? ? nil : street
130
+ end
131
+
132
+ def parse_house_number(address)
133
+ house = address[:address1].split(/\s+/).keep_if { |x| x =~ /\d/ }.join(' ')
134
+ house.empty? ? nil : house
135
+ end
136
+
125
137
  def add_card(post, card, action, options={})
126
138
  post[:card] = {}
127
139
  post[:card][:holder_name] = card.name
@@ -121,6 +121,7 @@ module ActiveMerchant #:nodoc:
121
121
 
122
122
  add_invoice(post, money, options)
123
123
  add_payment(post, credit_card, options)
124
+ add_aggregate_data(post, options) if options[:aggregate_data]
124
125
  end
125
126
 
126
127
  def add_payment_method_id(credit_card, options)
@@ -180,6 +181,29 @@ module ActiveMerchant #:nodoc:
180
181
  post[:card_data] = card_data
181
182
  end
182
183
 
184
+ def add_aggregate_data(post, options)
185
+ aggregate_data = {}
186
+ data = options[:aggregate_data]
187
+ aggregate_data[:indicator] = data[:indicator] if data[:indicator]
188
+ aggregate_data[:identification_number] = data[:identification_number] if data[:identification_number]
189
+ aggregate_data[:bill_to_pay] = data[:bill_to_pay] if data[:bill_to_pay]
190
+ aggregate_data[:bill_to_refund] = data[:bill_to_refund] if data[:bill_to_refund]
191
+ aggregate_data[:merchant_name] = data[:merchant_name] if data[:merchant_name]
192
+ aggregate_data[:street] = data[:street] if data[:street]
193
+ aggregate_data[:number] = data[:number] if data[:number]
194
+ aggregate_data[:postal_code] = data[:postal_code] if data[:postal_code]
195
+ aggregate_data[:category] = data[:category] if data[:category]
196
+ aggregate_data[:channel] = data[:channel] if data[:channel]
197
+ aggregate_data[:geographic_code] = data[:geographic_code] if data[:geographic_code]
198
+ aggregate_data[:city] = data[:city] if data[:city]
199
+ aggregate_data[:merchant_id] = data[:merchant_id] if data[:merchant_id]
200
+ aggregate_data[:province] = data[:province] if data[:province]
201
+ aggregate_data[:country] = data[:country] if data[:country]
202
+ aggregate_data[:merchant_email] = data[:merchant_email] if data[:merchant_email]
203
+ aggregate_data[:merchant_phone] = data[:merchant_phone] if data[:merchant_phone]
204
+ post[:aggregate_data] = aggregate_data
205
+ end
206
+
183
207
  def add_fraud_detection(options = {})
184
208
  {}.tap do |hsh|
185
209
  hsh[:send_to_cs] = options[:send_to_cs] if valid_fraud_detection_option?(options[:send_to_cs]) # true/false
@@ -266,6 +290,11 @@ module ActiveMerchant #:nodoc:
266
290
  error_code ||= error['type']
267
291
  elsif response['error_type']
268
292
  error_code = response['error_type'] if response['validation_errors']
293
+ elsif error = response.dig('error')
294
+ validation_errors = error.dig('validation_errors', 0)
295
+ code = validation_errors['code'] if validation_errors && validation_errors['code']
296
+ param = validation_errors['param'] if validation_errors && validation_errors['param']
297
+ error_code = "#{error['error_type']} | #{code} | #{param}" if error['error_type']
269
298
  end
270
299
 
271
300
  error_code || STANDARD_ERROR_CODE[:processing_error]
@@ -37,6 +37,15 @@ module ActiveMerchant #:nodoc:
37
37
  store: :post
38
38
  }
39
39
 
40
+ VERIFY_AMOUNT_PER_COUNTRY = {
41
+ 'br' => 100,
42
+ 'ar' => 100,
43
+ 'co' => 100,
44
+ 'pe' => 300,
45
+ 'mx' => 300,
46
+ 'cl' => 5000
47
+ }
48
+
40
49
  def initialize(options={})
41
50
  requires!(options, :integration_key)
42
51
  super
@@ -65,6 +74,7 @@ module ActiveMerchant #:nodoc:
65
74
  add_card_or_token(post, payment)
66
75
  add_address(post, options)
67
76
  add_customer_responsible_person(post, payment, options)
77
+ add_additional_data(post, options)
68
78
  post[:payment][:creditcard][:auto_capture] = false
69
79
 
70
80
  commit(:authorize, post)
@@ -109,7 +119,7 @@ module ActiveMerchant #:nodoc:
109
119
 
110
120
  def verify(credit_card, options={})
111
121
  MultiResponse.run(:use_first_response) do |r|
112
- r.process { authorize(100, credit_card, options) }
122
+ r.process { authorize(VERIFY_AMOUNT_PER_COUNTRY[customer_country(options)], credit_card, options) }
113
123
  r.process(:ignore_result) { void(r.authorization, options) }
114
124
  end
115
125
  end
@@ -202,6 +212,8 @@ module ActiveMerchant #:nodoc:
202
212
  def add_additional_data(post, options)
203
213
  post[:device_id] = options[:device_id] if options[:device_id]
204
214
  post[:metadata] = options[:metadata] if options[:metadata]
215
+ post[:metadata] = {} if post[:metadata].nil?
216
+ post[:metadata][:merchant_payment_code] = options[:order_id] if options[:order_id]
205
217
  end
206
218
 
207
219
  def parse(body)
@@ -26,6 +26,7 @@ module ActiveMerchant #:nodoc:
26
26
  void: 'CCDELETE',
27
27
  store: 'CCGETTOKEN',
28
28
  update: 'CCUPDATETOKEN',
29
+ verify: 'CCVERIFY'
29
30
  }
30
31
 
31
32
  def initialize(options = {})
@@ -47,6 +48,8 @@ module ActiveMerchant #:nodoc:
47
48
  add_customer_data(form, options)
48
49
  add_test_mode(form, options)
49
50
  add_ip(form, options)
51
+ add_auth_purchase_params(form, options)
52
+ add_level_3_fields(form, options) if options[:level_3_data]
50
53
  commit(:purchase, money, form, options)
51
54
  end
52
55
 
@@ -60,6 +63,8 @@ module ActiveMerchant #:nodoc:
60
63
  add_customer_data(form, options)
61
64
  add_test_mode(form, options)
62
65
  add_ip(form, options)
66
+ add_auth_purchase_params(form, options)
67
+ add_level_3_fields(form, options) if options[:level_3_data]
63
68
  commit(:authorize, money, form, options)
64
69
  end
65
70
 
@@ -72,6 +77,7 @@ module ActiveMerchant #:nodoc:
72
77
  add_invoice(form, options)
73
78
  add_creditcard(form, options[:credit_card])
74
79
  add_currency(form, money, options)
80
+ add_address(form, options)
75
81
  add_customer_data(form, options)
76
82
  add_test_mode(form, options)
77
83
  else
@@ -111,10 +117,12 @@ module ActiveMerchant #:nodoc:
111
117
  end
112
118
 
113
119
  def verify(credit_card, options = {})
114
- MultiResponse.run(:use_first_response) do |r|
115
- r.process { authorize(100, credit_card, options) }
116
- r.process(:ignore_result) { void(r.authorization, options) }
117
- end
120
+ form = {}
121
+ add_creditcard(form, credit_card)
122
+ add_address(form, options)
123
+ add_test_mode(form, options)
124
+ add_ip(form, options)
125
+ commit(:verify, 0, form, options)
118
126
  end
119
127
 
120
128
  def store(creditcard, options = {})
@@ -249,6 +257,51 @@ module ActiveMerchant #:nodoc:
249
257
  form[:cardholder_ip] = options[:ip] if options.has_key?(:ip)
250
258
  end
251
259
 
260
+ def add_auth_purchase_params(form, options)
261
+ form[:dynamic_dba] = options[:dba] if options.has_key?(:dba)
262
+ form[:merchant_initiated_unscheduled] = options[:merchant_initiated_unscheduled] if options.has_key?(:merchant_initiated_unscheduled)
263
+ end
264
+
265
+ def add_level_3_fields(form, options)
266
+ level_3_data = options[:level_3_data]
267
+ form[:customer_code] = level_3_data[:customer_code] if level_3_data[:customer_code]
268
+ form[:salestax] = level_3_data[:salestax] if level_3_data[:salestax]
269
+ form[:salestax_indicator] = level_3_data[:salestax_indicator] if level_3_data[:salestax_indicator]
270
+ form[:level3_indicator] = level_3_data[:level3_indicator] if level_3_data[:level3_indicator]
271
+ form[:ship_to_zip] = level_3_data[:ship_to_zip] if level_3_data[:ship_to_zip]
272
+ form[:ship_to_country] = level_3_data[:ship_to_country] if level_3_data[:ship_to_country]
273
+ form[:shipping_amount] = level_3_data[:shipping_amount] if level_3_data[:shipping_amount]
274
+ form[:ship_from_postal_code] = level_3_data[:ship_from_postal_code] if level_3_data[:ship_from_postal_code]
275
+ form[:discount_amount] = level_3_data[:discount_amount] if level_3_data[:discount_amount]
276
+ form[:duty_amount] = level_3_data[:duty_amount] if level_3_data[:duty_amount]
277
+ form[:national_tax_indicator] = level_3_data[:national_tax_indicator] if level_3_data[:national_tax_indicator]
278
+ form[:national_tax_amount] = level_3_data[:national_tax_amount] if level_3_data[:national_tax_amount]
279
+ form[:order_date] = level_3_data[:order_date] if level_3_data[:order_date]
280
+ form[:other_tax] = level_3_data[:other_tax] if level_3_data[:other_tax]
281
+ form[:summary_commodity_code] = level_3_data[:summary_commodity_code] if level_3_data[:summary_commodity_code]
282
+ form[:merchant_vat_number] = level_3_data[:merchant_vat_number] if level_3_data[:merchant_vat_number]
283
+ form[:customer_vat_number] = level_3_data[:customer_vat_number] if level_3_data[:customer_vat_number]
284
+ form[:freight_tax_amount] = level_3_data[:freight_tax_amount] if level_3_data[:freight_tax_amount]
285
+ form[:vat_invoice_number] = level_3_data[:vat_invoice_number] if level_3_data[:vat_invoice_number]
286
+ form[:tracking_number] = level_3_data[:tracking_number] if level_3_data[:tracking_number]
287
+ form[:shipping_company] = level_3_data[:shipping_company] if level_3_data[:shipping_company]
288
+ form[:other_fees] = level_3_data[:other_fees] if level_3_data[:other_fees]
289
+ add_line_items(form, level_3_data) if level_3_data[:line_items]
290
+ end
291
+
292
+ def add_line_items(form, level_3_data)
293
+ items = []
294
+ level_3_data[:line_items].each do |line_item|
295
+ item = {}
296
+ line_item.each do |key, value|
297
+ prefixed_key = "ssl_line_Item_#{key}"
298
+ item[prefixed_key.to_sym] = value
299
+ end
300
+ items << item
301
+ end
302
+ form[:LineItemProducts] = { product: items }
303
+ end
304
+
252
305
  def message_from(response)
253
306
  success?(response) ? response['result_message'] : response['errorMessage']
254
307
  end
@@ -278,7 +331,7 @@ module ActiveMerchant #:nodoc:
278
331
  end
279
332
 
280
333
  def post_data_string(key, value, options)
281
- if custom_field?(key, options)
334
+ if custom_field?(key, options) || key == :LineItemProducts
282
335
  "#{key}=#{CGI.escape(value.to_s)}"
283
336
  else
284
337
  "ssl_#{key}=#{CGI.escape(value.to_s)}"
@@ -111,10 +111,18 @@ module ActiveMerchant #:nodoc:
111
111
  end
112
112
 
113
113
  def verify(credit_card, options={})
114
- MultiResponse.run(:use_first_response) do |r|
115
- r.process { authorize(100, credit_card, options) }
116
- r.process(:ignore_result) { void(r.authorization, options) }
114
+ request = build_soap_request do |xml|
115
+ xml.CreditCardAVSOnly(xmlns: 'https://transaction.elementexpress.com') do
116
+ add_credentials(xml)
117
+ add_payment_method(xml, credit_card)
118
+ add_transaction(xml, 0, options)
119
+ add_terminal(xml, options)
120
+ add_address(xml, options)
121
+ end
117
122
  end
123
+
124
+ # send request with the transaction amount set to 0
125
+ commit('CreditCardAVSOnly', request, 0)
118
126
  end
119
127
 
120
128
  def supports_scrubbing?
@@ -185,8 +193,8 @@ module ActiveMerchant #:nodoc:
185
193
 
186
194
  def add_terminal(xml, options)
187
195
  xml.terminal do
188
- xml.TerminalID '01'
189
- xml.CardPresentCode 'UseDefault'
196
+ xml.TerminalID options[:terminal_id] || '01'
197
+ xml.CardPresentCode options[:card_present_code] || 'UseDefault'
190
198
  xml.CardholderPresentCode 'UseDefault'
191
199
  xml.CardInputCode 'UseDefault'
192
200
  xml.CVVPresenceCode 'UseDefault'
@@ -255,14 +255,14 @@ module ActiveMerchant #:nodoc:
255
255
  (credit_card.respond_to?(:eci) ? credit_card.eci : nil) || options[:eci] || DEFAULT_ECI
256
256
  end
257
257
 
258
- xml.tag! 'Ecommerce_Flag', eci.to_s =~ /^[0-9]+$/ ? eci.to_s.rjust(2, '0') : eci
258
+ xml.tag! 'Ecommerce_Flag', /^[0-9]+$/.match?(eci.to_s) ? eci.to_s.rjust(2, '0') : eci
259
259
  end
260
260
 
261
261
  def add_credit_card_verification_strings(xml, credit_card, options)
262
262
  address = options[:billing_address] || options[:address]
263
263
  if address
264
264
  address_values = []
265
- [:address1, :zip, :city, :state, :country].each { |part| address_values << address[part].to_s }
265
+ [:address1, :zip, :city, :state, :country].each { |part| address_values << address[part].to_s.tr("\r\n", ' ').strip }
266
266
  xml.tag! 'VerificationStr1', address_values.join('|')
267
267
  end
268
268
 
@@ -229,7 +229,7 @@ module ActiveMerchant #:nodoc:
229
229
  (credit_card.respond_to?(:eci) ? credit_card.eci : nil) || options[:eci] || DEFAULT_ECI
230
230
  end
231
231
 
232
- xml.tag! 'Ecommerce_Flag', eci.to_s =~ /^[0-9]+$/ ? eci.to_s.rjust(2, '0') : eci
232
+ xml.tag! 'Ecommerce_Flag', /^[0-9]+$/.match?(eci.to_s) ? eci.to_s.rjust(2, '0') : eci
233
233
  end
234
234
 
235
235
  def add_credit_card_verification_strings(xml, credit_card, options)
@@ -319,7 +319,7 @@ module ActiveMerchant #:nodoc:
319
319
  xml.tag! 'StoredCredentials' do
320
320
  xml.tag! 'Indicator', stored_credential_indicator(xml, card, options)
321
321
  if initiator = options.dig(:stored_credential, :initiator)
322
- xml.tag! initiator == 'merchant' ? 'M' : 'C'
322
+ xml.tag! 'Initiation', initiator == 'merchant' ? 'M' : 'C'
323
323
  end
324
324
  if reason_type = options.dig(:stored_credential, :reason_type)
325
325
  xml.tag! 'Schedule', reason_type == 'unscheduled' ? 'U' : 'S'
@@ -24,7 +24,7 @@ module ActiveMerchant #:nodoc:
24
24
  post = {}
25
25
  add_amount(post, money, options)
26
26
  add_invoice(post, options)
27
- add_payment_method(post, payment_method)
27
+ add_payment_method(post, payment_method, options)
28
28
  add_billing_address(post, payment_method, options)
29
29
  add_shipping_address(post, options)
30
30
  post[:action] = 'sale'
@@ -36,7 +36,7 @@ module ActiveMerchant #:nodoc:
36
36
  post = {}
37
37
  add_amount(post, money, options)
38
38
  add_invoice(post, options)
39
- add_payment_method(post, payment_method)
39
+ add_payment_method(post, payment_method, options)
40
40
  add_billing_address(post, payment_method, options)
41
41
  add_shipping_address(post, options)
42
42
  post[:action] = 'authorize'
@@ -57,7 +57,7 @@ module ActiveMerchant #:nodoc:
57
57
  post = {}
58
58
  add_amount(post, money, options)
59
59
  add_invoice(post, options)
60
- add_payment_method(post, payment_method)
60
+ add_payment_method(post, payment_method, options)
61
61
  add_billing_address(post, payment_method, options)
62
62
  post[:action] = 'disburse'
63
63
 
@@ -151,21 +151,22 @@ module ActiveMerchant #:nodoc:
151
151
  post[:shipping_address][:physical_address][:locality] = address[:city] if address[:city]
152
152
  end
153
153
 
154
- def add_payment_method(post, payment_method)
154
+ def add_payment_method(post, payment_method, options)
155
155
  if payment_method.respond_to?(:brand)
156
156
  add_credit_card(post, payment_method)
157
157
  else
158
- add_echeck(post, payment_method)
158
+ add_echeck(post, payment_method, options)
159
159
  end
160
160
  end
161
161
 
162
- def add_echeck(post, payment)
162
+ def add_echeck(post, payment, options)
163
163
  post[:echeck] = {}
164
164
  post[:echeck][:account_holder] = payment.name
165
165
  post[:echeck][:account_number] = payment.account_number
166
166
  post[:echeck][:routing_number] = payment.routing_number
167
167
  post[:echeck][:account_type] = payment.account_type
168
168
  post[:echeck][:check_number] = payment.number
169
+ post[:echeck][:sec_code] = options[:sec_code] || 'PPD'
169
170
  end
170
171
 
171
172
  def add_credit_card(post, payment)
@@ -7,10 +7,10 @@ module ActiveMerchant #:nodoc:
7
7
  self.test_url = 'https://eu.sandbox.api-ingenico.com'
8
8
  self.live_url = 'https://api.globalcollect.com'
9
9
 
10
- self.supported_countries = ['AD', 'AE', 'AG', 'AI', 'AL', 'AM', 'AO', 'AR', 'AS', 'AT', 'AU', 'AW', 'AX', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BQ', 'BR', 'BS', 'BT', 'BW', 'BY', 'BZ', 'CA', 'CC', 'CD', 'CF', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR', 'GA', 'GB', 'GD', 'GE', 'GF', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', 'GS', 'GT', 'GU', 'GW', 'GY', 'HK', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IM', 'IN', 'IS', 'IT', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KR', 'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT', 'LU', 'LV', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', 'NC', 'NE', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG', 'PH', 'PL', 'PN', 'PS', 'PT', 'PW', 'QA', 'RE', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB', 'SC', 'SE', 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SR', 'ST', 'SV', 'SZ', 'TC', 'TD', 'TG', 'TH', 'TJ', 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA', 'UG', 'US', 'UY', 'UZ', 'VC', 'VE', 'VG', 'VI', 'VN', 'WF', 'WS', 'ZA', 'ZM', 'ZW']
10
+ self.supported_countries = %w[AD AE AG AI AL AM AO AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BL BM BN BO BQ BR BS BT BW BY BZ CA CC CD CF CH CI CK CL CM CN CO CR CU CV CW CX CY CZ DE DJ DK DM DO DZ EC EE EG ER ES ET FI FJ FK FM FO FR GA GB GD GE GF GH GI GL GM GN GP GQ GR GS GT GU GW GY HK HN HR HT HU ID IE IL IM IN IS IT JM JO JP KE KG KH KI KM KN KR KW KY KZ LA LB LC LI LK LR LS LT LU LV MA MC MD ME MF MG MH MK MM MN MO MP MQ MR MS MT MU MV MW MX MY MZ NA NC NE NG NI NL NO NP NR NU NZ OM PA PE PF PG PH PL PN PS PT PW QA RE RO RS RU RW SA SB SC SE SG SH SI SJ SK SL SM SN SR ST SV SZ TC TD TG TH TJ TL TM TN TO TR TT TV TW TZ UA UG US UY UZ VC VE VG VI VN WF WS ZA ZM ZW]
11
11
  self.default_currency = 'USD'
12
12
  self.money_format = :cents
13
- self.supported_cardtypes = [:visa, :master, :american_express, :discover, :naranja, :cabal]
13
+ self.supported_cardtypes = %i[visa master american_express discover naranja cabal]
14
14
 
15
15
  def initialize(options={})
16
16
  requires!(options, :merchant_id, :api_key_id, :secret_api_key)
@@ -20,7 +20,7 @@ module ActiveMerchant #:nodoc:
20
20
  def purchase(money, payment, options={})
21
21
  MultiResponse.run do |r|
22
22
  r.process { authorize(money, payment, options) }
23
- r.process { capture(money, r.authorization, options) } unless capture_requested?(r)
23
+ r.process { capture(money, r.authorization, options) } if should_request_capture?(r, options[:requires_approval])
24
24
  end
25
25
  end
26
26
 
@@ -32,7 +32,6 @@ module ActiveMerchant #:nodoc:
32
32
  add_address(post, payment, options)
33
33
  add_creator_info(post, options)
34
34
  add_fraud_fields(post, options)
35
-
36
35
  commit(:authorize, post)
37
36
  end
38
37
 
@@ -161,6 +160,8 @@ module ActiveMerchant #:nodoc:
161
160
  'skipFraudService' => 'true',
162
161
  'authorizationMode' => pre_authorization
163
162
  }
163
+ post['cardPaymentMethodSpecificInput']['requiresApproval'] = options[:requires_approval] unless options[:requires_approval].nil?
164
+
164
165
  post['cardPaymentMethodSpecificInput']['card'] = {
165
166
  'cvv' => payment.verification_value,
166
167
  'cardNumber' => payment.number,
@@ -283,7 +284,7 @@ module ActiveMerchant #:nodoc:
283
284
 
284
285
  def headers(action, post, authorization = nil)
285
286
  {
286
- 'Content-Type' => content_type,
287
+ 'Content-Type' => content_type,
287
288
  'Authorization' => auth_digest(action, post, authorization),
288
289
  'Date' => date
289
290
  }
@@ -314,18 +315,16 @@ POST
314
315
  end
315
316
 
316
317
  def message_from(succeeded, response)
317
- if succeeded
318
- 'Succeeded'
318
+ return 'Succeeded' if succeeded
319
+
320
+ if errors = response['errors']
321
+ errors.first.try(:[], 'message')
322
+ elsif response['error_message']
323
+ response['error_message']
324
+ elsif response['status']
325
+ 'Status: ' + response['status']
319
326
  else
320
- if errors = response['errors']
321
- errors.first.try(:[], 'message')
322
- elsif response['error_message']
323
- response['error_message']
324
- elsif response['status']
325
- 'Status: ' + response['status']
326
- else
327
- 'No message available'
328
- end
327
+ 'No message available'
329
328
  end
330
329
  end
331
330
 
@@ -340,14 +339,14 @@ POST
340
339
  end
341
340
 
342
341
  def error_code_from(succeeded, response)
343
- unless succeeded
344
- if errors = response['errors']
345
- errors.first.try(:[], 'code')
346
- elsif status = response.try(:[], 'statusOutput').try(:[], 'statusCode')
347
- status.to_s
348
- else
349
- 'No error code available'
350
- end
342
+ return if succeeded
343
+
344
+ if errors = response['errors']
345
+ errors.first.try(:[], 'code')
346
+ elsif status = response.try(:[], 'statusOutput').try(:[], 'statusCode')
347
+ status.to_s
348
+ else
349
+ 'No error code available'
351
350
  end
352
351
  end
353
352
 
@@ -355,6 +354,13 @@ POST
355
354
  Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
356
355
  end
357
356
 
357
+ # Capture hasn't already been requested,
358
+ # and
359
+ # `requires_approval` is not false
360
+ def should_request_capture?(response, requires_approval)
361
+ !capture_requested?(response) && requires_approval != false
362
+ end
363
+
358
364
  def capture_requested?(response)
359
365
  response.params.try(:[], 'payment').try(:[], 'status') == 'CAPTURE_REQUESTED'
360
366
  end