activemerchant 1.123.0 → 1.125.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +131 -0
  3. data/lib/active_merchant/billing/check.rb +5 -8
  4. data/lib/active_merchant/billing/credit_card.rb +10 -0
  5. data/lib/active_merchant/billing/credit_card_methods.rb +6 -3
  6. data/lib/active_merchant/billing/gateway.rb +1 -1
  7. data/lib/active_merchant/billing/gateways/adyen.rb +61 -9
  8. data/lib/active_merchant/billing/gateways/card_stream.rb +17 -13
  9. data/lib/active_merchant/billing/gateways/cashnet.rb +15 -5
  10. data/lib/active_merchant/billing/gateways/checkout_v2.rb +33 -4
  11. data/lib/active_merchant/billing/gateways/cyber_source.rb +11 -3
  12. data/lib/active_merchant/billing/gateways/d_local.rb +12 -6
  13. data/lib/active_merchant/billing/gateways/decidir_plus.rb +173 -0
  14. data/lib/active_merchant/billing/gateways/ebanx.rb +16 -1
  15. data/lib/active_merchant/billing/gateways/elavon.rb +6 -3
  16. data/lib/active_merchant/billing/gateways/element.rb +20 -2
  17. data/lib/active_merchant/billing/gateways/global_collect.rb +111 -16
  18. data/lib/active_merchant/billing/gateways/ipg.rb +416 -0
  19. data/lib/active_merchant/billing/gateways/kushki.rb +7 -0
  20. data/lib/active_merchant/billing/gateways/mercado_pago.rb +3 -1
  21. data/lib/active_merchant/billing/gateways/mit.rb +260 -0
  22. data/lib/active_merchant/billing/gateways/moka.rb +24 -11
  23. data/lib/active_merchant/billing/gateways/mundipagg.rb +8 -6
  24. data/lib/active_merchant/billing/gateways/nmi.rb +15 -1
  25. data/lib/active_merchant/billing/gateways/orbital.rb +19 -3
  26. data/lib/active_merchant/billing/gateways/pay_arc.rb +9 -7
  27. data/lib/active_merchant/billing/gateways/pay_conex.rb +3 -1
  28. data/lib/active_merchant/billing/gateways/pay_trace.rb +1 -1
  29. data/lib/active_merchant/billing/gateways/payflow.rb +14 -6
  30. data/lib/active_merchant/billing/gateways/paymentez.rb +9 -2
  31. data/lib/active_merchant/billing/gateways/paysafe.rb +144 -23
  32. data/lib/active_merchant/billing/gateways/payu_latam.rb +6 -1
  33. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +3 -3
  34. data/lib/active_merchant/billing/gateways/pin.rb +31 -4
  35. data/lib/active_merchant/billing/gateways/priority.rb +347 -0
  36. data/lib/active_merchant/billing/gateways/realex.rb +18 -0
  37. data/lib/active_merchant/billing/gateways/safe_charge.rb +6 -2
  38. data/lib/active_merchant/billing/gateways/stripe.rb +27 -7
  39. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +96 -38
  40. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -1
  41. data/lib/active_merchant/billing/gateways/trust_commerce.rb +2 -1
  42. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +20 -6
  43. data/lib/active_merchant/billing/gateways/wompi.rb +193 -0
  44. data/lib/active_merchant/billing/gateways/worldpay.rb +196 -64
  45. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  46. data/lib/active_merchant/billing/response.rb +4 -0
  47. data/lib/active_merchant/version.rb +1 -1
  48. metadata +7 -2
@@ -5,34 +5,42 @@ module ActiveMerchant #:nodoc:
5
5
  # This gateway uses the current Stripe {Payment Intents API}[https://stripe.com/docs/api/payment_intents].
6
6
  # For the legacy API, see the Stripe gateway
7
7
  class StripePaymentIntentsGateway < StripeGateway
8
- self.supported_countries = %w(AT AU BE BG BR CA CH CY CZ DE DK EE ES FI FR GB GR HK IE IT JP LT LU LV MT MX NL NO NZ PL PT RO SE SG SI SK US)
9
-
10
8
  ALLOWED_METHOD_STATES = %w[automatic manual].freeze
