activemerchant 1.119.0 → 1.124.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +216 -1
  3. data/README.md +4 -2
  4. data/lib/active_merchant/billing/check.rb +19 -12
  5. data/lib/active_merchant/billing/credit_card.rb +3 -0
  6. data/lib/active_merchant/billing/credit_card_formatting.rb +1 -0
  7. data/lib/active_merchant/billing/credit_card_methods.rb +32 -14
  8. data/lib/active_merchant/billing/gateways/adyen.rb +94 -25
  9. data/lib/active_merchant/billing/gateways/authorize_net.rb +19 -11
  10. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +3 -0
  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 +52 -8
  14. data/lib/active_merchant/billing/gateways/card_stream.rb +17 -13
  15. data/lib/active_merchant/billing/gateways/cashnet.rb +7 -2
  16. data/lib/active_merchant/billing/gateways/checkout_v2.rb +31 -0
  17. data/lib/active_merchant/billing/gateways/credorax.rb +15 -9
  18. data/lib/active_merchant/billing/gateways/cyber_source.rb +53 -6
  19. data/lib/active_merchant/billing/gateways/d_local.rb +9 -2
  20. data/lib/active_merchant/billing/gateways/decidir.rb +7 -1
  21. data/lib/active_merchant/billing/gateways/elavon.rb +70 -28
  22. data/lib/active_merchant/billing/gateways/element.rb +2 -0
  23. data/lib/active_merchant/billing/gateways/forte.rb +12 -0
  24. data/lib/active_merchant/billing/gateways/global_collect.rb +24 -10
  25. data/lib/active_merchant/billing/gateways/hps.rb +55 -1
  26. data/lib/active_merchant/billing/gateways/kushki.rb +23 -0
  27. data/lib/active_merchant/billing/gateways/litle.rb +1 -1
  28. data/lib/active_merchant/billing/gateways/mercado_pago.rb +5 -4
  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 +14 -5
  34. data/lib/active_merchant/billing/gateways/netbanx.rb +26 -2
  35. data/lib/active_merchant/billing/gateways/nmi.rb +27 -9
  36. data/lib/active_merchant/billing/gateways/orbital.rb +99 -59
  37. data/lib/active_merchant/billing/gateways/pay_arc.rb +392 -0
  38. data/lib/active_merchant/billing/gateways/pay_conex.rb +3 -1
  39. data/lib/active_merchant/billing/gateways/pay_trace.rb +404 -0
  40. data/lib/active_merchant/billing/gateways/payeezy.rb +34 -6
  41. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +1 -0
  42. data/lib/active_merchant/billing/gateways/payflow.rb +21 -4
  43. data/lib/active_merchant/billing/gateways/payment_express.rb +5 -5
  44. data/lib/active_merchant/billing/gateways/paymentez.rb +5 -0
  45. data/lib/active_merchant/billing/gateways/paypal_express.rb +1 -0
  46. data/lib/active_merchant/billing/gateways/paysafe.rb +376 -0
  47. data/lib/active_merchant/billing/gateways/payu_latam.rb +3 -3
  48. data/lib/active_merchant/billing/gateways/payway_dot_com.rb +253 -0
  49. data/lib/active_merchant/billing/gateways/qvalent.rb +23 -9
  50. data/lib/active_merchant/billing/gateways/realex.rb +18 -0
  51. data/lib/active_merchant/billing/gateways/redsys.rb +42 -24
  52. data/lib/active_merchant/billing/gateways/safe_charge.rb +25 -13
  53. data/lib/active_merchant/billing/gateways/spreedly_core.rb +13 -4
  54. data/lib/active_merchant/billing/gateways/stripe.rb +18 -8
  55. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +126 -48
  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 +1 -1
  59. data/lib/active_merchant/billing/gateways/vpos.rb +220 -0
  60. data/lib/active_merchant/billing/gateways/worldpay.rb +78 -18
  61. data/lib/active_merchant/billing/response.rb +4 -0
  62. data/lib/active_merchant/billing/three_d_secure_eci_mapper.rb +27 -0
  63. data/lib/active_merchant/billing.rb +1 -0
  64. data/lib/active_merchant/version.rb +1 -1
  65. data/lib/certs/cacert.pem +1582 -2431
  66. metadata +11 -3
