activemerchant 1.123.0 → 1.125.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 (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
@@ -4,8 +4,7 @@ module ActiveMerchant #:nodoc:
4
4
  self.test_url = 'https://api.test.paysafe.com'
5
5
  self.live_url = 'https://api.paysafe.com'
6
6
 
7
- self.supported_countries = %w(FR)
8
- self.default_currency = 'EUR'
7
+ self.supported_countries = %w(AL AT BE BA BG CA HR CY CZ DK EE FI FR DE GR HU IS IE IT LV LI LT LU MT ME NL MK NO PL PT RO RS SK SI ES SE CH TR GB US)
9
8
  self.supported_cardtypes = %i[visa master american_express discover]
10
9
 
11
10
  self.homepage_url = 'https://www.paysafe.com/'
@@ -22,8 +21,11 @@ module ActiveMerchant #:nodoc:
22
21
  add_payment(post, payment)
23
22
  add_billing_address(post, options)
24
23
  add_merchant_details(post, options)
24
+ add_airline_travel_details(post, options)
25
25
  add_customer_data(post, payment, options) unless payment.is_a?(String)
26
26
  add_three_d_secure(post, payment, options) if options[:three_d_secure]
27
+ add_stored_credential(post, options) if options[:stored_credential]
28
+ add_split_pay_details(post, options)
27
29
  post[:settleWithAuth] = true
28
30
 
29
31
  commit(:post, 'auths', post, options)
@@ -37,6 +39,7 @@ module ActiveMerchant #:nodoc:
37
39
  add_merchant_details(post, options)
38
40
  add_customer_data(post, payment, options) unless payment.is_a?(String)
39
41
  add_three_d_secure(post, payment, options) if options[:three_d_secure]
42
+ add_stored_credential(post, options) if options[:stored_credential]
40
43
 
41
44
  commit(:post, 'auths', post, options)
42
45
  end
@@ -91,8 +94,8 @@ module ActiveMerchant #:nodoc:
91
94
  commit(:post, 'profiles', post, options)
92
95
  end
93
96
 
94
- def redact(pm_profile_id)
95
- commit_for_redact(:delete, "profiles/#{pm_profile_id}", nil, nil)
97
+ def unstore(pm_profile_id)
98
+ commit_for_unstore(:delete, "profiles/#{pm_profile_id}", nil, nil)
96
99
  end
97
100
 
98
101
  def supports_scrubbing?
@@ -119,9 +122,8 @@ module ActiveMerchant #:nodoc:
119
122
  end
120
123
 
121
124
  def add_billing_address(post, options)
122
- return unless options[:billing_address] || options[:address]
125
+ return unless address = options[:billing_address] || options[:address]
123
126
 
124
- address = options[:billing_address] || options[:address]
125
127
  post[:billingDetails] = {}
126
128
  post[:billingDetails][:street] = address[:address1]
127
129
  post[:billingDetails][:city] = address[:city]
@@ -134,21 +136,19 @@ module ActiveMerchant #:nodoc:
134
136
  # The add_address_for_vaulting method is applicable to the store method, as the APIs address
135
137
  # object is formatted differently from the standard transaction billing address
136
138
  def add_address_for_vaulting(post, options)
137
- return unless options[:billing_address || options[:address]]
139
+ return unless address = options[:billing_address] || options[:address]
138
140
 
139
- address = options[:billing_address] || options[:address]
140
- post[:billingAddress] = {}
141
- post[:billingAddress][:street] = address[:address1]
142
- post[:billingAddress][:city] = address[:city]
143
- post[:billingAddress][:zip] = address[:zip]
144
- post[:billingAddress][:country] = address[:country]
145
- post[:billingAddress][:state] = address[:state] if address[:state]
141
+ post[:card][:billingAddress] = {}
142
+ post[:card][:billingAddress][:street] = address[:address1]
143
+ post[:card][:billingAddress][:street2] = address[:address2]
144
+ post[:card][:billingAddress][:city] = address[:city]
145
+ post[:card][:billingAddress][:zip] = address[:zip]
146
+ post[:card][:billingAddress][:country] = address[:country]
147
+ post[:card][:billingAddress][:state] = address[:state] if address[:state]
146
148
  end
147
149
 
148
150
  # This data is specific to creating a profile at the gateway's vault level
149
151
  def add_profile_data(post, payment, options)
150
- address = options[:billing_address] || options[:address]
151
-
152
152
  post[:firstName] = payment.first_name
153
153
  post[:lastName] = payment.last_name
154
154
  post[:dateOfBirth] = {}
@@ -156,8 +156,13 @@ module ActiveMerchant #:nodoc:
156
156
  post[:dateOfBirth][:month] = options[:date_of_birth][:month]
157
157
  post[:dateOfBirth][:day] = options[:date_of_birth][:day]
158
158
  post[:email] = options[:email] if options[:email]
159
- post[:phone] = (address[:phone] || options[:phone]) if address[:phone] || options[:phone]
160
159
  post[:ip] = options[:ip] if options[:ip]
160
+
161
+ if options[:phone]
162
+ post[:phone] = options[:phone]
163
+ elsif address = options[:billing_address] || options[:address]
164
+ post[:phone] = address[:phone] if address[:phone]
165
+ end
161
166
  end
162
167
 
163
168
  def add_store_data(post, payment, options)
@@ -200,7 +205,119 @@ module ActiveMerchant #:nodoc:
200
205
  post[:authentication][:cavv] = three_d_secure[:cavv]
201
206
  post[:authentication][:xid] = three_d_secure[:xid] if three_d_secure[:xid]
202
207
  post[:authentication][:threeDSecureVersion] = three_d_secure[:version]
203
- post[:authentication][:directoryServerTransactionId] = three_d_secure[:ds_transaction_id] unless payment.is_a?(String) || payment.brand != 'mastercard'
208
+ post[:authentication][:directoryServerTransactionId] = three_d_secure[:ds_transaction_id] unless payment.is_a?(String) || !mastercard?(payment)
209
+ end
210
+
211
+ def add_airline_travel_details(post, options)
212
+ return unless options[:airline_travel_details]
213
+
214
+ post[:airlineTravelDetails] = {}
215
+ post[:airlineTravelDetails][:passengerName] = options[:airline_travel_details][:passenger_name] if options[:airline_travel_details][:passenger_name]
216
+ post[:airlineTravelDetails][:departureDate] = options[:airline_travel_details][:departure_date] if options[:airline_travel_details][:departure_date]
217
+ post[:airlineTravelDetails][:origin] = options[:airline_travel_details][:origin] if options[:airline_travel_details][:origin]
218
+ post[:airlineTravelDetails][:computerizedReservationSystem] = options[:airline_travel_details][:computerized_reservation_system] if options[:airline_travel_details][:computerized_reservation_system]
219
+ post[:airlineTravelDetails][:customerReferenceNumber] = options[:airline_travel_details][:customer_reference_number] if options[:airline_travel_details][:customer_reference_number]
220
+
221
+ add_ticket_details(post, options)
222
+ add_travel_agency_details(post, options)
223
+ add_trip_legs(post, options)
224
+ end
225
+
226
+ def add_ticket_details(post, options)
227
+ return unless ticket = options[:airline_travel_details][:ticket]
228
+
229
+ post[:airlineTravelDetails][:ticket] = {}
230
+ post[:airlineTravelDetails][:ticket][:ticketNumber] = ticket[:ticket_number] if ticket[:ticket_number]
231
+ post[:airlineTravelDetails][:ticket][:isRestrictedTicket] = ticket[:is_restricted_ticket] if ticket[:is_restricted_ticket]
232
+ end
233
+
234
+ def add_travel_agency_details(post, options)
235
+ return unless agency = options[:airline_travel_details][:travel_agency]
236
+
237
+ post[:airlineTravelDetails][:travelAgency] = {}
238
+ post[:airlineTravelDetails][:travelAgency][:name] = agency[:name] if agency[:name]
239
+ post[:airlineTravelDetails][:travelAgency][:code] = agency[:code] if agency[:code]
240
+ end
241
+
242
+ def add_trip_legs(post, options)
243
+ return unless trip_legs = options[:airline_travel_details][:trip_legs]
244
+
245
+ trip_legs_hash = {}
246
+ trip_legs.each.with_index(1) do |leg, i|
247
+ my_leg = "leg#{i}".to_sym
248
+ details = add_leg_details(my_leg, leg[1])
249
+
250
+ trip_legs_hash[my_leg] = details
251
+ end
252
+ post[:airlineTravelDetails][:tripLegs] = trip_legs_hash
253
+ end
254
+
255
+ def add_leg_details(obj, leg)
256
+ details = {}
257
+ add_flight_details(details, obj, leg)
258
+ details[:serviceClass] = leg[:service_class] if leg[:service_class]
259
+ details[:isStopOverAllowed] = leg[:is_stop_over_allowed] if leg[:is_stop_over_allowed]
260
+ details[:destination] = leg[:destination] if leg[:destination]
261
+ details[:fareBasis] = leg[:fare_basis] if leg[:fare_basis]
262
+ details[:departureDate] = leg[:departure_date] if leg[:departure_date]
263
+
264
+ details
265
+ end
266
+
267
+ def add_flight_details(details, obj, leg)
268
+ details[:flight] = {}
269
+ details[:flight][:carrierCode] = leg[:flight][:carrier_code] if leg[:flight][:carrier_code]
270
+ details[:flight][:flightNumber] = leg[:flight][:flight_number] if leg[:flight][:flight_number]
271
+ end
272
+
273
+ def add_split_pay_details(post, options)
274
+ return unless options[:split_pay]
275
+
276
+ split_pay = []
277
+ options[:split_pay].each do |pmnt|
278
+ split = {}
279
+
280
+ split[:linkedAccount] = pmnt[:linked_account]
281
+ split[:amount] = pmnt[:amount].to_i if pmnt[:amount]
282
+ split[:percent] = pmnt[:percent].to_i if pmnt[:percent]
283
+
284
+ split_pay << split
285
+ end
286
+ post[:splitpay] = split_pay
287
+ end
288
+
289
+ def add_stored_credential(post, options)
290
+ return unless options[:stored_credential]
291
+
292
+ post[:storedCredential] = {}
293
+
294
+ case options[:stored_credential][:initial_transaction]
295
+ when true
296
+ post[:storedCredential][:occurrence] = 'INITIAL'
297
+ when false
298
+ post[:storedCredential][:occurrence] = 'SUBSEQUENT'
299
+ end
300
+
301
+ case options[:stored_credential][:reason_type]
302
+ when 'recurring' || 'installment'
303
+ post[:storedCredential][:type] = 'RECURRING'
304
+ when 'unscheduled'
305
+ if options[:stored_credential][:initiator] == 'merchant'
306
+ post[:storedCredential][:type] = 'TOPUP'
307
+ elsif options[:stored_credential][:initiator] == 'cardholder'
308
+ post[:storedCredential][:type] = 'ADHOC'
309
+ else
310
+ return
311
+ end
312
+ end
313
+
314
+ post[:storedCredential][:initialTransactionId] = options[:stored_credential][:network_transaction_id] if options[:stored_credential][:network_transaction_id]
315
+ end
316
+
317
+ def mastercard?(payment)
318
+ return false unless payment.respond_to?(:brand)
319
+
320
+ payment.brand == 'master'
204
321
  end
205
322
 
206
323
  def parse(body)
@@ -217,7 +334,7 @@ module ActiveMerchant #:nodoc:
217
334
  success,
218
335
  message_from(success, response),
219
336
  response,
220
- authorization: authorization_from(response),
337
+ authorization: authorization_from(action, response),
221
338
  avs_result: AVSResult.new(code: response['avsResponse']),
222
339
  cvv_result: CVVResult.new(response['cvvVerification']),
223
340
  test: test?,
@@ -225,7 +342,7 @@ module ActiveMerchant #:nodoc:
225
342
  )