11
9
  ALLOWED_CANCELLATION_REASONS = %w[duplicate fraudulent requested_by_customer abandoned].freeze
12
10
  CREATE_INTENT_ATTRIBUTES = %i[description statement_descriptor_suffix statement_descriptor receipt_email save_payment_method]
13
11
  CONFIRM_INTENT_ATTRIBUTES = %i[receipt_email return_url save_payment_method setup_future_usage off_session]
14
12
  UPDATE_INTENT_ATTRIBUTES = %i[description statement_descriptor_suffix statement_descriptor receipt_email setup_future_usage]
15
- DEFAULT_API_VERSION = '2019-05-16'
13
+ DEFAULT_API_VERSION = '2020-08-27'
14
+ NO_WALLET_SUPPORT = %w(apple_pay google_pay android_pay)
16
15
 
17
16
  def create_intent(money, payment_method, options = {})
17
+ card_source_pay = payment_method.source.to_s if defined?(payment_method.source)
18
+ card_brand_pay = card_brand(payment_method) unless payment_method.is_a?(String) || payment_method.nil?
19
+ if NO_WALLET_SUPPORT.include?(card_source_pay) || NO_WALLET_SUPPORT.include?(card_brand_pay)
20
+ store_apple_or_google_pay_token = 'Direct Apple Pay and Google Pay transactions are not supported. Those payment methods must be stored before use.'
21
+ return Response.new(false, store_apple_or_google_pay_token)
22
+ end
18
23
  post = {}
19
24
  add_amount(post, money, options, true)
20
25
  add_capture_method(post, options)
21
26
  add_confirmation_method(post, options)
22
27
  add_customer(post, options)
23
- payment_method = add_payment_method_token(post, payment_method, options)
24
- return payment_method if payment_method.is_a?(ActiveMerchant::Billing::Response)
28
+ result = add_payment_method_token(post, payment_method, options)
29
+ return result if result.is_a?(ActiveMerchant::Billing::Response)
25
30
 
26
31
  add_external_three_d_secure_auth_data(post, options)
27
32
  add_metadata(post, options)
28
33
  add_return_url(post, options)
29
34
  add_connected_account(post, options)
35
+ add_radar_data(post, options)
30
36
  add_shipping_address(post, options)
31
37
  setup_future_usage(post, options)
32
38
  add_exemption(post, options)
33
39
  add_stored_credentials(post, options)
34
40
  add_ntid(post, options)
41
+ add_claim_without_transaction_id(post, options)
35
42
  add_error_on_requires_action(post, options)
43
+ add_fulfillment_date(post, options)
36
44
  request_three_d_secure(post, options)
37
45
 
38
46
  CREATE_INTENT_ATTRIBUTES.each do |attribute|
@@ -48,23 +56,24 @@ module ActiveMerchant #:nodoc:
48
56
 
49
57
  def confirm_intent(intent_id, payment_method, options = {})
50
58
  post = {}
51
- payment_method = add_payment_method_token(post, payment_method, options)
52
- return payment_method if payment_method.is_a?(ActiveMerchant::Billing::Response)
59
+ result = add_payment_method_token(post, payment_method, options)
60
+ return result if result.is_a?(ActiveMerchant::Billing::Response)
53
61
 
54
62
  CONFIRM_INTENT_ATTRIBUTES.each do |attribute|
55
63
  add_whitelisted_attribute(post, options, attribute)
56
64
  end
65
+
57
66
  commit(:post, "payment_intents/#{intent_id}/confirm", post, options)
58
67
  end
59
68
 
60
69
  def create_payment_method(payment_method, options = {})
61
- post_data = create_payment_method_data(payment_method, options)
70
+ post_data = add_payment_method_data(payment_method, options)
62
71
 
63
72
  options = format_idempotency_key(options, 'pm')
64
73
  commit(:post, 'payment_methods', post_data, options)
65
74
  end
66
75
 
67
- def create_payment_method_data(payment_method, options = {})
76
+ def add_payment_method_data(payment_method, options = {})
68
77
  post_data = {}
69
78
  post_data[:type] = 'card'
70
79
  post_data[:card] = {}
@@ -73,6 +82,7 @@ module ActiveMerchant #:nodoc:
73
82
  post_data[:card][:exp_year] = payment_method.year
