activemerchant 1.120.0 → 1.125.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +227 -1
  3. data/README.md +1 -1
  4. data/lib/active_merchant/billing/check.rb +13 -19
  5. data/lib/active_merchant/billing/credit_card.rb +13 -0
  6. data/lib/active_merchant/billing/credit_card_formatting.rb +1 -0
  7. data/lib/active_merchant/billing/credit_card_methods.rb +24 -12
  8. data/lib/active_merchant/billing/gateway.rb +1 -1
  9. data/lib/active_merchant/billing/gateways/adyen.rb +81 -26
  10. data/lib/active_merchant/billing/gateways/authorize_net.rb +10 -8
  11. data/lib/active_merchant/billing/gateways/blue_pay.rb +29 -0
  12. data/lib/active_merchant/billing/gateways/blue_snap.rb +2 -2
  13. data/lib/active_merchant/billing/gateways/braintree_blue.rb +9 -5
  14. data/lib/active_merchant/billing/gateways/card_stream.rb +17 -13
  15. data/lib/active_merchant/billing/gateways/cashnet.rb +15 -5
  16. data/lib/active_merchant/billing/gateways/checkout_v2.rb +43 -4
  17. data/lib/active_merchant/billing/gateways/credorax.rb +2 -1
  18. data/lib/active_merchant/billing/gateways/cyber_source.rb +41 -6
  19. data/lib/active_merchant/billing/gateways/d_local.rb +12 -6
  20. data/lib/active_merchant/billing/gateways/decidir.rb +7 -1
  21. data/lib/active_merchant/billing/gateways/decidir_plus.rb +173 -0
  22. data/lib/active_merchant/billing/gateways/ebanx.rb +16 -1
  23. data/lib/active_merchant/billing/gateways/elavon.rb +65 -30
  24. data/lib/active_merchant/billing/gateways/element.rb +22 -2
  25. data/lib/active_merchant/billing/gateways/global_collect.rb +130 -26
  26. data/lib/active_merchant/billing/gateways/ipg.rb +416 -0
  27. data/lib/active_merchant/billing/gateways/kushki.rb +30 -0
  28. data/lib/active_merchant/billing/gateways/mercado_pago.rb +6 -3
  29. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +2 -0
  30. data/lib/active_merchant/billing/gateways/mit.rb +260 -0
  31. data/lib/active_merchant/billing/gateways/moka.rb +290 -0
  32. data/lib/active_merchant/billing/gateways/monei.rb +228 -144
  33. data/lib/active_merchant/billing/gateways/mundipagg.rb +22 -11
  34. data/lib/active_merchant/billing/gateways/nmi.rb +29 -10
  35. data/lib/active_merchant/billing/gateways/orbital.rb +55 -9
  36. data/lib/active_merchant/billing/gateways/pay_arc.rb +392 -0
  37. data/lib/active_merchant/billing/gateways/pay_conex.rb +3 -1
  38. data/lib/active_merchant/billing/gateways/pay_trace.rb +404 -0
  39. data/lib/active_merchant/billing/gateways/payeezy.rb +4 -0
  40. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -0
  41. data/lib/active_merchant/billing/gateways/payflow.rb +21 -4
  42. data/lib/active_merchant/billing/gateways/payment_express.rb +1 -1
  43. data/lib/active_merchant/billing/gateways/paymentez.rb +14 -2
  44. data/lib/active_merchant/billing/gateways/paypal_express.rb +1 -0
  45. data/lib/active_merchant/billing/gateways/paysafe.rb +412 -0
  46. data/lib/active_merchant/billing/gateways/payu_latam.rb +9 -4
  47. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +3 -3
  48. data/lib/active_merchant/billing/gateways/pin.rb +31 -4
  49. data/lib/active_merchant/billing/gateways/priority.rb +347 -0
  50. data/lib/active_merchant/billing/gateways/realex.rb +18 -0
  51. data/lib/active_merchant/billing/gateways/redsys.rb +35 -32
  52. data/lib/active_merchant/billing/gateways/safe_charge.rb +8 -2
  53. data/lib/active_merchant/billing/gateways/spreedly_core.rb +13 -4
  54. data/lib/active_merchant/billing/gateways/stripe.rb +27 -7
  55. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +115 -39
  56. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -1
  57. data/lib/active_merchant/billing/gateways/trust_commerce.rb +2 -1
  58. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +21 -7
  59. data/lib/active_merchant/billing/gateways/vpos.rb +58 -10
  60. data/lib/active_merchant/billing/gateways/wompi.rb +193 -0
  61. data/lib/active_merchant/billing/gateways/worldpay.rb +226 -62
  62. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  63. data/lib/active_merchant/billing/response.rb +4 -0
  64. data/lib/active_merchant/billing/three_d_secure_eci_mapper.rb +27 -0
  65. data/lib/active_merchant/billing.rb +1 -0
  66. data/lib/active_merchant/version.rb +1 -1
  67. metadata +13 -3
