activemerchant 1.90.0 → 1.99.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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +202 -0
  3. data/README.md +6 -2
  4. data/lib/active_merchant/billing/avs_result.rb +4 -5
  5. data/lib/active_merchant/billing/credit_card.rb +8 -0
  6. data/lib/active_merchant/billing/credit_card_methods.rb +81 -5
  7. data/lib/active_merchant/billing/gateway.rb +10 -0
  8. data/lib/active_merchant/billing/gateways/adyen.rb +206 -54
  9. data/lib/active_merchant/billing/gateways/bambora_apac.rb +226 -0
  10. data/lib/active_merchant/billing/gateways/barclaycard_smartpay.rb +43 -10
  11. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +3 -0
  12. data/lib/active_merchant/billing/gateways/beanstream.rb +11 -6
  13. data/lib/active_merchant/billing/gateways/blue_pay.rb +10 -8
  14. data/lib/active_merchant/billing/gateways/blue_snap.rb +211 -36
  15. data/lib/active_merchant/billing/gateways/bpoint.rb +4 -4
  16. data/lib/active_merchant/billing/gateways/braintree_blue.rb +79 -18
  17. data/lib/active_merchant/billing/gateways/card_connect.rb +6 -1
  18. data/lib/active_merchant/billing/gateways/cecabank.rb +20 -9
  19. data/lib/active_merchant/billing/gateways/checkout_v2.rb +98 -61
  20. data/lib/active_merchant/billing/gateways/credorax.rb +69 -4
  21. data/lib/active_merchant/billing/gateways/cyber_source.rb +85 -14
  22. data/lib/active_merchant/billing/gateways/d_local.rb +3 -3
  23. data/lib/active_merchant/billing/gateways/decidir.rb +245 -0
  24. data/lib/active_merchant/billing/gateways/elavon.rb +9 -0
  25. data/lib/active_merchant/billing/gateways/epay.rb +13 -2
  26. data/lib/active_merchant/billing/gateways/eway_rapid.rb +42 -12
  27. data/lib/active_merchant/billing/gateways/fat_zebra.rb +26 -7
  28. data/lib/active_merchant/billing/gateways/firstdata_e4_v27.rb +42 -3
  29. data/lib/active_merchant/billing/gateways/global_collect.rb +3 -7
  30. data/lib/active_merchant/billing/gateways/hps.rb +46 -1
  31. data/lib/active_merchant/billing/gateways/ipp.rb +1 -0
  32. data/lib/active_merchant/billing/gateways/kushki.rb +1 -1
  33. data/lib/active_merchant/billing/gateways/litle.rb +61 -3
  34. data/lib/active_merchant/billing/gateways/mastercard.rb +30 -5
  35. data/lib/active_merchant/billing/gateways/mercado_pago.rb +1 -1
  36. data/lib/active_merchant/billing/gateways/migs.rb +8 -0
  37. data/lib/active_merchant/billing/gateways/monei.rb +31 -0
  38. data/lib/active_merchant/billing/gateways/moneris.rb +3 -4
  39. data/lib/active_merchant/billing/gateways/mundipagg.rb +37 -9
  40. data/lib/active_merchant/billing/gateways/nab_transact.rb +1 -1
  41. data/lib/active_merchant/billing/gateways/netbanx.rb +4 -0
  42. data/lib/active_merchant/billing/gateways/nmi.rb +45 -5
  43. data/lib/active_merchant/billing/gateways/openpay.rb +1 -1
  44. data/lib/active_merchant/billing/gateways/opp.rb +20 -1
  45. data/lib/active_merchant/billing/gateways/orbital.rb +92 -11
  46. data/lib/active_merchant/billing/gateways/payflow.rb +64 -14
  47. data/lib/active_merchant/billing/gateways/payment_express.rb +7 -0
  48. data/lib/active_merchant/billing/gateways/paymentez.rb +7 -11
  49. data/lib/active_merchant/billing/gateways/paymill.rb +5 -0
  50. data/lib/active_merchant/billing/gateways/paypal.rb +14 -1
  51. data/lib/active_merchant/billing/gateways/paypal_express.rb +3 -1
  52. data/lib/active_merchant/billing/gateways/payu_latam.rb +6 -2
  53. data/lib/active_merchant/billing/gateways/pin.rb +19 -6
  54. data/lib/active_merchant/billing/gateways/pro_pay.rb +1 -1
  55. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +7 -1
  56. data/lib/active_merchant/billing/gateways/qvalent.rb +54 -1
  57. data/lib/active_merchant/billing/gateways/realex.rb +42 -5
  58. data/lib/active_merchant/billing/gateways/redsys.rb +113 -30
  59. data/lib/active_merchant/billing/gateways/spreedly_core.rb +43 -29
  60. data/lib/active_merchant/billing/gateways/stripe.rb +66 -34
  61. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +271 -0
  62. data/lib/active_merchant/billing/gateways/tns.rb +10 -5
  63. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +5 -5
  64. data/lib/active_merchant/billing/gateways/trust_commerce.rb +46 -6
  65. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +19 -8
  66. data/lib/active_merchant/billing/gateways/visanet_peru.rb +22 -10
  67. data/lib/active_merchant/billing/gateways/worldpay.rb +237 -34
  68. data/lib/active_merchant/country.rb +2 -1
  69. data/lib/active_merchant/version.rb +1 -1
  70. metadata +20 -4