74
83
  post_data[:card][:cvc] = payment_method.verification_value if payment_method.verification_value
75
84
  add_billing_address(post_data, options)
85
+ add_name_only(post_data, payment_method) if post_data[:billing_details].nil?
76
86
  post_data
77
87
  end
78
88
 
@@ -80,14 +90,15 @@ module ActiveMerchant #:nodoc:
80
90
  post = {}
81
91
  add_amount(post, money, options)
82
92
 
83
- payment_method = add_payment_method_token(post, payment_method, options)
84
- return payment_method if payment_method.is_a?(ActiveMerchant::Billing::Response)
93
+ result = add_payment_method_token(post, payment_method, options)
94
+ return result if result.is_a?(ActiveMerchant::Billing::Response)
85
95
 
86
96
  add_payment_method_types(post, options)
87
97
  add_customer(post, options)
88
98
  add_metadata(post, options)
89
99
  add_shipping_address(post, options)
90
100
  add_connected_account(post, options)
101
+ add_fulfillment_date(post, options)
91
102
 
92
103
  UPDATE_INTENT_ATTRIBUTES.each do |attribute|
93
104
  add_whitelisted_attribute(post, options, attribute)
@@ -98,11 +109,12 @@ module ActiveMerchant #:nodoc:
98
109
  def create_setup_intent(payment_method, options = {})
99
110
  post = {}
100
111
  add_customer(post, options)
101
- payment_method = add_payment_method_token(post, payment_method, options)
102
- return payment_method if payment_method.is_a?(ActiveMerchant::Billing::Response)
112
+ result = add_payment_method_token(post, payment_method, options)
113
+ return result if result.is_a?(ActiveMerchant::Billing::Response)
103
114
 
104
115
  add_metadata(post, options)
105
116
  add_return_url(post, options)
117
+ add_fulfillment_date(post, options)
106
118
  post[:on_behalf_of] = options[:on_behalf_of] if options[:on_behalf_of]
107
119
  post[:usage] = options[:usage] if %w(on_session off_session).include?(options[:usage])
108
120
  post[:description] = options[:description] if options[:description]
@@ -178,8 +190,8 @@ module ActiveMerchant #:nodoc:
178
190
  # If customer option is provided, create a payment method and attach to customer id
179
191
  # Otherwise, create a customer, then attach
180
192
  if payment_method.is_a?(StripePaymentToken) || payment_method.is_a?(ActiveMerchant::Billing::CreditCard)
181
- payment_method = add_payment_method_token(params, payment_method, options)
182
- return payment_method if payment_method.is_a?(ActiveMerchant::Billing::Response)
193
+ result = add_payment_method_token(params, payment_method, options)
194
+ return result if result.is_a?(ActiveMerchant::Billing::Response)
183
195
 
184
196
  if options[:customer]
185
197
  customer_id = options[:customer]
@@ -187,6 +199,7 @@ module ActiveMerchant #:nodoc:
187
199
  post[:description] = options[:description] if options[:description]
188
200
  post[:email] = options[:email] if options[:email]
189
201
  options = format_idempotency_key(options, 'customer')
202
+ post[:expand] = [:sources]
190
203
  customer = commit(:post, 'customers', post, options)
191
204
  customer_id = customer.params['id']
192
205
  end
@@ -212,6 +225,16 @@ module ActiveMerchant #:nodoc:
212
225
  create_setup_intent(payment_method, options.merge!(confirm: true))
213
226
  end
214
227
 
228
+ def setup_purchase(money, options = {})
229
+ requires!(options, :payment_method_types)
230
+ post = {}
231
+ add_currency(post, options, money)
232
+ add_amount(post, money, options)
233
+ add_payment_method_types(post, options)
234
+ add_metadata(post, options)
235
+ commit(:post, 'payment_intents', post, options)
236
+ end
237
+
215
238
  private
216
239
 
217
240
  def off_session_request?(options = {})
@@ -242,6 +265,16 @@ module ActiveMerchant #:nodoc:
242
265
  post[:customer] = customer if customer.start_with?('cus_')
243
266
  end
244
267
 