@@ -5,39 +5,36 @@ module ActiveMerchant #:nodoc:
5
5
  #
6
6
  # == Monei gateway
7
7
  # This class implements Monei gateway for Active Merchant. For more information about Monei
8
- # gateway please go to http://www.monei.net
8
+ # gateway please go to http://www.monei.com
9
9
  #
10
10
  # === Setup
11
- # In order to set-up the gateway you need four paramaters: sender_id, channel_id, login and pwd.
11
+ # In order to set-up the gateway you need only one paramater: the api_key
12
12
  # Request that data to Monei.
13
13
  class MoneiGateway < Gateway
14
- self.test_url = 'https://test.monei-api.net/payment/ctpe'
15
- self.live_url = 'https://monei-api.net/payment/ctpe'
14
+ self.live_url = self.test_url = 'https://api.monei.com/v1/payments'
16
15
 
17
16
  self.supported_countries = %w[AD AT BE BG CA CH CY CZ DE DK EE ES FI FO FR GB GI GR HU IE IL IS IT LI LT LU LV MT NL NO PL PT RO SE SI SK TR US VA]
18
17
  self.default_currency = 'EUR'
18
+ self.money_format = :cents
19
19
  self.supported_cardtypes = %i[visa master maestro jcb american_express]
20
20
 
21
- self.homepage_url = 'http://www.monei.net/'
22
- self.display_name = 'Monei'
21
+ self.homepage_url = 'https://monei.com/'
22
+ self.display_name = 'MONEI'
23
23
 
24
24
  # Constructor
25
25
  #
26
26
  # options - Hash containing the gateway credentials, ALL MANDATORY
27
- # :sender_id Sender ID
28
- # :channel_id Channel ID
29
- # :login User login
30
- # :pwd User password
27
+ # :api_key Account's API KEY
31
28
  #
32
29
  def initialize(options = {})
33
- requires!(options, :sender_id, :channel_id, :login, :pwd)
30
+ requires!(options, :api_key)
34
31
  super
35
32
  end
36
33
 
37
34
  # Public: Performs purchase operation
38
35
  #
39
36
  # money - Amount of purchase
40
- # credit_card - Credit card
37
+ # payment_method - Credit card
41
38
  # options - Hash containing purchase options
42
39
  # :order_id Merchant created id for the purchase
43
40
  # :billing_address Hash with billing address information
@@ -45,14 +42,14 @@ module ActiveMerchant #:nodoc:
45
42
  # :currency Sale currency to override money object or default (optional)
46
43
  #
47
44
  # Returns Active Merchant response object
48
- def purchase(money, credit_card, options = {})
49
- execute_new_order(:purchase, money, credit_card, options)
45
+ def purchase(money, payment_method, options = {})
46
+ execute_new_order(:purchase, money, payment_method, options)
50
47
  end
51
48
 
52
49
  # Public: Performs authorization operation
53
50
  #
54
51
  # money - Amount to authorize
55
- # credit_card - Credit card
52
+ # payment_method - Credit card
56
53
  # options - Hash containing authorization options
57
54
  # :order_id Merchant created id for the authorization
58
55
  # :billing_address Hash with billing address information
@@ -60,8 +57,8 @@ module ActiveMerchant #:nodoc:
60
57
  # :currency Sale currency to override money object or default (optional)
61
58
  #
62
59
  # Returns Active Merchant response object
63
- def authorize(money, credit_card, options = {})
64
- execute_new_order(:authorize, money, credit_card, options)
60
+ def authorize(money, payment_method, options = {})
61
+ execute_new_order(:authorize, money, payment_method, options)
65
62
  end
66
63
 
67
64
  # Public: Performs capture operation on previous authorization
@@ -109,7 +106,7 @@ module ActiveMerchant #:nodoc:
109
106
 
110
107
  # Public: Verifies credit card. Does this by doing a authorization of 1.00 Euro and then voiding it.
111
108
  #