@@ -63,6 +63,7 @@ module ActiveMerchant #:nodoc:
63
63
  add_invoice(post, options)
64
64
  add_creditcard_or_reference(post, credit_card_or_reference)
65
65
  add_instant_capture(post, false)
66
+ add_3ds_auth(post, options)
66
67
 
67
68
  commit(:authorize, post)
68
69
  end
@@ -74,6 +75,7 @@ module ActiveMerchant #:nodoc:
74
75
  add_creditcard_or_reference(post, credit_card_or_reference)
75
76
  add_invoice(post, options)
76
77
  add_instant_capture(post, true)
78
+ add_3ds_auth(post, options)
77
79
 
78
80
  commit(:authorize, post)
79
81
  end
@@ -158,6 +160,16 @@ module ActiveMerchant #:nodoc:
158
160
  post[:instantcapture] = option ? 1 : 0
159
161
  end
160
162
 
163
+ def add_3ds_auth(post, options)
164
+ if options[:three_d_secure]
165
+ post[:eci] = options.dig(:three_d_secure, :eci)
166
+ post[:xid] = options.dig(:three_d_secure, :xid)
167
+ post[:cavv] = options.dig(:three_d_secure, :cavv)
168
+ post[:threeds_version] = options.dig(:three_d_secure, :version)
169
+ post[:ds_transaction_id] = options.dig(:three_d_secure, :ds_transaction_id)
170
+ end
171
+ end
172
+
161
173
  def commit(action, params)
162
174
  response = send("do_#{action}", params)
163
175
 
@@ -193,7 +205,6 @@ module ActiveMerchant #:nodoc:
193
205
  headers['Referer'] = (options[:password] || 'activemerchant.org')
194
206
 
195
207
  response = raw_ssl_request(:post, live_url + 'auth/default.aspx', authorize_post_data(params), headers)
196
-
197
208
  # Authorize gives the response back by redirecting with the values in
198
209
  # the URL query
199
210
  if location = response['Location']
@@ -268,7 +279,7 @@ module ActiveMerchant #:nodoc:
268
279
 
269
280
  def authorize_post_data(params = {})
270
281
  params[:language] = '2'
271
- params[:cms] = 'activemerchant'
282
+ params[:cms] = 'activemerchant_3ds'
272
283
  params[:accepturl] = live_url + 'auth/default.aspx?accept=1'
273
284
  params[:declineurl] = live_url + 'auth/default.aspx?decline=1'
274
285
  params[:merchantnumber] = @options[:login]
@@ -51,7 +51,7 @@ module ActiveMerchant #:nodoc:
51
51
  params = {}
52
52
  add_metadata(params, options)
53
53
  add_invoice(params, amount, options)
54
- add_customer_data(params, options)
54
+ add_customer_data(params, options, payment_method)
55
55
  add_credit_card(params, payment_method, options)
56
56
  params['Method'] = payment_method.respond_to?(:number) ? 'ProcessPayment' : 'TokenPayment'
57
57
  commit(url_for('Transaction'), params)
@@ -61,7 +61,7 @@ module ActiveMerchant #:nodoc:
61
61
  params = {}
62
62
  add_metadata(params, options)
63
63
  add_invoice(params, amount, options)
64
- add_customer_data(params, options)
64
+ add_customer_data(params, options, payment_method)
65
65
  add_credit_card(params, payment_method, options)
66
66
  params['Method'] = 'Authorise'