268
+ def add_fulfillment_date(post, options)
269
+ post[:fulfillment_date] = options[:fulfillment_date].to_i if options[:fulfillment_date]
270
+ end
271
+
272
+ def add_metadata(post, options = {})
273
+ super
274
+
275
+ post[:metadata][:event_type] = options[:event_type] if options[:event_type]
276
+ end
277
+
245
278
  def add_return_url(post, options)
246
279
  return unless options[:confirm]
247
280
 
@@ -250,35 +283,36 @@ module ActiveMerchant #:nodoc:
250
283
  end
251
284
 
252
285
  def add_payment_method_token(post, payment_method, options)
253
- return if payment_method.nil?
254
-
255
- if payment_method.is_a?(ActiveMerchant::Billing::CreditCard)
256
- if off_session_request?(options)
257
- post[:payment_method_data] = create_payment_method_data(payment_method, options)
258
- return
259
- else
260
- p = create_payment_method(payment_method, options)
261
- return p unless p.success?
262
-
263
- payment_method = p.params['id']
264
- end
265
- end
266
-
267
286
  case payment_method
268
287
  when StripePaymentToken
269
288
  post[:payment_method] = payment_method.payment_data['id']
270
289
  when String
271
- if payment_method.include?('|')
272
- customer_id, payment_method_id = payment_method.split('|')
273
- token = payment_method_id
274
- post[:customer] = customer_id
275
- else
276
- token = payment_method
277
- end
278
- post[:payment_method] = token
290
+ extract_token_from_string_and_maybe_add_customer_id(post, payment_method)
291
+ when ActiveMerchant::Billing::CreditCard
292
+ get_payment_method_data_from_card(post, payment_method, options)
279
293
  end
294
+ end
280
295
 
281
- post
296
+ def extract_token_from_string_and_maybe_add_customer_id(post, payment_method)
297
+ if payment_method.include?('|')
298
+ customer_id, payment_method = payment_method.split('|')
299
+ post[:customer] = customer_id
300
+ end
301
+
302
+ post[:payment_method] = payment_method
303
+ end
304
+
305
+ def get_payment_method_data_from_card(post, payment_method, options)
306
+ return create_payment_method_and_extract_token(post, payment_method, options) unless off_session_request?(options)
307
+
308
+ post[:payment_method_data] = add_payment_method_data(payment_method, options)
309
+ end
310
+
311
+ def create_payment_method_and_extract_token(post, payment_method, options)
312
+ payment_method_response = create_payment_method(payment_method, options)
313
+ return payment_method_response if payment_method_response.failure?
314
+
315
+ add_payment_method_token(post, payment_method_response.params['id'], options)
282
316
  end
283
317
 
284
318
  def add_payment_method_types(post, options)
@@ -326,6 +360,19 @@ module ActiveMerchant #:nodoc:
326
360
  post[:payment_method_options][:card][:mit_exemption][:network_transaction_id] = options[:network_transaction_id] if options[:network_transaction_id]
327
361
  end
328
362
 
363
+ def add_claim_without_transaction_id(post, options = {})
364
+ return if options[:stored_credential] || options[:network_transaction_id] || options[:ds_transaction_id]
365
+ return unless options[:claim_without_transaction_id]
366
+
367
+ post[:payment_method_options] ||= {}
368
+ post[:payment_method_options][:card] ||= {}
369
+ post[:payment_method_options][:card][:mit_exemption] = {}
370
+
371
+ # Stripe PI accepts claim_without_transaction_id for transactions without transaction ids.
372
+ # Gateway validation for this field occurs through a different service, before the transaction request is sent to the gateway.
373
+ post[:payment_method_options][:card][:mit_exemption][:claim_without_transaction_id] = options[:claim_without_transaction_id]
374
+ end
375
+
329
376
  def add_error_on_requires_action(post, options = {})
330
377
  return unless options[:confirm]
331
378
 
@@ -375,6 +422,13 @@ module ActiveMerchant #:nodoc:
375
422
  post[:billing_details][:phone] = billing[:phone] if billing[:phone]
376
423
  end
377
424
 