112
- # credit_card - Credit card
109
+ # payment_method - Credit card
113
110
  # options - Hash containing authorization options
114
111
  # :order_id Merchant created id for the authorization
115
112
  # :billing_address Hash with billing address information
@@ -117,113 +114,122 @@ module ActiveMerchant #:nodoc:
117
114
  # :currency Sale currency to override money object or default (optional)
118
115
  #
119
116
  # Returns Active Merchant response object of Authorization operation
120
- def verify(credit_card, options = {})
117
+ def verify(payment_method, options = {})
121
118
  MultiResponse.run(:use_first_response) do |r|
122
- r.process { authorize(100, credit_card, options) }
119
+ r.process { authorize(100, payment_method, options) }
123
120
  r.process(:ignore_result) { void(r.authorization, options) }
124
121
  end
125
122
  end
126
123
 
124
+ def store(payment_method, options = {})
125
+ execute_new_order(:store, 0, payment_method, options)
126
+ end
127
+
128
+ def supports_scrubbing?
129
+ true
130
+ end
131
+
132
+ def scrub(transcript)
133
+ transcript.
134
+ gsub(%r((Authorization: )\w+), '\1[FILTERED]').
135
+ gsub(%r(("number\\?":\\?")[^"]*)i, '\1[FILTERED]').
136
+ gsub(%r(("cvc\\?":\\?")[^"]*)i, '\1[FILTERED]').
137
+ gsub(%r(("cavv\\?":\\?")[^"]*)i, '\1[FILTERED]')
138
+ end
139
+
127
140
  private
128
141
 
129
142
  # Private: Execute purchase or authorize operation
130
- def execute_new_order(action, money, credit_card, options)
131
- request = build_request do |xml|
132
- add_identification_new_order(xml, options)
133
- add_payment(xml, action, money, options)
134
- add_account(xml, credit_card)
135
- add_customer(xml, credit_card, options)
136
- add_three_d_secure(xml, options)
137
- end
138
-
139
- commit(request)
143
+ def execute_new_order(action, money, payment_method, options)
144
+ request = build_request
145
+ add_identification_new_order(request, options)
146
+ add_transaction(request, action, money, options)
147
+ add_payment(request, payment_method)
148
+ add_customer(request, payment_method, options)
149
+ add_3ds_authenticated_data(request, options)
150
+ add_browser_info(request, options)
151
+ commit(request, action, options)
140
152
  end
141
153
 
142
154
  # Private: Execute operation that depends on authorization code from previous purchase or authorize operation
143
155
  def execute_dependant(action, money, authorization, options)
144
- request = build_request do |xml|
145
- add_identification_authorization(xml, authorization, options)
146
- add_payment(xml, action, money, options)
147
- end
156
+ request = build_request
148
157
 
149
- commit(request)
158
+ add_identification_authorization(request, authorization, options)
159
+ add_transaction(request, action, money, options)
160
+
161
+ commit(request, action, options)
150
162
  end
151
163
 
152
- # Private: Build XML wrapping code yielding to code to fill the transaction information
164
+ # Private: Build request object
153
165
  def build_request
154
- builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
155
- xml.Request(version: '1.0') do
156
- xml.Header { xml.Security(sender: @options[:sender_id]) }
157
- xml.Transaction(mode: test? ? 'CONNECTOR_TEST' : 'LIVE', response: 'SYNC', channel: @options[:channel_id]) do
158
- xml.User(login: @options[:login], pwd: @options[:pwd])
159
- yield xml
160
- end
161
- end
162
- end
163
- builder.to_xml
166
+ request = {}
167
+ request[:livemode] = test? ? 'false' : 'true'
168
+ request
164
169
  end
165
170
 
166
- # Private: Add identification part to XML for new orders
167
- def add_identification_new_order(xml, options)
171
+ # Private: Add identification part to request for new orders
172
+ def add_identification_new_order(request, options)
168
173
  requires!(options, :order_id)
169
- xml.Identification do
170
- xml.TransactionID options[:order_id]
171
- end
174
+ request[:orderId] = options[:order_id]
172
175
  end
173
176
 