67
67
  commit(url_for('Authorisation'), params)
@@ -137,7 +137,7 @@ module ActiveMerchant #:nodoc:
137
137
  params = {}
138
138
  add_metadata(params, options)
139
139
  add_invoice(params, 0, options)
140
- add_customer_data(params, options)
140
+ add_customer_data(params, options, payment_method)
141
141
  add_credit_card(params, payment_method, options)
142
142
  params['Method'] = 'CreateTokenCustomer'
143
143
  commit(url_for('Transaction'), params)
@@ -166,7 +166,7 @@ module ActiveMerchant #:nodoc:
166
166
  params = {}
167
167
  add_metadata(params, options)
168
168
  add_invoice(params, 0, options)
169
- add_customer_data(params, options)
169
+ add_customer_data(params, options, payment_method)
170
170
  add_credit_card(params, payment_method, options)
171
171
  add_customer_token(params, customer_token)
172
172
  params['Method'] = 'UpdateTokenCustomer'
@@ -212,17 +212,48 @@ module ActiveMerchant #:nodoc:
212
212
  params['TransactionID'] = reference
213
213
  end
214
214
 
215
- def add_customer_data(params, options)
216
- params['Customer'] ||= {}
217
- add_address(params['Customer'], (options[:billing_address] || options[:address]), {:email => options[:email]})
218
- params['ShippingAddress'] = {}
219
- add_address(params['ShippingAddress'], options[:shipping_address], {:skip_company => true})
215
+ def add_customer_data(params, options, payment_method = nil)
216
+ add_customer_fields(params, options, payment_method)
217
+ add_shipping_fields(params, options)
218
+ end
219
+
220
+ def add_customer_fields(params, options, payment_method)
221
+ key = 'Customer'
222
+ params[key] ||= {}
223
+
224
+ customer_address = options[:billing_address] || options[:address]
225
+
226
+ add_name_and_email(params[key], customer_address, options[:email], payment_method)
227
+ add_address(params[key], customer_address)
228
+ end
229
+
230
+ def add_shipping_fields(params, options)
231
+ key = 'ShippingAddress'
232
+ params[key] = {}
233
+
234
+ add_name_and_email(params[key], options[:shipping_address], options[:email])
235
+ add_address(params[key], options[:shipping_address], {:skip_company => true})
236
+ end
237
+
238
+ def add_name_and_email(params, address, email, payment_method = nil)
239
+ if address.present?
240
+ params['FirstName'], params['LastName'] = split_names(address[:name])
241
+ elsif payment_method_name_available?(payment_method)
242
+ params['FirstName'] = payment_method.first_name
243
+ params['LastName'] = payment_method.last_name
244
+ end
245
+
246
+ params['Email'] = email
247
+ end
248
+
249
+ def payment_method_name_available?(payment_method)
250
+ payment_method.respond_to?(:first_name) && payment_method.respond_to?(:last_name) &&
251
+ payment_method.first_name.present? && payment_method.last_name.present?
220
252
  end
221
253
 
222
254
  def add_address(params, address, options={})
223
255
  return unless address
224
256
 
225
- params['FirstName'], params['LastName'] = split_names(address[:name])
226
257
  params['Title'] = address[:title]
227
258
  params['CompanyName'] = address[:company] unless options[:skip_company]
228
259
  params['Street1'] = truncate(address[:address1], 50)
@@ -231,9 +262,8 @@ module ActiveMerchant #:nodoc:
231
262
  params['State'] = address[:state]
232
263
  params['PostalCode'] = address[:zip]
233
264
  params['Country'] = address[:country].to_s.downcase
234
- params['Phone'] = address[:phone]
265
+ params['Phone'] = address[:phone] || address[:phone_number]
235
266
  params['Fax'] = address[:fax]
236
- params['Email'] = options[:email]
237
267
  end
238
268
 
239
269
  def add_credit_card(params, credit_card, options)
@@ -27,6 +27,7 @@ module ActiveMerchant #:nodoc:
27
27
  add_extra_options(post, options)
28
28
  add_order_id(post, options)
29
29
  add_ip(post, options)
30
+ add_metadata(post, options)
30
31
 
31
32
  commit(:post, 'purchases', post)
32
33
  end
@@ -39,6 +40,7 @@ module ActiveMerchant #:nodoc:
39
40
  add_extra_options(post, options)
40
41
  add_order_id(post, options)
41
42
  add_ip(post, options)
