activemerchant 1.106.0 → 1.108.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 (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