174
- # Private: Add identification part to XML for orders that depend on authorization from previous operation
175
- def add_identification_authorization(xml, authorization, options)
176
- xml.Identification do
177
- xml.ReferenceID authorization
178
- xml.TransactionID options[:order_id]
179
- end
177
+ # Private: Add identification part to request for orders that depend on authorization from previous operation
178
+ def add_identification_authorization(request, authorization, options)
179
+ options[:paymentId] = authorization
180
+ request[:orderId] = options[:order_id] if options[:order_id]
180
181
  end
181
182
 
182
- # Private: Add payment part to XML
183
- def add_payment(xml, action, money, options)
184
- code = tanslate_payment_code(action)
185
-
186
- xml.Payment(code: code) do
187
- xml.Presentation do
188
- xml.Amount amount(money)
189
- xml.Currency options[:currency] || currency(money)
190
- xml.Usage options[:description] || options[:order_id]
191
- end unless money.nil?
183
+ # Private: Add payment part to request
184
+ def add_transaction(request, action, money, options)
185
+ request[:transactionType] = translate_payment_code(action)
186
+ request[:description] = options[:description] || options[:order_id]
187
+ unless money.nil?
188
+ request[:amount] = amount(money).to_i
189
+ request[:currency] = options[:currency] || currency(money)
192
190
  end
193
191
  end
194
192
 
195
- # Private: Add account part to XML
196
- def add_account(xml, credit_card)
197
- xml.Account do
198
- xml.Holder credit_card.name
199
- xml.Number credit_card.number
200
- xml.Brand credit_card.brand.upcase
201
- xml.Expiry(month: credit_card.month, year: credit_card.year)
202
- xml.Verification credit_card.verification_value
193
+ # Private: Add payment method to request
194
+ def add_payment(request, payment_method)
195
+ if payment_method.is_a? String
196
+ request[:paymentToken] = payment_method
197
+ else
198
+ request[:paymentMethod] = {}
199
+ request[:paymentMethod][:card] = {}
200
+ request[:paymentMethod][:card][:number] = payment_method.number
201
+ request[:paymentMethod][:card][:expMonth] = format(payment_method.month, :two_digits)
202
+ request[:paymentMethod][:card][:expYear] = format(payment_method.year, :two_digits)
203
+ request[:paymentMethod][:card][:cvc] = payment_method.verification_value.to_s
203
204
  end
204
205
  end
205
206
 
206
- # Private: Add customer part to XML
207
- def add_customer(xml, credit_card, options)
208
- requires!(options, :billing_address)
209
- address = options[:billing_address]
210
- xml.Customer do
211
- xml.Name do
212
- xml.Given credit_card.first_name
213
- xml.Family credit_card.last_name
214
- end
215
- xml.Address do
216
- xml.Street address[:address1].to_s
217
- xml.Zip address[:zip].to_s
218
- xml.City address[:city].to_s
219
- xml.State address[:state].to_s if address.has_key? :state
220
- xml.Country address[:country].to_s
221
- end
222
- xml.Contact do
223
- xml.Email options[:email] || 'noemail@monei.net'
224
- xml.Ip options[:ip] || '0.0.0.0'
225
- end
207
+ # Private: Add customer part to request
208
+ def add_customer(request, payment_method, options)
209
+ address = options[:billing_address] || options[:address]
210
+
211
+ request[:customer] = {}
212
+ request[:customer][:email] = options[:email] || 'support@monei.net'
213
+
214
+ if address
215
+ request[:customer][:name] = address[:name].to_s if address[:name]
216
+
217
+ request[:billingDetails] = {}
218
+ request[:billingDetails][:email] = options[:email] if options[:email]
219
+ request[:billingDetails][:name] = address[:name] if address[:name]
220
+ request[:billingDetails][:company] = address[:company] if address[:company]
221
+ request[:billingDetails][:phone] = address[:phone] if address[:phone]
222
+ request[:billingDetails][:address] = {}
223
+ request[:billingDetails][:address][:line1] = address[:address1] if address[:address1]
224
+ request[:billingDetails][:address][:line2] = address[:address2] if address[:address2]
225
+ request[:billingDetails][:address][:city] = address[:city] if address[:city]
226
+ request[:billingDetails][:address][:state] = address[:state] if address[:state].present?
227
+ request[:billingDetails][:address][:zip] = address[:zip].to_s if address[:zip]
228
+ request[:billingDetails][:address][:country] = address[:country] if address[:country]
226
229
  end