226
343
  end
227
344
 
228
- def commit_for_redact(method, action, parameters, options)
345
+ def commit_for_unstore(method, action, parameters, options)
229
346
  url = url(action)
230
347
  response = raw_ssl_request(method, url, post_data(parameters, options), headers)
231
348
  success = true if response.code == '200'
@@ -239,7 +356,7 @@ module ActiveMerchant #:nodoc:
239
356
  def headers
240
357
  {
241
358
  'Content-Type' => 'application/json',
242
- 'Authorization' => "Basic #{Base64.strict_encode64(@options[:api_key].to_s)}"
359
+ 'Authorization' => 'Basic ' + Base64.strict_encode64("#{@options[:username]}:#{@options[:password]}")
243
360
  }
244
361
  end
245
362
 
@@ -265,8 +382,12 @@ module ActiveMerchant #:nodoc:
265
382
  "Error(s)- code:#{response['error']['code']}, message:#{response['error']['message']}"
266
383
  end
267
384
 
268
- def authorization_from(response)
269
- response['id']
385
+ def authorization_from(action, response)
386
+ if action == 'profiles'
387
+ response['cards'].first['paymentToken']
388
+ else
389
+ response['id']
390
+ end
270
391
  end
271
392
 
272
393
  def post_data(parameters = {}, options = {})