@@ -0,0 +1,412 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class PaysafeGateway < Gateway
4
+ self.test_url = 'https://api.test.paysafe.com'
5
+ self.live_url = 'https://api.paysafe.com'
6
+
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)
8
+ self.supported_cardtypes = %i[visa master american_express discover]
9
+
10
+ self.homepage_url = 'https://www.paysafe.com/'
11
+ self.display_name = 'Paysafe'
12
+
13
+ def initialize(options = {})
14
+ requires!(options, :username, :password, :account_id)
15
+ super
16
+ end
17
+
18
+ def purchase(money, payment, options = {})
19
+ post = {}
20
+ add_invoice(post, money, options)
21
+ add_payment(post, payment)
22
+ add_billing_address(post, options)
23
+ add_merchant_details(post, options)
24
+ add_airline_travel_details(post, options)
25
+ add_customer_data(post, payment, options) unless payment.is_a?(String)
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)
29
+ post[:settleWithAuth] = true
30
+
31
+ commit(:post, 'auths', post, options)
32
+ end
33
+
34
+ def authorize(money, payment, options = {})
35
+ post = {}
36
+ add_invoice(post, money, options)
37
+ add_payment(post, payment)
38
+ add_billing_address(post, options)
39
+ add_merchant_details(post, options)
40
+ add_customer_data(post, payment, options) unless payment.is_a?(String)
41
+ add_three_d_secure(post, payment, options) if options[:three_d_secure]
42
+ add_stored_credential(post, options) if options[:stored_credential]
43
+
44
+ commit(:post, 'auths', post, options)
45
+ end
46
+
47
+ def capture(money, authorization, options = {})
48
+ post = {}
49
+ add_invoice(post, money, options)
50
+
51
+ commit(:post, "auths/#{authorization}/settlements", post, options)
52
+ end
53
+
54
+ def refund(money, authorization, options = {})
55
+ post = {}
56
+ add_invoice(post, money, options)
57
+
58
+ commit(:post, "settlements/#{authorization}/refunds", post, options)
59
+ end
60
+
61
+ def void(authorization, options = {})
62
+ post = {}
63
+ money = options[:amount]
64
+ add_invoice(post, money, options)
65
+
66
+ commit(:post, "auths/#{authorization}/voidauths", post, options)
67
+ end
68
+
69
+ def credit(money, payment, options = {})
70
+ post = {}
71
+ add_invoice(post, money, options)
72
+ add_payment(post, payment)
73
+
74
+ commit(:post, 'standalonecredits', post, options)
75
+ end
76
+
77
+ # This is a '$0 auth' done at a specific verification endpoint at the gateway
78
+ def verify(payment, options = {})
79
+ post = {}
80
+ add_payment(post, payment)
81
+ add_billing_address(post, options)
82
+ add_customer_data(post, payment, options) unless payment.is_a?(String)
83
+
84
+ commit(:post, 'verifications', post, options)
85
+ end
86
+
87
+ def store(payment, options = {})
88
+ post = {}
89
+ add_payment(post, payment)
90
+ add_address_for_vaulting(post, options)
91
+ add_profile_data(post, payment, options)
92
+ add_store_data(post, payment, options)
93
+
94
+ commit(:post, 'profiles', post, options)
95
+ end
96
+
97
+ def unstore(pm_profile_id)
98
+ commit_for_unstore(:delete, "profiles/#{pm_profile_id}", nil, nil)
99
+ end
100
+
101
+ def supports_scrubbing?
102
+ true
103
+ end
104
+
105
+ def scrub(transcript)
106
+ transcript.
107
+ gsub(%r((Authorization: Basic )[a-zA-Z0-9:_]+), '\1[FILTERED]').
108
+ gsub(%r(("cardNum\\?":\\?")\d+), '\1[FILTERED]').
109
+ gsub(%r(("cvv\\?":\\?")\d+), '\1[FILTERED]')
110
+ end
111
+
112
+ private
113
+
114
+ # Customer data can be included in transactions where the payment method is a credit card
115
+ # but should not be sent when the payment method is a token
116
+ def add_customer_data(post, creditcard, options)
117
+ post[:profile] = {}
118
+ post[:profile][:firstName] = creditcard.first_name
119
+ post[:profile][:lastName] = creditcard.last_name
120
+ post[:profile][:email] = options[:email] if options[:email]
121
+ post[:customerIp] = options[:ip] if options[:ip]
122
+ end
123
+
124
+ def add_billing_address(post, options)
125
+ return unless address = options[:billing_address] || options[:address]
126
+
127
+ post[:billingDetails] = {}
128
+ post[:billingDetails][:street] = address[:address1]
129
+ post[:billingDetails][:city] = address[:city]
130
+ post[:billingDetails][:state] = address[:state]
131
+ post[:billingDetails][:country] = address[:country]
132
+ post[:billingDetails][:zip] = address[:zip]
133
+ post[:billingDetails][:phone] = address[:phone]
134
+ end
135
+
136
+ # The add_address_for_vaulting method is applicable to the store method, as the APIs address
137
+ # object is formatted differently from the standard transaction billing address
138
+ def add_address_for_vaulting(post, options)
139
+ return unless address = options[:billing_address] || options[:address]
140
+
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]
148
+ end
149
+
150
+ # This data is specific to creating a profile at the gateway's vault level
151
+ def add_profile_data(post, payment, options)
152
+ post[:firstName] = payment.first_name
153
+ post[:lastName] = payment.last_name
154
+ post[:dateOfBirth] = {}
155
+ post[:dateOfBirth][:year] = options[:date_of_birth][:year]
156
+ post[:dateOfBirth][:month] = options[:date_of_birth][:month]
157
+ post[:dateOfBirth][:day] = options[:date_of_birth][:day]
158
+ post[:email] = options[:email] if options[:email]
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
166
+ end
167
+
168
+ def add_store_data(post, payment, options)
169
+ post[:merchantCustomerId] = options[:customer_id] || SecureRandom.hex(12)
170
+ post[:locale] = options[:locale] || 'en_US'
171
+ post[:card][:holderName] = payment.name
172
+ end
173
+
174
+ # Paysafe expects minor units so we are not calling amount method on money parameter
175
+ def add_invoice(post, money, options)
176
+ post[:amount] = money
177
+ end
178
+
179
+ def add_payment(post, payment)
180
+ if payment.is_a?(String)
181
+ post[:card] = {}
182
+ post[:card][:paymentToken] = payment
183
+ else
184
+ post[:card] = { cardExpiry: {} }
185
+ post[:card][:cardNum] = payment.number
186
+ post[:card][:cardExpiry][:month] = payment.month
187
+ post[:card][:cardExpiry][:year] = payment.year
188
+ post[:card][:cvv] = payment.verification_value
189
+ end
190
+ end
191
+
192
+ def add_merchant_details(post, options)
193
+ return unless options[:merchant_descriptor]
194
+
195
+ post[:merchantDescriptor] = {}
196
+ post[:merchantDescriptor][:dynamicDescriptor] = options[:merchant_descriptor][:dynamic_descriptor] if options[:merchant_descriptor][:dynamic_descriptor]
197
+ post[:merchantDescriptor][:phone] = options[:merchant_descriptor][:phone] if options[:merchant_descriptor][:phone]
198
+ end
199
+
200
+ def add_three_d_secure(post, payment, options)
201
+ three_d_secure = options[:three_d_secure]
202
+
203
+ post[:authentication] = {}
204
+ post[:authentication][:eci] = three_d_secure[:eci]
205
+ post[:authentication][:cavv] = three_d_secure[:cavv]
206
+ post[:authentication][:xid] = three_d_secure[:xid] if three_d_secure[:xid]
207
+ post[:authentication][:threeDSecureVersion] = three_d_secure[:version]
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'
321
+ end
322
+
323
+ def parse(body)
324
+ JSON.parse(body)
325
+ end
326
+
327
+ def commit(method, action, parameters, options)
328
+ url = url(action)
329
+ raw_response = ssl_request(method, url, post_data(parameters, options), headers)
330
+ response = parse(raw_response)
331
+ success = success_from(response)
332
+
333
+ Response.new(
334
+ success,
335
+ message_from(success, response),
336
+ response,
337
+ authorization: authorization_from(action, response),
338
+ avs_result: AVSResult.new(code: response['avsResponse']),
339
+ cvv_result: CVVResult.new(response['cvvVerification']),
340
+ test: test?,
341
+ error_code: success ? nil : error_code_from(response)
342
+ )
343
+ end
344
+
345
+ def commit_for_unstore(method, action, parameters, options)
346
+ url = url(action)
347
+ response = raw_ssl_request(method, url, post_data(parameters, options), headers)
348
+ success = true if response.code == '200'
349
+
350
+ Response.new(
351
+ success,
352
+ message: response.message
353
+ )
354
+ end
355
+
356
+ def headers
357
+ {
358
+ 'Content-Type' => 'application/json',
359
+ 'Authorization' => 'Basic ' + Base64.strict_encode64("#{@options[:username]}:#{@options[:password]}")
360
+ }
361
+ end
362
+
363
+ def url(action, options = {})
364
+ base_url = (test? ? test_url : live_url)
365
+
366
+ if action.include? 'profiles'
367
+ "#{base_url}/customervault/v1/#{action}"
368
+ else
369
+ "#{base_url}/cardpayments/v1/accounts/#{@options[:account_id]}/#{action}"
370
+ end
371
+ end
372
+
373
+ def success_from(response)
374
+ return false if response['status'] == 'FAILED' || response['error']
375
+
376
+ true
377
+ end
378
+
379
+ def message_from(success, response)
380
+ return response['status'] unless response['error']
381
+
382
+ "Error(s)- code:#{response['error']['code']}, message:#{response['error']['message']}"
383
+ end
384
+
385
+ def authorization_from(action, response)
386
+ if action == 'profiles'
387
+ response['cards'].first['paymentToken']
388
+ else
389
+ response['id']
390
+ end
391
+ end
392
+
393
+ def post_data(parameters = {}, options = {})
394
+ return unless parameters.present?
395
+
396
+ parameters[:merchantRefNum] = options[:merchant_ref_num] || SecureRandom.hex(16).to_s
397
+
398
+ parameters.to_json
399
+ end
400
+
401
+ def error_code_from(response)
402
+ return unless response['error']
403
+
404
+ response['error']['code']
405
+ end
406
+
407
+ def handle_response(response)
408
+ response.body
409
+ end
410
+ end
411
+ end
412
+ end
@@ -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',
@@ -208,7 +209,7 @@ module ActiveMerchant #:nodoc:
208
209
  buyer[:merchantBuyerId] = buyer_hash[:merchant_buyer_id]
209
210
  buyer[:cnpj] = buyer_hash[:cnpj] if @options[:payment_country] == 'BR'
210
211
  buyer[:emailAddress] = buyer_hash[:email]
211
- buyer[:contactPhone] = (options[:billing_address][:phone] if options[:billing_address]) || (options[:shipping_address][:phone] if options[:shipping_address]) || ''
212
+ buyer[:contactPhone] = (options[:billing_address][:phone] if options[:billing_address]) || (options[:shipping_address][:phone_number] if options[:shipping_address]) || ''
212
213
  buyer[:shippingAddress] = shipping_address_fields(options) if options[:shipping_address]
213
214
  else
214
215
  buyer[:fullName] = payment_method.name.strip
@@ -217,7 +218,7 @@ module ActiveMerchant #:nodoc:
217
218
  buyer[:merchantBuyerId] = options[:merchant_buyer_id]
218
219
  buyer[:cnpj] = options[:cnpj] if @options[:payment_country] == 'BR'
219
220
  buyer[:emailAddress] = options[:email]
220
- buyer[:contactPhone] = (options[:billing_address][:phone] if options[:billing_address]) || (options[:shipping_address][:phone] if options[:shipping_address]) || ''
221
+ buyer[:contactPhone] = (options[:billing_address][:phone] if options[:billing_address]) || (options[:shipping_address][:phone_number] if options[:shipping_address]) || ''
221
222
  buyer[:shippingAddress] = shipping_address_fields(options) if options[:shipping_address]
222
223
  end
223
224
  post[:transaction][:order][:buyer] = buyer
@@ -233,7 +234,7 @@ module ActiveMerchant #:nodoc:
233
234
  shipping_address[:state] = address[:state]
234
235
  shipping_address[:country] = address[:country]
235
236
  shipping_address[:postalCode] = address[:zip]
236
- shipping_address[:phone] = address[:phone]
237
+ shipping_address[:phone] = address[:phone_number]
237
238
  shipping_address
238
239
  end
239
240
 
@@ -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 = {})