43
+ add_metadata(post, options)
42
44
 
43
45
  post[:capture] = false
44
46
 
@@ -46,14 +48,17 @@ module ActiveMerchant #:nodoc:
46
48
  end
47
49
 
48
50
  def capture(money, authorization, options = {})
51
+ txn_id, _ = authorization.to_s.split('|')
49
52
  post = {}
53
+
50
54
  add_amount(post, money, options)
51
55
  add_extra_options(post, options)
52
56
 
53
- commit(:post, "purchases/#{CGI.escape(authorization)}/capture", post)
57
+ commit(:post, "purchases/#{CGI.escape(txn_id)}/capture", post)
54
58
  end
55
59
 
56
- def refund(money, txn_id, options={})
60
+ def refund(money, authorization, options={})
61
+ txn_id, _ = authorization.to_s.split('|')
57
62
  post = {}
58
63
 
59
64
  add_extra_options(post, options)
@@ -64,8 +69,15 @@ module ActiveMerchant #:nodoc:
64
69
  commit(:post, 'refunds', post)
65
70
  end
66
71
 
72
+ def void(authorization, options={})
73
+ txn_id, endpoint = authorization.to_s.split('|')
74
+
75
+ commit(:post, "#{endpoint}/void?id=#{txn_id}", {})
76
+ end
77
+
67
78
  def store(creditcard, options={})
68
79
  post = {}
80
+
69
81
  add_creditcard(post, creditcard)
70
82
 
71
83
  commit(:post, 'credit_cards', post)
@@ -97,7 +109,8 @@ module ActiveMerchant #:nodoc:
97
109
  post[:cvv] = creditcard.verification_value if creditcard.verification_value?
98
110
  post[:card_holder] = creditcard.name if creditcard.name
99
111
  elsif creditcard.is_a?(String)
100
- post[:card_token] = creditcard
112
+ id, _ = creditcard.to_s.split('|')
113
+ post[:card_token] = id
101
114
  post[:cvv] = options[:cvv]
102
115
  elsif creditcard.is_a?(Hash)
103
116
  ActiveMerchant.deprecated 'Passing the credit card as a Hash is deprecated. Use a String and put the (optional) CVV in the options hash instead.'
@@ -127,6 +140,10 @@ module ActiveMerchant #:nodoc:
127
140
  post[:customer_ip] = options[:ip] || '127.0.0.1'
128
141
  end
129
142
 
143
+ def add_metadata(post, options)
144
+ post[:metadata] = options.fetch(:metadata, {})
145
+ end
146
+
130
147
  def commit(method, uri, parameters=nil)
131
148
  response = begin
132
149
  parse(ssl_request(method, get_url(uri), parameters.to_json, headers))
@@ -141,7 +158,7 @@ module ActiveMerchant #:nodoc:
141
158
  message_from(response),
142
159
  response,
143
160
  :test => response['test'],
144
- :authorization => authorization_from(response, success)
161
+ :authorization => authorization_from(response, success, uri)
145
162
  )
146
163
  end
147
164
 
@@ -149,13 +166,15 @@ module ActiveMerchant #:nodoc:
149
166
  (
150
167
  response['successful'] &&
151
168
  response['response'] &&
152
- (response['response']['successful'] || response['response']['token'])
169
+ (response['response']['successful'] || response['response']['token'] || response['response']['response_code'] == '00')
153
170
  )
154
171
  end
155
172
 
156
- def authorization_from(response, success)
173
+ def authorization_from(response, success, uri)
174
+ endpoint = uri.split('/')[0]
157
175
  if success
158
- (response['response']['id'] || response['response']['token'])
176
+ id = response['response']['id'] || response['response']['token']
177
+ "#{id}|#{endpoint}"
159
178
  else
160
179
  nil
161
180
  end
@@ -1,8 +1,8 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class FirstdataE4V27Gateway < Gateway
4
- self.test_url = 'https://api.demo.globalgatewaye4.firstdata.com/transaction/v27'
5
- self.live_url = 'https://api.globalgatewaye4.firstdata.com/transaction/v27'
4
+ self.test_url = 'https://api.demo.globalgatewaye4.firstdata.com/transaction/v28'
5
+ self.live_url = 'https://api.globalgatewaye4.firstdata.com/transaction/v28'
6
6
 