425
+ def add_name_only(post, payment_method)
426
+ post[:billing_details] = {} unless post[:billing_details]
427
+
428
+ name = [payment_method.first_name, payment_method.last_name].compact.join(' ')
429
+ post[:billing_details][:name] = name
430
+ end
431
+
378
432
  def add_shipping_address(post, options = {})
379
433
  return unless shipping = options[:shipping]
380
434
 
@@ -408,6 +462,10 @@ module ActiveMerchant #:nodoc:
408
462
 
409
463
  super(response, options)
410
464
  end
465
+
466
+ def add_currency(post, options, money)
467
+ post[:currency] = options[:currency] || currency(money)
468
+ end
411
469
  end
412
470
  end
413
471
  end
@@ -317,7 +317,8 @@ module ActiveMerchant #:nodoc:
317
317
  gsub(%r((<[^>]+pan>)[^<]+(<))i, '\1[FILTERED]\2').
318
318
  gsub(%r((<[^>]+sec>)[^<]+(<))i, '\1[FILTERED]\2').
319
319
  gsub(%r((<[^>]+id>)[^<]+(<))i, '\1[FILTERED]\2').
320
- gsub(%r((<[^>]+regKey>)[^<]+(<))i, '\1[FILTERED]\2')
320
+ gsub(%r((<[^>]+regKey>)[^<]+(<))i, '\1[FILTERED]\2').
321
+ gsub(%r((<[^>]+acctNr>)[^<]+(<))i, '\1[FILTERED]\2')
321
322
  end
322
323
 
323
324
  private
@@ -331,7 +331,8 @@ module ActiveMerchant #:nodoc:
331
331
  gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
332
332
  gsub(%r((&?cc=)\d*(&?)), '\1[FILTERED]\2').
333
333
  gsub(%r((&?password=)[^&]+(&?)), '\1[FILTERED]\2').
334
- gsub(%r((&?cvv=)\d*(&?)), '\1[FILTERED]\2')
334
+ gsub(%r((&?cvv=)\d*(&?)), '\1[FILTERED]\2').
335
+ gsub(%r((&?account=)\d*(&?)), '\1[FILTERED]\2')
335
336
  end
336
337
 
337
338
  private
@@ -16,7 +16,8 @@ module ActiveMerchant #:nodoc:
16
16
  refund: 'cc:refund',
17
17
  void: 'cc:void',
18
18
  void_release: 'cc:void:release',
19
- check_purchase: 'check:sale'
19
+ check_purchase: 'check:sale',
20
+ store: 'cc:save'
20
21
  }
21
22
 