230
+
231
+ request[:sessionDetails] = {}
232
+ request[:sessionDetails][:ip] = options[:ip] if options[:ip]
227
233
  end
228
234
 
229
235
  # Private : Convert ECI to ResultIndicator
@@ -245,92 +251,170 @@ module ActiveMerchant #:nodoc:
245
251
  end
246
252
  end
247
253
 
248
- # Private : Add the 3DSecure infos to XML
249
- def add_three_d_secure(xml, options)
250
- if options[:three_d_secure]
251
- xml.Authentication(type: '3DSecure') do
252
- xml.ResultIndicator eci_to_result_indicator options[:three_d_secure][:eci]
253
- xml.Parameter(name: 'VERIFICATION_ID') { xml.text options[:three_d_secure][:cavv] }
254
- xml.Parameter(name: 'XID') { xml.text options[:three_d_secure][:xid] }
255
- end
254
+ # Private: add the already validated 3DSecure info to request
255
+ def add_3ds_authenticated_data(request, options)
256
+ if options[:three_d_secure] && options[:three_d_secure][:eci] && options[:three_d_secure][:xid]
257
+ add_3ds1_authenticated_data(request, options)
258
+ elsif options[:three_d_secure]
259
+ add_3ds2_authenticated_data(request, options)
256
260
  end
257
261
  end
258
262
 
259
- # Private: Parse XML response from Monei servers
263
+ def add_3ds1_authenticated_data(request, options)
264
+ three_d_secure_options = options[:three_d_secure]
265
+ request[:paymentMethod][:card][:auth] = {
266
+ cavv: three_d_secure_options[:cavv],
267
+ cavvAlgorithm: three_d_secure_options[:cavv_algorithm],
268
+ eci: three_d_secure_options[:eci],
269
+ xid: three_d_secure_options[:xid],
270
+ directoryResponse: three_d_secure_options[:enrolled],
271
+ authenticationResponse: three_d_secure_options[:authentication_response_status]
272
+ }
273
+ end
274
+
275
+ def add_3ds2_authenticated_data(request, options)
276
+ three_d_secure_options = options[:three_d_secure]
277
+ # If the transaction was authenticated in a frictionless flow, send the transStatus from the ARes.
278
+ if three_d_secure_options[:authentication_response_status].nil?
279
+ authentication_response = three_d_secure_options[:directory_response_status]
280
+ else
281
+ authentication_response = three_d_secure_options[:authentication_response_status]
282
+ end
283
+ request[:paymentMethod][:card][:auth] = {
284
+ threeDSVersion: three_d_secure_options[:version],
285
+ eci: three_d_secure_options[:eci],
286
+ cavv: three_d_secure_options[:cavv],
287
+ dsTransID: three_d_secure_options[:ds_transaction_id],
288
+ directoryResponse: three_d_secure_options[:directory_response_status],
289
+ authenticationResponse: authentication_response
290
+ }
291
+ end
292
+
293
+ def add_browser_info(request, options)
294
+ request[:sessionDetails][:ip] = options[:ip] if options[:ip]
295
+ request[:sessionDetails][:userAgent] = options[:user_agent] if options[:user_agent]
296
+ end
297
+
298
+ # Private: Parse JSON response from Monei servers
260
299
  def parse(body)
261
- xml = Nokogiri::XML(body)
300
+ JSON.parse(body)
301
+ end
302
+
303
+ def json_error(raw_response)
304
+ msg = 'Invalid response received from the MONEI API. Please contact support@monei.net if you continue to receive this message.'
305
+ msg += " (The raw response returned by the API was #{raw_response.inspect})"
262
306
  {
263
- unique_id: xml.xpath('//Response/Transaction/Identification/UniqueID').text,
264
- status: translate_status_code(xml.xpath('//Response/Transaction/Processing/Status/@code').text),
265
- reason: translate_status_code(xml.xpath('//Response/Transaction/Processing/Reason/@code').text),
266
- message: xml.xpath('//Response/Transaction/Processing/Return').text
307
+ 'status' => 'error',
308
+ 'message' => msg
267
309
  }