7
7
  TRANSACTIONS = {
8
8
  sale: '00',
@@ -148,6 +148,7 @@ module ActiveMerchant #:nodoc:
148
148
  add_credit_card_token(xml, credit_card_or_store_authorization, options)
149
149
  else
150
150
  add_credit_card(xml, credit_card_or_store_authorization, options)
151
+ add_stored_credentials(xml, credit_card_or_store_authorization, options)
151
152
  end
152
153
 
153
154
  add_address(xml, options)
@@ -312,6 +313,35 @@ module ActiveMerchant #:nodoc:
312
313
  xml.tag!('Level3') { |x| x << options[:level_3] } if options[:level_3]
313
314
  end
314
315
 
316
+ def add_stored_credentials(xml, card, options)
317
+ return unless options[:stored_credential]
318
+ xml.tag! 'StoredCredentials' do
319
+ xml.tag! 'Indicator', stored_credential_indicator(xml, card, options)
320
+ if initiator = options.dig(:stored_credential, :initiator)
321
+ xml.tag! initiator == 'merchant' ? 'M' : 'C'
322
+ end
323
+ if reason_type = options.dig(:stored_credential, :reason_type)
324
+ xml.tag! 'Schedule', reason_type == 'unscheduled' ? 'U' : 'S'
325
+ end
326
+ xml.tag! 'AuthorizationTypeOverride', options[:authorization_type_override] if options[:authorization_type_override]
327
+ if network_transaction_id = options[:stored_credential][:network_transaction_id]
328
+ xml.tag! 'TransactionId', network_transaction_id
329
+ else
330
+ xml.tag! 'TransactionId', 'new'
331
+ end
332
+ xml.tag! 'OriginalAmount', options[:original_amount] if options[:original_amount]
333
+ xml.tag! 'ProtectbuyIndicator', options[:protectbuy_indicator] if options[:protectbuy_indicator]
334
+ end
335
+ end
336
+
337
+ def stored_credential_indicator(xml, card, options)
338
+ if card.brand == 'master' || options.dig(:stored_credential, :initial_transaction) == false
339
+ 'S'
340
+ else
341
+ '1'
342
+ end
343
+ end
344
+
315
345
  def expdate(credit_card)
316
346
  "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
317
347
  end
@@ -438,9 +468,18 @@ module ActiveMerchant #:nodoc:
438
468
 
439
469
  def parse_elements(response, root)
440
470
  root.elements.to_a.each do |node|
441
- response[node.name.gsub(/EXact/, 'Exact').underscore.to_sym] = (node.text || '').strip
471
+ if node.has_elements?
472
+ parse_elements(response, node)
473
+ else
474
+ response[name_node(root, node)] = (node.text || '').strip
475
+ end
442
476
  end
443
477
  end
478
+
479
+ def name_node(root, node)
480
+ parent = root.name unless root.name == 'TransactionResult'
481
+ "#{parent}#{node.name}".gsub(/EXact/, 'Exact').underscore.to_sym
482
+ end
444
483
  end
445
484
  end
446
485
  end
@@ -10,7 +10,7 @@ module ActiveMerchant #:nodoc:
10
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']
11
11
  self.default_currency = 'USD'
12
12
  self.money_format = :cents
13
- self.supported_cardtypes = [:visa, :master, :american_express, :discover]
13
+ self.supported_cardtypes = [: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)
@@ -142,12 +142,8 @@ module ActiveMerchant #:nodoc:
142
142
 
143
143
  def add_customer_data(post, options, payment = nil)
144
144
  if payment
145
- post['order']['customer']['personalInformation'] = {
146
- 'name' => {
147
- 'firstName' => payment.first_name[0..14],
148
- 'surname' => payment.last_name[0..69]
149
- }
150
- }
145
+ post['order']['customer']['personalInformation']['name']['firstName'] = payment.first_name[0..14] if payment.first_name
146
+ post['order']['customer']['personalInformation']['name']['surname'] = payment.last_name[0..69] if payment.last_name
151
147
  end
152
148
  post['order']['customer']['merchantCustomerId'] = options[:customer] if options[:customer]
153
149
  post['order']['customer']['companyInformation']['name'] = options[:company] if options[:company]
@@ -15,6 +15,14 @@ module ActiveMerchant #:nodoc:
15
15
 
16
16
  self.money_format = :dollars
17
17
 
18
+ PAYMENT_DATA_SOURCE_MAPPING = {
19
+ apple_pay: 'ApplePay',
20
+ master: 'MasterCard 3DSecure',
21
+ visa: 'Visa 3DSecure',
22
+ american_express: 'AMEX 3DSecure',
23
+ discover: 'Discover 3DSecure',
24
+ }
25
+
18
26
  def initialize(options={})
19
27
  requires!(options, :secret_api_key)
20
28
  super
@@ -28,6 +36,7 @@ module ActiveMerchant #:nodoc:
28
36
  add_details(xml, options)
29
37
  add_descriptor_name(xml, options)
30
38
  add_payment(xml, card_or_token, options)
39
+ add_three_d_secure(xml, card_or_token, options)
31
40
  end
32
41
  end
33
42
 
@@ -46,6 +55,7 @@ module ActiveMerchant #:nodoc:
46
55
  add_details(xml, options)
47
56
  add_descriptor_name(xml, options)
48
57
  add_payment(xml, card_or_token, options)
58
+ add_three_d_secure(xml, card_or_token, options)
49
59
  end
50
60
  end
51
61
 
@@ -81,7 +91,8 @@ module ActiveMerchant #:nodoc:
81
91
  transcript.
82
92
  gsub(%r((<hps:CardNbr>)[^<]*(<\/hps:CardNbr>))i, '\1[FILTERED]\2').
83
93
  gsub(%r((<hps:CVV2>)[^<]*(<\/hps:CVV2>))i, '\1[FILTERED]\2').
84
- gsub(%r((<hps:SecretAPIKey>)[^<]*(<\/hps:SecretAPIKey>))i, '\1[FILTERED]\2')
94
+ gsub(%r((<hps:SecretAPIKey>)[^<]*(<\/hps:SecretAPIKey>))i, '\1[FILTERED]\2').
95
+ gsub(%r((<hps:PaymentData>)[^<]*(<\/hps:PaymentData>))i, '\1[FILTERED]\2')
85
96
  end
86
97
 
87
98
  private
@@ -164,6 +175,40 @@ module ActiveMerchant #:nodoc:
164
175
  xml.hps :TxnDescriptor, options[:descriptor_name] if options[:descriptor_name]
165
176
  end
166
177
 
178
+ def add_three_d_secure(xml, card_or_token, options)
179
+ if card_or_token.is_a?(NetworkTokenizationCreditCard)
180
+ build_three_d_secure(xml, {
181
+ source: card_or_token.source,
182
+ cavv: card_or_token.payment_cryptogram,
183
+ eci: card_or_token.eci,
184
+ xid: card_or_token.transaction_id,
185
+ })
186
+ elsif options[:three_d_secure]
187
+ options[:three_d_secure][:source] ||= card_brand(card_or_token)
188
+ build_three_d_secure(xml, options[:three_d_secure])
189
+ end
190
+ end
191
+
192
+ def build_three_d_secure(xml, three_d_secure)
193
+ # PaymentDataSource is required when supplying the SecureECommerce data group,
194
+ # and the gateway currently only allows the values within the mapping
195
+ return unless PAYMENT_DATA_SOURCE_MAPPING[three_d_secure[:source].to_sym]
196
+
197
+ xml.hps :SecureECommerce do
198
+ xml.hps :PaymentDataSource, PAYMENT_DATA_SOURCE_MAPPING[three_d_secure[:source].to_sym]
199
+ xml.hps :TypeOfPaymentData, '3DSecure' # Only type currently supported
200
+ xml.hps :PaymentData, three_d_secure[:cavv] if three_d_secure[:cavv]
201
+ # the gateway only allows a single character for the ECI
202
+ xml.hps :ECommerceIndicator, strip_leading_zero(three_d_secure[:eci]) if three_d_secure[:eci]
203
+ xml.hps :XID, three_d_secure[:xid] if three_d_secure[:xid]
204
+ end
205
+ end
206
+
207
+ def strip_leading_zero(value)
208
+ return value unless value[0] == '0'
209
+ value[1, 1]
210
+ end
211
+
167
212
  def build_request(action)
168
213
  xml = Builder::XmlMarkup.new(encoding: 'UTF-8')
169
214
  xml.instruct!(:xml, encoding: 'UTF-8')
@@ -22,6 +22,7 @@ module ActiveMerchant #:nodoc:
22
22
  }
