activemerchant 1.121.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +217 -0
  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 +75 -27
  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 +6 -3
  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 +33 -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 +46 -8
  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 +2 -2
  43. data/lib/active_merchant/billing/gateways/paymentez.rb +14 -2
  44. data/lib/active_merchant/billing/gateways/paysafe.rb +412 -0
  45. data/lib/active_merchant/billing/gateways/payu_latam.rb +9 -4
  46. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +3 -3
  47. data/lib/active_merchant/billing/gateways/pin.rb +31 -4
  48. data/lib/active_merchant/billing/gateways/priority.rb +347 -0
  49. data/lib/active_merchant/billing/gateways/realex.rb +18 -0
  50. data/lib/active_merchant/billing/gateways/redsys.rb +35 -32
  51. data/lib/active_merchant/billing/gateways/safe_charge.rb +8 -2
  52. data/lib/active_merchant/billing/gateways/spreedly_core.rb +13 -4
  53. data/lib/active_merchant/billing/gateways/stripe.rb +27 -7
  54. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +115 -39
  55. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +2 -1
  56. data/lib/active_merchant/billing/gateways/trust_commerce.rb +2 -1
  57. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +21 -7
  58. data/lib/active_merchant/billing/gateways/vpos.rb +49 -6
  59. data/lib/active_merchant/billing/gateways/wompi.rb +193 -0
  60. data/lib/active_merchant/billing/gateways/worldpay.rb +226 -62
  61. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +1 -1
  62. data/lib/active_merchant/billing/response.rb +4 -0
  63. data/lib/active_merchant/billing/three_d_secure_eci_mapper.rb +27 -0
  64. data/lib/active_merchant/billing.rb +1 -0
  65. data/lib/active_merchant/version.rb +1 -1
  66. 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 = {})