268
310
  end
269
311
 
270
- # Private: Send XML transaction to Monei servers and create AM response
271
- def commit(xml)
312
+ def response_error(raw_response)
313
+ parse(raw_response)
314
+ rescue JSON::ParserError
315
+ json_error(raw_response)
316
+ end
317
+
318
+ def api_request(url, parameters, options = {})
319
+ raw_response = response = nil
320
+ begin
321
+ raw_response = ssl_post(url, post_data(parameters), options)
322
+ response = parse(raw_response)
323
+ rescue ResponseError => e
324
+ raw_response = e.response.body
325
+ response = response_error(raw_response)
326
+ rescue JSON::ParserError
327
+ response = json_error(raw_response)
328
+ end
329
+ response
330
+ end
331
+
332
+ # Private: Send transaction to Monei servers and create AM response
333
+ def commit(request, action, options)
272
334
  url = (test? ? test_url : live_url)
335
+ endpoint = translate_action_endpoint(action, options)
336
+ headers = {
337
+ 'Content-Type': 'application/json;charset=UTF-8',
338
+ 'Authorization': @options[:api_key],
339
+ 'User-Agent': 'MONEI/Shopify/0.1.0'
340
+ }
273
341
 
274
- response = parse(ssl_post(url, post_data(xml), 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'))
342
+ response = api_request(url + endpoint, params(request, action), headers)
343
+ success = success_from(response)
275
344
 
276
345
  Response.new(
277
- success_from(response),
278
- message_from(response),
346
+ success,
347
+ message_from(response, success),
279
348
  response,
280
- authorization: authorization_from(response),
349
+ authorization: authorization_from(response, action),
281
350
  test: test?,
282
- error_code: error_code_from(response)
351
+ error_code: error_code_from(response, success)
283
352
  )
284
353
  end
285
354
 
286
355
  # Private: Decide success from servers response
287
356
  def success_from(response)
288
- response[:status] == :success || response[:status] == :new
357
+ %w[
358
+ SUCCEEDED
359
+ AUTHORIZED
360
+ REFUNDED
361
+ PARTIALLY_REFUNDED
362
+ CANCELED
363
+ ].include? response['status']
289
364
  end
290
365
 
291
366
  # Private: Get message from servers response
292
- def message_from(response)
293
- response[:message]
367
+ def message_from(response, success)
368
+ success ? 'Transaction approved' : response.fetch('statusMessage', response.fetch('message', 'No error details'))
294
369
  end
295
370
 
296
371
  # Private: Get error code from servers response
297
- def error_code_from(response)
298
- success_from(response) ? nil : STANDARD_ERROR_CODE[:card_declined]
372
+ def error_code_from(response, success)
373
+ success ? nil : STANDARD_ERROR_CODE[:card_declined]
299
374
  end
300
375
 
301
376
  # Private: Get authorization code from servers response
302
- def authorization_from(response)
303
- response[:unique_id]
377
+ def authorization_from(response, action)
378
+ case action
379
+ when :store
380
+ return response['paymentToken']
381
+ else
382
+ return response['id']
383
+ end
304
384
  end
305
385
 
306
386
  # Private: Encode POST parameters
307
- def post_data(xml)
308
- "load=#{CGI.escape(xml)}"
387
+ def post_data(params)
388
+ params.clone.to_json
309
389
  end
310
390
 
311
- # Private: Translate Monei status code to native ruby symbols
312
- def translate_status_code(code)
313
- {
314
- '00' => :success,
315
- '40' => :neutral,
316
- '59' => :waiting_bank,
317
- '60' => :rejected_bank,
318
- '64' => :waiting_risk,
319
- '65' => :rejected_risk,
320
- '70' => :rejected_validation,
321
- '80' => :waiting,
322
- '90' => :new
323
- }[code]
391
+ # Private: generate request params depending on action
392
+ def params(request, action)
393
+ request[:generatePaymentToken] = true if action == :store
394
+ request
324
395
  end
325
396
 
326
397
  # Private: Translate AM operations to Monei operations codes
327
- def tanslate_payment_code(action)
398
+ def translate_payment_code(action)
399
+ {
400
+ purchase: 'SALE',
401
+ store: 'SALE',
402
+ authorize: 'AUTH',
403
+ capture: 'CAPTURE',
404
+ refund: 'REFUND',
405
+ void: 'CANCEL'
406
+ }[action]
407
+ end
408
+
409
+ # Private: Translate AM operations to Monei endpoints
410
+ def translate_action_endpoint(action, options)
328
411
  {
329
- purchase: 'CC.DB',
330
- authorize: 'CC.PA',
331
- capture: 'CC.CP',
332
- refund: 'CC.RF',
333
- void: 'CC.RV'
412
+ purchase: '',
413
+ store: '',
414
+ authorize: '',
415
+ capture: "/#{options[:paymentId]}/capture",
416
+ refund: "/#{options[:paymentId]}/refund",
417
+ void: "/#{options[:paymentId]}/cancel"
334
418
  }[action]
335
419
  end
336
420
  end
@@ -40,7 +40,7 @@ module ActiveMerchant #:nodoc:
40
40
  add_shipping_address(post, options)
41
41
  add_payment(post, payment, options)
42
42
  add_submerchant(post, options)
43
-
43
+ add_auth_key(post, options)
44
44
  commit('sale', post)
45
45
  end
46
46
 
@@ -52,6 +52,7 @@ module ActiveMerchant #:nodoc:
52
52
  add_payment(post, payment, options)
53
53
  add_capture_flag(post, payment)
54
54
  add_submerchant(post, options)
55
+ add_auth_key(post, options)
55
56
  commit('authonly', post)
56
57
  end
57
58
 
@@ -229,9 +230,16 @@ module ActiveMerchant #:nodoc:
229
230
  end
230
231
  end
231
232
 
232
- def headers
233
+ def add_auth_key(post, options)
234
+ if authorization_secret_key = options[:authorization_secret_key]
235
+ post[:authorization_secret_key] = authorization_secret_key
236
+ end
237
+ end
238
+
239
+ def headers(authorization_secret_key = nil)
240
+ basic_token = authorization_secret_key || @options[:api_key]
233
241
  {
234
- 'Authorization' => 'Basic ' + Base64.strict_encode64("#{@options[:api_key]}:"),
242
+ 'Authorization' => 'Basic ' + Base64.strict_encode64("#{basic_token}:"),
235
243
  'Content-Type' => 'application/json',
236
244
  'Accept' => 'application/json'
237
245
  }
@@ -259,11 +267,12 @@ module ActiveMerchant #:nodoc:
259
267
 
260
268
  def commit(action, parameters, auth = nil)
261
269
  url = url_for(action, auth)
270
+ authorization_secret_key = parameters[:authorization_secret_key] if parameters
262
271
  parameters.merge!(parameters[:payment][:credit_card].delete(:card)).delete(:payment) if action == 'store'
263
272
  response = if %w[refund void].include? action
264
- parse(ssl_request(:delete, url, post_data(parameters), headers))
273
+ parse(ssl_request(:delete, url, post_data(parameters), headers(authorization_secret_key)))
265
274
  else
266
- parse(ssl_post(url, post_data(parameters), headers))
275
+ parse(ssl_post(url, post_data(parameters), headers(authorization_secret_key)))
267
276
  end
268
277
 
269
278
  Response.new(
@@ -22,6 +22,22 @@ module ActiveMerchant #:nodoc:
22
22
  self.homepage_url = 'https://processing.paysafe.com/'
23
23
  self.display_name = 'Netbanx by PaySafe'
24
24
 
25
+ AVS_CODE_CONVERTER = {
26
+ 'MATCH' => 'X',
27
+ 'MATCH_ADDRESS_ONLY' => 'A',
28
+ 'MATCH_ZIP_ONLY' => 'Z',
29
+ 'NO_MATCH' => 'N',
30
+ 'NOT_PROCESSED' => 'U',
31
+ 'UNKNOWN' => 'Q'
32
+ }
33
+
34
+ CVV_CODE_CONVERTER = {
35
+ 'MATCH' => 'M',
36
+ 'NO_MATCH' => 'N',
37
+ 'NOT_PROCESSED' => 'P',
38
+ 'UNKNOWN' => 'U'
39
+ }
40
+
25
41
  def initialize(options = {})
26
42
  requires!(options, :account_number, :api_key)
27
43
  super
@@ -256,11 +272,19 @@ module ActiveMerchant #:nodoc:
256
272
  test: test?,
257
273
  error_code: error_code_from(response),
258
274
  authorization: authorization_from(success, get_url(uri), method, response),
259
- avs_result: AVSResult.new(code: response['avsResponse']),
260
- cvv_result: CVVResult.new(response['cvvVerification'])
275
+ avs_result: avs_result(response),
276
+ cvv_result: cvv_result(response)
261
277
  )
262
278
  end
263
279
 
280
+ def avs_result(response)
281
+ AVSResult.new(code: AVS_CODE_CONVERTER[response['avsResponse']])
282
+ end
283
+
284
+ def cvv_result(response)
285
+ CVVResult.new(CVV_CODE_CONVERTER[response['cvvVerification']])
286
+ end
287
+
264
288
  def get_url(uri)
265
289
  url = (test? ? test_url : live_url)
266
290
  if /^customervault/.match?(uri)
@@ -236,6 +236,19 @@ module ActiveMerchant #:nodoc:
236
236
  post[:shipping_zip] = shipping_address[:zip]
237
237
  post[:shipping_phone] = shipping_address[:phone]
238
238
  end
239
+
240
+ if (descriptor = options[:descriptors])
241
+ post[:descriptor] = descriptor[:descriptor]
242
+ post[:descriptor_phone] = descriptor[:descriptor_phone]
243
+ post[:descriptor_address] = descriptor[:descriptor_address]
244
+ post[:descriptor_city] = descriptor[:descriptor_city]
245
+ post[:descriptor_state] = descriptor[:descriptor_state]
246
+ post[:descriptor_postal] = descriptor[:descriptor_postal]
247
+ post[:descriptor_country] = descriptor[:descriptor_country]
248
+ post[:descriptor_mcc] = descriptor[:descriptor_mcc]
249
+ post[:descriptor_merchant_id] = descriptor[:descriptor_merchant_id]
250
+ post[:descriptor_url] = descriptor[:descriptor_url]
251
+ end
239
252
  end
240
253
 
241
254
  def add_vendor_data(post, options)
@@ -251,15 +264,20 @@ module ActiveMerchant #:nodoc:
251
264
  end
252
265
 
253
266
  def add_three_d_secure(post, options)
254
- return unless options[:three_d_secure]
255
-
256
- if (three_d_secure = options[:three_d_secure])
257
- post[:eci] = three_d_secure[:eci]
258
- post[:cavv] = three_d_secure[:cavv]
259
- post[:xid] = three_d_secure[:xid]
260
- post[:three_ds_version] = three_d_secure[:version]
261
- post[:directory_server_id] = three_d_secure[:ds_transaction_id]
262
- end
267
+ three_d_secure = options[:three_d_secure]
268
+ return unless three_d_secure
269
+
270
+ post[:cardholder_auth] = cardholder_auth(three_d_secure[:authentication_response_status])
271
+ post[:cavv] = three_d_secure[:cavv]
272
+ post[:xid] = three_d_secure[:xid]
273
+ post[:three_ds_version] = three_d_secure[:version]
274
+ post[:directory_server_id] = three_d_secure[:ds_transaction_id]
275
+ end
276
+
277
+ def cardholder_auth(trans_status)
278
+ return nil if trans_status.nil?
279
+
280
+ trans_status == 'Y' ? 'verified' : 'attempted'
263
281
  end
264
282
 
265
283
  def add_reference(post, authorization)