23
23
 
24
24
  def initialize(options={})
25
+ ActiveMerchant.deprecated('IPP gateway is now named Bambora Asia-Pacific')
25
26
  requires!(options, :username, :password)
26
27
  super
27
28
  end
@@ -7,7 +7,7 @@ module ActiveMerchant #:nodoc:
7
7
  self.test_url = 'https://api-uat.kushkipagos.com/v1/'
8
8
  self.live_url = 'https://api.kushkipagos.com/v1/'
9
9
 
10
- self.supported_countries = ['CO', 'EC']
10
+ self.supported_countries = ['CL', 'CO', 'EC', 'MX', 'PE']
11
11
  self.default_currency = 'USD'
12
12
  self.money_format = :dollars
13
13
  self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club]
@@ -3,7 +3,7 @@ require 'nokogiri'
3
3
  module ActiveMerchant #:nodoc:
4
4
  module Billing #:nodoc:
5
5
  class LitleGateway < Gateway
6
- SCHEMA_VERSION = '9.12'
6
+ SCHEMA_VERSION = '9.14'
7
7
 
8
8
  self.test_url = 'https://www.testvantivcnp.com/sandbox/communicator/online'
9
9
  self.live_url = 'https://payments.vantivcnp.com/vap/communicator/online'
@@ -223,6 +223,7 @@ module ActiveMerchant #:nodoc:
223
223
  add_descriptor(doc, options)