@@ -17,6 +17,7 @@ module ActiveMerchant #:nodoc:
17
17
  BRAND_MAP = {
18
18
  'visa' => 'VISA',
19
19
  'master' => 'MASTERCARD',
20
+ 'maestro' => 'MASTERCARD',
20
21
  'american_express' => 'AMEX',
21
22
  'diners_club' => 'DINERS',
22
23
  'naranja' => 'NARANJA',
@@ -278,6 +279,10 @@ module ActiveMerchant #:nodoc:
278
279
  Digest::MD5.hexdigest(signature_string)
279
280
  end
280
281
 
282
+ def codensa_bin?(number)
283
+ number.start_with?('590712')
284
+ end
285
+
281
286
  def add_payment_method(post, payment_method, options)
282
287
  if payment_method.is_a?(String)
283
288
  brand, token = split_authorization(payment_method)
@@ -295,7 +300,7 @@ module ActiveMerchant #:nodoc:
295
300
  credit_card[:name] = payment_method.name.strip
296
301
  credit_card[:processWithoutCvv2] = true if add_process_without_cvv2(payment_method, options)
297
302
  post[:transaction][:creditCard] = credit_card
298
- post[:transaction][:paymentMethod] = BRAND_MAP[payment_method.brand.to_s]
303
+ post[:transaction][:paymentMethod] = codensa_bin?(payment_method.number) ? 'CODENSA' : BRAND_MAP[payment_method.brand.to_s]
299
304
  end
300
305
  end
301
306
 
@@ -1,8 +1,8 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
3
  class PaywayDotComGateway < Gateway
4
- self.test_url = 'https://devedgilpayway.net/PaywayWS/Payment/CreditCard'
5
- self.live_url = 'https://edgilpayway.com/PaywayWS/Payment/CreditCard'
4
+ self.test_url = 'https://paywaywsdev.com/PaywayWS/Payment/CreditCard'
5
+ self.live_url = 'https://paywayws.com/PaywayWS/Payment/CreditCard'
6
6
 
7
7
  self.supported_countries = %w[US CA]
8
8
  self.default_currency = 'USD'
@@ -233,7 +233,7 @@ module ActiveMerchant #:nodoc:
233
233
 
234
234
  return response['paywayCode'] + '-' + 'success' if success
235
235
 
236
- response['paywayCode'] + '-' + response['paywayMessage']
236
+ response['paywayCode']
237
237
  end
238
238
 
239
239
  def authorization_from(response)
@@ -6,8 +6,8 @@ module ActiveMerchant #:nodoc:
6
6
 
7
7
  self.default_currency = 'AUD'
8
8
  self.money_format = :cents
9
- self.supported_countries = ['AU']
10
- self.supported_cardtypes = %i[visa master american_express]
9
+ self.supported_countries = %w(AU NZ)
10
+ self.supported_cardtypes = %i[visa master american_express diners_club discover jcb]
11
11
  self.homepage_url = 'http://www.pinpayments.com/'
12
12
  self.display_name = 'Pin Payments'
13
13
 
@@ -46,6 +46,17 @@ module ActiveMerchant #:nodoc:
46
46
  commit(:post, 'customers', post, options)
47
47
  end
48
48
 
49
+ # Unstore a customer and associated credit card.
50
+ def unstore(token)
51
+ customer_token =
52
+ if /cus_/.match?(token)
53
+ get_customer_token(token)
54
+ else
55
+ token
56
+ end
57
+ commit(:delete, "customers/#{CGI.escape(customer_token)}", {}, {})
58
+ end
59
+
49
60
  # Refund a transaction
50
61
  def refund(money, token, options = {})
51
62
  commit(:post, "charges/#{CGI.escape(token)}/refunds", { amount: amount(money) }, options)
@@ -65,6 +76,11 @@ module ActiveMerchant #:nodoc:
65
76
  commit(:put, "charges/#{CGI.escape(token)}/capture", { amount: amount(money) }, options)
66
77
  end
67
78
 
79
+ # Voids a previously authorized charge.
80
+ def void(token, options = {})
81
+ commit(:put, "charges/#{CGI.escape(token)}/void", {}, options)
82
+ end
83
+
68
84
  # Updates the credit card for the customer.
69
85
  def update(token, creditcard, options = {})
70
86
  post = {}
@@ -190,7 +206,9 @@ module ActiveMerchant #:nodoc:
190
206
  body = parse(e.response.body)
191
207
  end
192
208
 
193
- if body['response']
209
+ if body.nil?
210
+ no_content_response
211
+ elsif body['response']
194
212
  success_response(body)
195
213
  elsif body['error']
196
214
  error_response(body)
@@ -220,6 +238,15 @@ module ActiveMerchant #:nodoc:
220
238
  )
221
239
  end
222
240
 
241
+ def no_content_response
242
+ Response.new(
243
+ true,
244
+ nil,
245
+ {},
246
+ test: test?
247
+ )
248
+ end
249
+
223
250
  def unparsable_response(raw_response)
224
251
  message = 'Invalid JSON response received from Pin Payments. Please contact support@pinpayments.com if you continue to receive this message.'
225
252
  message += " (The raw response returned by the API was #{raw_response.inspect})"
@@ -235,7 +262,7 @@ module ActiveMerchant #:nodoc:
235
262
  end
236
263
 
237
264
  def parse(body)
238
- JSON.parse(body)
265
+ JSON.parse(body) unless body.nil? || body.length == 0
239
266
  end
240
267
 
241
268
  def post_data(parameters = {})