22
23
  STANDARD_ERROR_CODE_MAPPING = {
@@ -43,14 +44,14 @@ module ActiveMerchant #:nodoc:
43
44
  super
44
45
  end
45
46
 
46
- def authorize(money, credit_card, options = {})
47
+ def authorize(money, payment, options = {})
47
48
  post = {}
48
49
 
49
50
  add_amount(post, money)
50
51
  add_invoice(post, options)
51
- add_payment(post, credit_card)
52
- unless credit_card.track_data.present?
53
- add_address(post, credit_card, options)
52
+ add_payment(post, payment)
53
+ unless payment.is_a?(CreditCard) && payment.track_data.present?
54
+ add_address(post, payment, options)
54
55
  add_customer_data(post, options)
55
56
  end
56
57
  add_split_payments(post, options)
@@ -97,6 +98,12 @@ module ActiveMerchant #:nodoc:
97
98
  commit(:refund, post)
98
99
  end
99
100
 
101
+ def store(payment, options = {})
102
+ post = {}
103
+ add_payment(post, payment, options)
104
+ commit(:store, post)
105
+ end
106
+
100
107
  def verify(creditcard, options = {})
101
108
  MultiResponse.run(:use_first_response) do |r|
102
109
  r.process { authorize(1, creditcard, options) }
@@ -213,6 +220,8 @@ module ActiveMerchant #:nodoc:
213
220
  elsif payment.respond_to?(:track_data) && payment.track_data.present?
214
221
  post[:magstripe] = payment.track_data
215
222
  post[:cardpresent] = true
223
+ elsif payment.is_a?(String)
224
+ post[:card] = payment
216
225
  else
217
226
  post[:card] = payment.number
218
227
  post[:cvv2] = payment.verification_value if payment.verification_value?
@@ -299,6 +308,7 @@ module ActiveMerchant #:nodoc:
299
308
  status: fields['UMstatus'],
300
309
  auth_code: fields['UMauthCode'],
301
310
  ref_num: fields['UMrefNum'],
311
+ card_ref: fields['UMcardRef'],
302
312
  batch: fields['UMbatch'],
303
313
  avs_result: fields['UMavsResult'],
304
314
  avs_result_code: fields['UMavsResultCode'],
@@ -321,7 +331,7 @@ module ActiveMerchant #:nodoc:
321
331
  error_code = (STANDARD_ERROR_CODE_MAPPING[response[:error_code]] || STANDARD_ERROR_CODE[:processing_error]) unless approved
322
332
  Response.new(approved, message_from(response), response,
323
333
  test: test?,
324
- authorization: response[:ref_num],
334
+ authorization: authorization_from(action, response),
325
335
  cvv_result: response[:cvv2_result_code],
326
336
  avs_result: { code: response[:avs_result_code] },
327
337
  error_code: error_code)
@@ -337,6 +347,10 @@ module ActiveMerchant #:nodoc:
337
347
  end
338
348
  end
339
349
 
350
+ def authorization_from(action, response)
351
+ return (action == :store ? response[:card_ref] : response[:ref_num])
352
+ end
353
+
340
354
  def post_data(action, parameters = {})
341
355
  parameters[:command] = TRANSACTIONS[action]
342
356
  parameters[:key] = @options[:login]
@@ -0,0 +1,193 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class WompiGateway < Gateway
4
+ self.test_url = 'https://sync.sandbox.wompi.co/v1'
5
+ self.live_url = 'https://sync.production.wompi.co/v1'
6
+
7
+ self.supported_countries = ['CO']
8
+ self.default_currency = 'COP'
9
+ self.supported_cardtypes = %i[visa master american_express]
10
+
11
+ self.homepage_url = 'https://wompi.co/'
12
+ self.display_name = 'Wompi'
13
+
14
+ self.money_format = :cents
15
+
16
+ def initialize(options = {})
17
+ ## Sandbox keys have prefix pub_test_ and prv_test_
18
+ ## Production keys have prefix pub_prod_ and prv_prod_
19
+ begin
20
+ requires!(options, :prod_private_key, :prod_public_key)
21
+ rescue ArgumentError
22
+ begin
23
+ requires!(options, :test_private_key, :test_public_key)
24
+ rescue ArgumentError
25
+ raise ArgumentError, 'Gateway requires both test_private_key and test_public_key, or both prod_private_key and prod_public_key'
26
+ end
27
+ end
28
+ super
29
+ end
30
+
31
+ def purchase(money, payment, options = {})
32
+ post = {
33
+ reference: options[:reference] || generate_reference,
34
+ public_key: public_key
35
+ }
36
+ add_invoice(post, money, options)
37
+ add_card(post, payment, options)
38
+
39
+ commit('sale', post, '/transactions_sync')
40
+ end
41
+
42
+ def authorize(money, payment, options = {})
43
+ post = {
44
+ public_key: public_key,
45
+ type: 'CARD',
46
+ financial_operation: 'PREAUTHORIZATION'
47
+ }
48
+ add_auth_params(post, money, payment, options)
49
+
50
+ commit('authorize', post, '/payment_sources_sync')
51
+ end
52
+
53
+ def capture(money, authorization, options = {})
54
+ post = {
55
+ reference: options[:reference] || generate_reference,
56
+ public_key: public_key,
57
+ payment_source_id: authorization.to_i
58
+ }
59
+ add_invoice(post, money, options)
60
+ commit('capture', post, '/transactions_sync')
61
+ end
62
+
63
+ def refund(money, authorization, options = {})
64
+ post = { amount_in_cents: amount(money).to_i, transaction_id: authorization.to_s }
65
+ commit('refund', post, '/refunds_sync')
66
+ end
67
+
68
+ def void(authorization, options = {})
69
+ commit('void', {}, "/transactions/#{authorization}/void_sync")
70
+ end
71
+
72
+ def supports_scrubbing?
73
+ true
74
+ end
75
+
76
+ def scrub(transcript)
77
+ transcript.gsub(/(Bearer )\w+/, '\1[REDACTED]').
78
+ gsub(/(\\\"number\\\":\\\")\d+/, '\1[REDACTED]').
79
+ gsub(/(\\\"cvc\\\":\\\")\d+/, '\1[REDACTED]').
80
+ gsub(/(\\\"phone_number\\\":\\\")\+?\d+/, '\1[REDACTED]').
81
+ gsub(/(\\\"email\\\":\\\")\S+\\\",/, '\1[REDACTED]\",').
82
+ gsub(/(\\\"legal_id\\\":\\\")\d+/, '\1[REDACTED]')
83
+ end
84
+
85
+ private
86
+
87
+ def headers
88
+ {
89
+ 'Authorization' => "Bearer #{private_key}",
90
+ 'Content-Type' => 'application/json'
91
+ }
92
+ end
93
+
94
+ def generate_reference
95
+ SecureRandom.alphanumeric(12)
96
+ end
97
+
98
+ def private_key
99
+ test? ? options[:test_private_key] : options[:prod_private_key]
100
+ end
101
+
102
+ def public_key
103
+ test? ? options[:test_public_key] : options[:prod_public_key]
104
+ end
105
+
106
+ def add_invoice(post, money, options)
107
+ post[:amount_in_cents] = amount(money).to_i
108
+ post[:currency] = (options[:currency] || currency(money))
109
+ end
110
+
111
+ def add_card(post, card, options)
112
+ payment_method = {
113
+ type: 'CARD'
114
+ }
115
+ add_basic_card_info(payment_method, card, options)
116
+ post[:payment_method] = payment_method
117
+ end
118
+
119
+ def add_auth_params(post, money, card, options)
120
+ data = {
121
+ amount_in_cents: amount(money).to_i,
122
+ currency: (options[:currency] || currency(money))
123
+ }
124
+ add_basic_card_info(data, card, options)
125
+ post[:data] = data
126
+ end
127
+
128
+ def add_basic_card_info(post, card, options)
129
+ installments = options[:installments] ? options[:installments].to_i : 1
130
+ cvc = card.verification_value || nil
131
+
132
+ post[:number] = card.number
133
+ post[:exp_month] = card.month.to_s.rjust(2, '0')
134
+ post[:exp_year] = card.year.to_s[2..3]
135
+ post[:installments] = installments
136
+ post[:card_holder] = card.name
137
+ post[:cvc] = cvc if cvc && !cvc.empty?
138
+ end
139
+
140
+ def parse(body)
141
+ JSON.parse(body)
142
+ end
143
+
144
+ def commit(action, parameters, endpoint)
145
+ url = (test? ? test_url : live_url) + endpoint
146
+ response = parse(ssl_post(url, post_data(action, parameters), headers))
147
+ Response.new(
148
+ success_from(response),
149
+ message_from(response),
150
+ response,
151
+ authorization: authorization_from(response),
152
+ avs_result: nil,
153
+ cvv_result: nil,
154
+ test: test?,
155
+ error_code: error_code_from(response)
156
+ )
157
+ end
158
+
159
+ def handle_response(response)
160
+ case response.code.to_i
161
+ when 200...300, 401, 404, 422
162
+ response.body
163
+ else
164
+ raise ResponseError.new(response)
165
+ end
166
+ end
167
+
168
+ def success_from(response)
169
+ success_statuses.include? response.dig('data', 'status')
170
+ end
171
+
172
+ def success_statuses
173
+ %w(APPROVED AVAILABLE)
174
+ end
175
+
176
+ def message_from(response)
177
+ response.dig('data', 'status_message') || response.dig('error', 'reason') || response.dig('error', 'messages').to_json
178
+ end
179
+
180
+ def authorization_from(response)
181
+ response.dig('data', 'transaction_id') || response.dig('data', 'id') || response.dig('data', 'transaction', 'id')
182
+ end
183
+
184
+ def post_data(action, parameters = {})
185
+ parameters.to_json
186
+ end
187
+
188
+ def error_code_from(response)
189
+ response.dig('error', 'type') unless success_from(response)
190
+ end
191
+ end
192
+ end
193
+ end