224
224
  add_merchant_data(doc, options)
225
225
  add_debt_repayment(doc, options)
226
+ add_stored_credential_params(doc, options)
226
227
  end
227
228
 
228
229
  def add_merchant_data(doc, options={})
@@ -293,6 +294,38 @@ module ActiveMerchant #:nodoc:
293
294
  end
294
295
  end
295
296
 
297
+ def add_stored_credential_params(doc, options={})
298
+ return unless options[:stored_credential]
299
+
300
+ if options[:stored_credential][:initial_transaction]
301
+ add_stored_credential_params_initial(doc, options)
302
+ else
303
+ add_stored_credential_params_used(doc, options)
304
+ end
305
+ end
306
+
307
+ def add_stored_credential_params_initial(doc, options)
308
+ case options[:stored_credential][:reason_type]
309
+ when 'unscheduled'
310
+ doc.processingType('initialCOF')
311
+ when 'installment'
312
+ doc.processingType('initialInstallment')
313
+ when 'recurring'
314
+ doc.processingType('initialRecurring')
315
+ end
316
+ end
317
+
318
+ def add_stored_credential_params_used(doc, options)
319
+ if options[:stored_credential][:reason_type] == 'unscheduled'
320
+ if options[:stored_credential][:initiator] == 'merchant'
321
+ doc.processingType('merchantInitiatedCOF')
322
+ else
323
+ doc.processingType('cardholderInitiatedCOF')
324
+ end
325
+ end
326
+ doc.originalNetworkTransactionId(options[:stored_credential][:network_transaction_id])
327
+ end
328
+
296
329
  def add_billing_address(doc, payment_method, options)
297
330
  return if payment_method.is_a?(String)
298
331
 
@@ -332,8 +365,9 @@ module ActiveMerchant #:nodoc:
332
365
  end
333
366
 
334
367
  def add_order_source(doc, payment_method, options)
335
- if options[:order_source]
336
- doc.orderSource(options[:order_source])
368
+ order_source = order_source(options)
369
+ if order_source
370
+ doc.orderSource(order_source)
337
371
  elsif payment_method.is_a?(NetworkTokenizationCreditCard) && payment_method.source == :apple_pay
338
372
  doc.orderSource('applepay')
339
373
  elsif payment_method.is_a?(NetworkTokenizationCreditCard) && payment_method.source == :android_pay
@@ -345,6 +379,30 @@ module ActiveMerchant #:nodoc:
345
379
  end
346
380
  end
347
381
 
382
+ def order_source(options={})
383
+ return options[:order_source] unless options[:stored_credential]
384
+ order_source = nil
385
+
386
+ case options[:stored_credential][:reason_type]
387
+ when 'unscheduled'
388
+ if options[:stored_credential][:initiator] == 'merchant'
389
+ # For merchant-initiated, we should always set order source to
390
+ # 'ecommerce'
391
+ order_source = 'ecommerce'
392
+ else
393
+ # For cardholder-initiated, we rely on #add_order_source's
394
+ # default logic to set orderSource appropriately
395
+ order_source = options[:order_source]
396
+ end
397
+ when 'installment'
398
+ order_source = 'installment'
399
+ when 'recurring'
400
+ order_source = 'recurring'
401
+ end
402
+
403
+ order_source
404
+ end
405
+
348
406
  def add_pos(doc, payment_method)
349
407
  return unless payment_method.respond_to?(:track_data) && payment_method.track_data.present?
350
408
 
@@ -7,9 +7,20 @@ module ActiveMerchant
7
7
  end
8
8
 
9
9
  def purchase(amount, payment_method, options={})
10
- MultiResponse.run do |r|
11
- r.process { authorize(amount, payment_method, options) }
12
- r.process { capture(amount, r.authorization, options) }
10
+ if options[:pay_mode]
11
+ post = new_post
12
+ add_invoice(post, amount, options)
13
+ add_reference(post, *new_authorization)
14
+ add_payment_method(post, payment_method)
15
+ add_customer_data(post, payment_method, options)
16
+ add_3dsecure_id(post, options)
17
+
18
+ commit('pay', post)
19
+ else
20
+ MultiResponse.run do |r|
21
+ r.process { authorize(amount, payment_method, options) }
22
+ r.process { capture(amount, r.authorization, options) }
23
+ end
13
24
  end
14
25
  end
15
26
 
@@ -206,9 +217,23 @@ module ActiveMerchant
206
217
 
207
218
  def base_url
208
219
  if test?
209
- @options[:region] == 'asia_pacific' ? test_ap_url : test_na_url
220
+ case @options[:region]
221
+ when 'asia_pacific'
222
+ test_ap_url
223
+ when 'europe'
224
+ test_eu_url
225
+ when 'north_america', nil
226
+ test_na_url
227
+ end
210
228
  else
211
- @options[:region] == 'asia_pacific' ? live_ap_url : live_na_url
229
+ case @options[:region]
230
+ when 'asia_pacific'
231
+ live_ap_url
232
+ when 'europe'
233
+ live_eu_url
234
+ when 'north_america', nil
235
+ live_na_url
236
+ end
212
237
  end
213
238
  end
214
239
 
@@ -4,7 +4,7 @@ module ActiveMerchant #:nodoc:
4
4
  self.live_url = self.test_url = 'https://api.mercadopago.com/v1'
5
5
 
6
6
  self.supported_countries = ['AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY']
7
- self.supported_cardtypes = [:visa, :master, :american_express]
7
+ self.supported_cardtypes = [:visa, :master, :american_express, :elo, :cabal, :naranja]
8
8
 
9
9
  self.homepage_url = 'https://www.mercadopago.com/'
10
10
  self.display_name = 'Mercado Pago'
@@ -63,6 +63,7 @@ module ActiveMerchant #:nodoc:
63
63
  add_creditcard(post, creditcard)
64
64
  add_standard_parameters('pay', post, options[:unique_id])
65
65
  add_3ds(post, options)
66
+ add_tx_source(post, options)
66
67
 
67
68
  commit(post)
68
69
  end
@@ -83,6 +84,7 @@ module ActiveMerchant #:nodoc:
83
84
  add_amount(post, money, options)
84
85
  add_advanced_user(post)
85
86
  add_standard_parameters('capture', post, options[:unique_id])
87
+ add_tx_source(post, options)
86
88
 
87
89
  commit(post)
88
90
  end
@@ -99,6 +101,7 @@ module ActiveMerchant #:nodoc:
99
101
  add_amount(post, money, options)
100
102
  add_advanced_user(post)
101
103
  add_standard_parameters('refund', post, options[:unique_id])
104
+ add_tx_source(post, options)
102
105
 
103
106
  commit(post)
104
107
  end
@@ -110,6 +113,7 @@ module ActiveMerchant #:nodoc:
110
113
 
111
114
  add_advanced_user(post)
112
115
  add_standard_parameters('voidAuthorisation', post, options[:unique_id])
116
+ add_tx_source(post, options)
113
117
 
114
118
  commit(post)
115
119
  end
@@ -241,6 +245,10 @@ module ActiveMerchant #:nodoc:
241
245
  post['3DSstatus'] = options[:three_ds_status] if options[:three_ds_status]
242
246
  end
243
247
 
248
+ def add_tx_source(post, options)
249
+ post[:TxSource] = options[:tx_source] if options[:tx_source]
250
+ end
251
+
244
252
  def add_creditcard(post, creditcard)
245
253
  post[:CardNum] = creditcard.number
246
254
  post[:CardSecurityCode] = creditcard.verification_value if creditcard.verification_value?