activemerchant 1.126.0 → 1.129.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +241 -0
  3. data/lib/active_merchant/billing/check.rb +40 -8
  4. data/lib/active_merchant/billing/credit_card.rb +28 -1
  5. data/lib/active_merchant/billing/credit_card_methods.rb +79 -23
  6. data/lib/active_merchant/billing/gateways/adyen.rb +67 -8
  7. data/lib/active_merchant/billing/gateways/airwallex.rb +40 -11
  8. data/lib/active_merchant/billing/gateways/alelo.rb +256 -0
  9. data/lib/active_merchant/billing/gateways/authorize_net.rb +21 -4
  10. data/lib/active_merchant/billing/gateways/beanstream.rb +18 -0
  11. data/lib/active_merchant/billing/gateways/blue_snap.rb +22 -1
  12. data/lib/active_merchant/billing/gateways/bogus.rb +4 -0
  13. data/lib/active_merchant/billing/gateways/borgun.rb +56 -16
  14. data/lib/active_merchant/billing/gateways/braintree_blue.rb +64 -17
  15. data/lib/active_merchant/billing/gateways/card_connect.rb +27 -9
  16. data/lib/active_merchant/billing/gateways/card_stream.rb +23 -0
  17. data/lib/active_merchant/billing/gateways/checkout_v2.rb +228 -57
  18. data/lib/active_merchant/billing/gateways/commerce_hub.rb +361 -0
  19. data/lib/active_merchant/billing/gateways/credorax.rb +47 -27
  20. data/lib/active_merchant/billing/gateways/cyber_source/cyber_source_common.rb +36 -0
  21. data/lib/active_merchant/billing/gateways/cyber_source.rb +100 -26
  22. data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +456 -0
  23. data/lib/active_merchant/billing/gateways/d_local.rb +44 -5
  24. data/lib/active_merchant/billing/gateways/decidir.rb +15 -4
  25. data/lib/active_merchant/billing/gateways/ebanx.rb +36 -24
  26. data/lib/active_merchant/billing/gateways/element.rb +21 -1
  27. data/lib/active_merchant/billing/gateways/global_collect.rb +73 -22
  28. data/lib/active_merchant/billing/gateways/ipg.rb +13 -8
  29. data/lib/active_merchant/billing/gateways/iveri.rb +39 -3
  30. data/lib/active_merchant/billing/gateways/kushki.rb +21 -1
  31. data/lib/active_merchant/billing/gateways/litle.rb +25 -5
  32. data/lib/active_merchant/billing/gateways/mastercard.rb +1 -8
  33. data/lib/active_merchant/billing/gateways/mercado_pago.rb +17 -0
  34. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +44 -10
  35. data/lib/active_merchant/billing/gateways/monei.rb +2 -0
  36. data/lib/active_merchant/billing/gateways/moneris.rb +20 -5
  37. data/lib/active_merchant/billing/gateways/mundipagg.rb +3 -0
  38. data/lib/active_merchant/billing/gateways/ogone.rb +35 -7
  39. data/lib/active_merchant/billing/gateways/openpay.rb +20 -3
  40. data/lib/active_merchant/billing/gateways/orbital.rb +43 -22
  41. data/lib/active_merchant/billing/gateways/pay_trace.rb +64 -18
  42. data/lib/active_merchant/billing/gateways/payeezy.rb +59 -4
  43. data/lib/active_merchant/billing/gateways/paymentez.rb +18 -6
  44. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +4 -0
  45. data/lib/active_merchant/billing/gateways/paysafe.rb +22 -14
  46. data/lib/active_merchant/billing/gateways/payu_latam.rb +3 -0
  47. data/lib/active_merchant/billing/gateways/plexo.rb +308 -0
  48. data/lib/active_merchant/billing/gateways/priority.rb +29 -6
  49. data/lib/active_merchant/billing/gateways/rapyd.rb +110 -49
  50. data/lib/active_merchant/billing/gateways/reach.rb +277 -0
  51. data/lib/active_merchant/billing/gateways/redsys.rb +9 -5
  52. data/lib/active_merchant/billing/gateways/sage_pay.rb +1 -1
  53. data/lib/active_merchant/billing/gateways/securion_pay.rb +40 -0
  54. data/lib/active_merchant/billing/gateways/shift4.rb +342 -0
  55. data/lib/active_merchant/billing/gateways/simetrik.rb +28 -22
  56. data/lib/active_merchant/billing/gateways/stripe.rb +21 -1
  57. data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +62 -22
  58. data/lib/active_merchant/billing/gateways/tns.rb +2 -5
  59. data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +1 -1
  60. data/lib/active_merchant/billing/gateways/trust_commerce.rb +14 -3
  61. data/lib/active_merchant/billing/gateways/vanco.rb +12 -3
  62. data/lib/active_merchant/billing/gateways/visanet_peru.rb +1 -1
  63. data/lib/active_merchant/billing/gateways/vpos.rb +7 -4
  64. data/lib/active_merchant/billing/gateways/wompi.rb +8 -4
  65. data/lib/active_merchant/billing/gateways/worldpay.rb +117 -9
  66. data/lib/active_merchant/billing/response.rb +15 -1
  67. data/lib/active_merchant/connection.rb +0 -2
  68. data/lib/active_merchant/country.rb +1 -0
  69. data/lib/active_merchant/errors.rb +4 -1
  70. data/lib/active_merchant/version.rb +1 -1
  71. metadata +24 -3
@@ -0,0 +1,361 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class CommerceHubGateway < Gateway
4
+ self.test_url = 'https://cert.api.fiservapps.com/ch'
5
+ self.live_url = 'https://prod.api.fiservapps.com/ch'
6
+
7
+ self.supported_countries = ['US']
8
+ self.default_currency = 'USD'
9
+ self.supported_cardtypes = %i[visa master american_express discover]
10
+
11
+ self.homepage_url = 'https://developer.fiserv.com/product/CommerceHub'
12
+ self.display_name = 'CommerceHub'
13
+
14
+ STANDARD_ERROR_CODE_MAPPING = {}
15
+
16
+ SCHEDULED_REASON_TYPES = %w(recurring installment)
17
+ ENDPOINTS = {
18
+ 'sale' => '/payments/v1/charges',
19
+ 'void' => '/payments/v1/cancels',
20
+ 'refund' => '/payments/v1/refunds',
21
+ 'vault' => '/payments-vas/v1/tokens',
22
+ 'verify' => '/payments-vas/v1/accounts/verification'
23
+ }
24
+
25
+ def initialize(options = {})
26
+ requires!(options, :api_key, :api_secret, :merchant_id, :terminal_id)
27
+ super
28
+ end
29
+
30
+ def purchase(money, payment, options = {})
31
+ post = {}
32
+ options[:capture_flag] = true
33
+ options[:create_token] = false
34
+
35
+ add_transaction_details(post, options, 'sale')
36
+ build_purchase_and_auth_request(post, money, payment, options)
37
+
38
+ commit('sale', post, options)
39
+ end
40
+
41
+ def authorize(money, payment, options = {})
42
+ post = {}
43
+ options[:capture_flag] = false
44
+ options[:create_token] = false
45
+
46
+ add_transaction_details(post, options, 'sale')
47
+ build_purchase_and_auth_request(post, money, payment, options)
48
+
49
+ commit('sale', post, options)
50
+ end
51
+
52
+ def capture(money, authorization, options = {})
53
+ post = {}
54
+ options[:capture_flag] = true
55
+ add_invoice(post, money, options)
56
+ add_transaction_details(post, options, 'capture')
57
+ add_reference_transaction_details(post, authorization, options, :capture)
58
+
59
+ commit('sale', post, options)
60
+ end
61
+
62
+ def refund(money, authorization, options = {})
63
+ post = {}
64
+ add_invoice(post, money, options) if money
65
+ add_transaction_details(post, options)
66
+ add_reference_transaction_details(post, authorization, options, :refund)
67
+
68
+ commit('refund', post, options)
69
+ end
70
+
71
+ def void(authorization, options = {})
72
+ post = {}
73
+ add_transaction_details(post, options)
74
+ add_reference_transaction_details(post, authorization, options, :void)
75
+
76
+ commit('void', post, options)
77
+ end
78
+
79
+ def store(credit_card, options = {})
80
+ post = {}
81
+ add_payment(post, credit_card, options)
82
+ add_billing_address(post, credit_card, options)
83
+ add_transaction_details(post, options)
84
+ add_transaction_interaction(post, options)
85
+
86
+ commit('vault', post, options)
87
+ end
88
+
89
+ def verify(credit_card, options = {})
90
+ post = {}
91
+ add_payment(post, credit_card, options)
92
+ add_billing_address(post, credit_card, options)
93
+
94
+ commit('verify', post, options)
95
+ end
96
+
97
+ def supports_scrubbing?
98
+ true
99
+ end
100
+
101
+ def scrub(transcript)
102
+ transcript.
103
+ gsub(%r((Authorization: )[a-zA-Z0-9+./=]+), '\1[FILTERED]').
104
+ gsub(%r((Api-Key: )\w+), '\1[FILTERED]').
105
+ gsub(%r(("cardData\\?":\\?")\d+), '\1[FILTERED]').
106
+ gsub(%r(("securityCode\\?":\\?")\d+), '\1[FILTERED]').
107
+ gsub(%r(("cavv\\?":\\?")\w+), '\1[FILTERED]')
108
+ end
109
+
110
+ private
111
+
112
+ def add_transaction_interaction(post, options)
113
+ post[:transactionInteraction] = {}
114
+ post[:transactionInteraction][:origin] = options[:origin] || 'ECOM'
115
+ post[:transactionInteraction][:eciIndicator] = options[:eci_indicator] || 'CHANNEL_ENCRYPTED'
116
+ post[:transactionInteraction][:posConditionCode] = options[:pos_condition_code] || 'CARD_NOT_PRESENT_ECOM'
117
+ post[:transactionInteraction][:posEntryMode] = options[:pos_entry_mode] || 'MANUAL'
118
+ post[:transactionInteraction][:additionalPosInformation] = {}
119
+ post[:transactionInteraction][:additionalPosInformation][:dataEntrySource] = options[:data_entry_source] || 'UNSPECIFIED'
120
+ end
121
+
122
+ def add_transaction_details(post, options, action = nil)
123
+ details = { captureFlag: options[:capture_flag], createToken: options[:create_token] }
124
+
125
+ if options[:order_id].present? && action == 'sale'
126
+ details[:merchantOrderId] = options[:order_id]
127
+ details[:merchantTransactionId] = options[:order_id]
128
+ end
129
+
130
+ if action != 'capture'
131
+ details[:merchantInvoiceNumber] = options[:merchant_invoice_number] || rand.to_s[2..13]
132
+ details[:primaryTransactionType] = options[:primary_transaction_type]
133
+ details[:accountVerification] = options[:account_verification]
134
+ end
135
+
136
+ post[:transactionDetails] = details.compact
137
+ end
138
+
139
+ def add_billing_address(post, payment, options)
140
+ return unless billing = options[:billing_address]
141
+
142
+ billing_address = {}
143
+ if payment.is_a?(CreditCard)
144
+ billing_address[:firstName] = payment.first_name if payment.first_name
145
+ billing_address[:lastName] = payment.last_name if payment.last_name
146
+ end
147
+ address = {}
148
+ address[:street] = billing[:address1] if billing[:address1]
149
+ address[:houseNumberOrName] = billing[:address2] if billing[:address2]
150
+ address[:recipientNameOrAddress] = billing[:name] if billing[:name]
151
+ address[:city] = billing[:city] if billing[:city]
152
+ address[:stateOrProvince] = billing[:state] if billing[:state]
153
+ address[:postalCode] = billing[:zip] if billing[:zip]
154
+ address[:country] = billing[:country] if billing[:country]
155
+
156
+ billing_address[:address] = address unless address.empty?
157
+ if billing[:phone_number]
158
+ billing_address[:phone] = {}
159
+ billing_address[:phone][:phoneNumber] = billing[:phone_number]
160
+ end
161
+ post[:billingAddress] = billing_address
162
+ end
163
+
164
+ def add_shipping_address(post, options)
165
+ return unless shipping = options[:shipping_address]
166
+
167
+ shipping_address = {}
168
+ address = {}
169
+ address[:street] = shipping[:address1] if shipping[:address1]
170
+ address[:houseNumberOrName] = shipping[:address2] if shipping[:address2]
171
+ address[:recipientNameOrAddress] = shipping[:name] if shipping[:name]
172
+ address[:city] = shipping[:city] if shipping[:city]
173
+ address[:stateOrProvince] = shipping[:state] if shipping[:state]
174
+ address[:postalCode] = shipping[:zip] if shipping[:zip]
175
+ address[:country] = shipping[:country] if shipping[:country]
176
+
177
+ shipping_address[:address] = address unless address.empty?
178
+ if shipping[:phone_number]
179
+ shipping_address[:phone] = {}
180
+ shipping_address[:phone][:phoneNumber] = shipping[:phone_number]
181
+ end
182
+ post[:shippingAddress] = shipping_address
183
+ end
184
+
185
+ def build_purchase_and_auth_request(post, money, payment, options)
186
+ add_invoice(post, money, options)
187
+ add_payment(post, payment, options)
188
+ add_stored_credentials(post, options)
189
+ add_transaction_interaction(post, options)
190
+ add_billing_address(post, payment, options)
191
+ add_shipping_address(post, options)
192
+ end
193
+
194
+ def add_reference_transaction_details(post, authorization, options, action = nil)
195
+ reference_details = {}
196
+ _merchant_reference, transaction_id = authorization.include?('|') ? authorization.split('|') : [nil, authorization]
197
+
198
+ reference_details[:referenceTransactionId] = transaction_id
199
+ reference_details[:referenceTransactionType] = (options[:reference_transaction_type] || 'CHARGES') unless action == :capture
200
+ post[:referenceTransactionDetails] = reference_details.compact
201
+ end
202
+
203
+ def add_invoice(post, money, options)
204
+ post[:amount] = {
205
+ total: amount(money).to_f,
206
+ currency: options[:currency] || self.default_currency
207
+ }
208
+ end
209
+
210
+ def add_stored_credentials(post, options)
211
+ return unless stored_credential = options[:stored_credential]
212
+
213
+ post[:storedCredentials] = {}
214
+ post[:storedCredentials][:sequence] = stored_credential[:initial_transaction] ? 'FIRST' : 'SUBSEQUENT'
215
+ post[:storedCredentials][:initiator] = stored_credential[:initiator] == 'merchant' ? 'MERCHANT' : 'CARD_HOLDER'
216
+ post[:storedCredentials][:scheduled] = SCHEDULED_REASON_TYPES.include?(stored_credential[:reason_type])
217
+ post[:storedCredentials][:schemeReferenceTransactionId] = stored_credential[:network_transaction_id] if stored_credential[:network_transaction_id]
218
+ end
219
+
220
+ def add_credit_card(source, payment, options)
221
+ source[:sourceType] = 'PaymentCard'
222
+ source[:card] = {}
223
+ source[:card][:cardData] = payment.number
224
+ source[:card][:expirationMonth] = format(payment.month, :two_digits) if payment.month
225
+ source[:card][:expirationYear] = format(payment.year, :four_digits) if payment.year
226
+ if payment.verification_value
227
+ source[:card][:securityCode] = payment.verification_value
228
+ source[:card][:securityCodeIndicator] = 'PROVIDED'
229
+ end
230
+ end
231
+
232
+ def add_payment_token(source, payment, options)
233
+ source[:sourceType] = 'PaymentToken'
234
+ source[:tokenData] = payment
235
+ source[:tokenSource] = options[:token_source] if options[:token_source]
236
+ if options[:card_expiration_month] || options[:card_expiration_year]
237
+ source[:card] = {}
238
+ source[:card][:expirationMonth] = options[:card_expiration_month] if options[:card_expiration_month]
239
+ source[:card][:expirationYear] = options[:card_expiration_year] if options[:card_expiration_year]
240
+ end
241
+ end
242
+
243
+ def add_decrypted_wallet(source, payment, options)
244
+ source[:sourceType] = 'DecryptedWallet'
245
+ source[:card] = {}
246
+ source[:card][:cardData] = payment.number
247
+ source[:card][:expirationMonth] = format(payment.month, :two_digits)
248
+ source[:card][:expirationYear] = format(payment.year, :four_digits)
249
+ source[:cavv] = payment.payment_cryptogram
250
+ source[:walletType] = payment.source.to_s.upcase
251
+ end
252
+
253
+ def add_payment(post, payment, options = {})
254
+ source = {}
255
+ case payment
256
+ when NetworkTokenizationCreditCard
257
+ add_decrypted_wallet(source, payment, options)
258
+ when CreditCard
259
+ add_credit_card(source, payment, options)
260
+ when String
261
+ add_payment_token(source, payment, options)
262
+ end
263
+ post[:source] = source
264
+ end
265
+
266
+ def parse(body)
267
+ JSON.parse(body)
268
+ end
269
+
270
+ def headers(request, options)
271
+ time = DateTime.now.strftime('%Q').to_s
272
+ client_request_id = options[:client_request_id] || rand.to_s[2..8]
273
+ raw_signature = @options[:api_key] + client_request_id.to_s + time + request
274
+ hmac = OpenSSL::HMAC.digest('sha256', @options[:api_secret], raw_signature)
275
+ signature = Base64.strict_encode64(hmac.to_s).to_s
276
+
277
+ {
278
+ 'Client-Request-Id' => client_request_id,
279
+ 'Api-Key' => @options[:api_key],
280
+ 'Timestamp' => time,
281
+ 'Accept-Language' => 'application/json',
282
+ 'Auth-Token-Type' => 'HMAC',
283
+ 'Content-Type' => 'application/json',
284
+ 'Accept' => 'application/json',
285
+ 'Authorization' => signature
286
+ }
287
+ end
288
+
289
+ def add_merchant_details(post)
290
+ post[:merchantDetails] = {}
291
+ post[:merchantDetails][:terminalId] = @options[:terminal_id]
292
+ post[:merchantDetails][:merchantId] = @options[:merchant_id]
293
+ end
294
+
295
+ def commit(action, parameters, options)
296
+ url = (test? ? test_url : live_url) + ENDPOINTS[action]
297
+ add_merchant_details(parameters)
298
+ response = parse(ssl_post(url, parameters.to_json, headers(parameters.to_json, options)))
299
+
300
+ Response.new(
301
+ success_from(response, action),
302
+ message_from(response, action),
303
+ response,
304
+ authorization: authorization_from(action, response, options),
305
+ test: test?,
306
+ error_code: error_code_from(response, action),
307
+ avs_result: AVSResult.new(code: get_avs_cvv(response, 'avs')),
308
+ cvv_result: CVVResult.new(get_avs_cvv(response, 'cvv'))
309
+ )
310
+ end
311
+
312
+ def get_avs_cvv(response, type = 'avs')
313
+ response.dig(
314
+ 'paymentReceipt',
315
+ 'processorResponseDetails',
316
+ 'bankAssociationDetails',
317
+ 'avsSecurityCodeResponse',
318
+ 'association',
319
+ type == 'avs' ? 'avsCode' : 'securityCodeResponse'
320
+ )
321
+ end
322
+
323
+ def handle_response(response)
324
+ case response.code.to_i
325
+ when 200...300, 400, 401, 429
326
+ response.body
327
+ else
328
+ raise ResponseError.new(response)
329
+ end
330
+ end
331
+
332
+ def success_from(response, action = nil)
333
+ return message_from(response, action) == 'VERIFIED' if action == 'verify'
334
+
335
+ (response.dig('paymentReceipt', 'processorResponseDetails', 'responseCode') || response.dig('paymentTokens', 0, 'tokenResponseCode')) == '000'
336
+ end
337
+
338
+ def message_from(response, action = nil)
339
+ return response.dig('error', 0, 'message') if response['error'].present?
340
+ return response.dig('gatewayResponse', 'transactionState') if action == 'verify'
341
+
342
+ response.dig('paymentReceipt', 'processorResponseDetails', 'responseMessage') || response.dig('gatewayResponse', 'transactionType')
343
+ end
344
+
345
+ def authorization_from(action, response, options)
346
+ case action
347
+ when 'vault'
348
+ response.dig('paymentTokens', 0, 'tokenData')
349
+ when 'sale'
350
+ [options[:order_id] || '', response.dig('gatewayResponse', 'transactionProcessingDetails', 'transactionId')].join('|')
351
+ else
352
+ response.dig('gatewayResponse', 'transactionProcessingDetails', 'transactionId')
353
+ end
354
+ end
355
+
356
+ def error_code_from(response, action)
357
+ response.dig('error', 0, 'code') unless success_from(response, action)
358
+ end
359
+ end
360
+ end
361
+ end
@@ -4,7 +4,7 @@ module ActiveMerchant #:nodoc:
4
4
  class_attribute :test_url, :live_na_url, :live_eu_url
5
5
 
6
6
  self.display_name = 'Credorax Gateway'
7
- self.homepage_url = 'https://www.credorax.com/'
7
+ self.homepage_url = 'https://www.finaro.com/'
8
8
 
9
9
  # NOTE: the IP address you run the remote tests from will need to be
10
10
  # whitelisted by Credorax; contact support@credorax.com as necessary to
@@ -26,7 +26,13 @@ module ActiveMerchant #:nodoc:
26
26
  self.currencies_with_three_decimal_places = %w(BHD IQD JOD KWD LYD OMR TND)
27
27
 
28
28
  self.money_format = :cents
29
- self.supported_cardtypes = %i[visa master maestro american_express]
29
+ self.supported_cardtypes = %i[visa master maestro american_express jcb discover diners_club]
30
+
31
+ NETWORK_TOKENIZATION_CARD_SOURCE = {
32
+ 'apple_pay' => 'applepay',
33
+ 'google_pay' => 'googlepay',
34
+ 'network_token' => 'vts_mdes_token'
35
+ }
30
36
 
31
37
  RESPONSE_MESSAGES = {
32
38
  '00' => 'Approved or completed successfully',
@@ -63,26 +69,27 @@ module ActiveMerchant #:nodoc:
63
69
  '31' => 'Issuer signed-off',
64
70
  '32' => 'Completed partially',
65
71
  '33' => 'Pick-up, expired card',
66
- '34' => 'Suspect Fraud',
72
+ '34' => 'Implausible card data',
67
73
  '35' => 'Pick-up, card acceptor contact acquirer',
68
74
  '36' => 'Pick up, card restricted',
69
75
  '37' => 'Pick up, call acquirer security',
70
76
  '38' => 'Pick up, Allowable PIN tries exceeded',
71
- '39' => 'Transaction Not Allowed',
77
+ '39' => 'No credit account',
72
78
  '40' => 'Requested function not supported',
73
79
  '41' => 'Lost Card, Pickup',
74
80
  '42' => 'No universal account',
75
81
  '43' => 'Pick up, stolen card',
76
82
  '44' => 'No investment account',
83
+ '46' => 'Closed account',
77
84
  '50' => 'Do not renew',
78
- '51' => 'Not sufficient funds',
85
+ '51' => 'Insufficient funds',
79
86
  '52' => 'No checking Account',
80
87
  '53' => 'No savings account',
81
88
  '54' => 'Expired card',
82
- '55' => 'Pin incorrect',
89
+ '55' => 'Incorrect PIN',
83
90
  '56' => 'No card record',
84
91
  '57' => 'Transaction not allowed for cardholder',
85
- '58' => 'Transaction not allowed for merchant',
92
+ '58' => 'Transaction not permitted to terminal',
86
93
  '59' => 'Suspected Fraud',
87
94
  '60' => 'Card acceptor contact acquirer',
88
95
  '61' => 'Exceeds withdrawal amount limit',
@@ -93,22 +100,22 @@ module ActiveMerchant #:nodoc:
93
100
  '66' => 'Call acquirers security department',
94
101
  '67' => 'Card to be picked up at ATM',
95
102
  '68' => 'Response received too late.',
96
- '70' => 'Invalid transaction; contact card issuer',
103
+ '70' => 'PIN data required',
97
104
  '71' => 'Decline PIN not changed',
98
105
  '75' => 'Pin tries exceeded',
99
106
  '76' => 'Wrong PIN, number of PIN tries exceeded',
100
107
  '77' => 'Wrong Reference No.',
101
- '78' => 'Record Not Found',
102
- '79' => 'Already reversed',
108
+ '78' => 'Blocked, first used/ Record not found',
109
+ '79' => 'Declined due to lifecycle event',
103
110
  '80' => 'Network error',
104
- '81' => 'Foreign network error / PIN cryptographic error',
105
- '82' => 'Time out at issuer system',
111
+ '81' => 'PIN cryptographic error',
112
+ '82' => 'Bad CVV/ Declined due to policy event',
106
113
  '83' => 'Transaction failed',
107
114
  '84' => 'Pre-authorization timed out',
108
115
  '85' => 'No reason to decline',
109
116
  '86' => 'Cannot verify pin',
110
117
  '87' => 'Purchase amount only, no cashback allowed',
111
- '88' => 'MAC sync Error',
118
+ '88' => 'Cryptographic failure',
112
119
  '89' => 'Authentication failure',
113
120
  '91' => 'Issuer not available',
114
121
  '92' => 'Unable to route at acquirer Module',
@@ -116,9 +123,13 @@ module ActiveMerchant #:nodoc:
116
123
  '94' => 'Duplicate Transmission',
117
124
  '95' => 'Reconcile error / Auth Not found',
118
125
  '96' => 'System malfunction',
126
+ '97' => 'Transaction has been declined by the processor',
127
+ 'N3' => 'Cash service not available',
128
+ 'N4' => 'Cash request exceeds issuer or approved limit',
129
+ 'N7' => 'CVV2 failure',
119
130
  'R0' => 'Stop Payment Order',
120
131
  'R1' => 'Revocation of Authorisation Order',
121
- 'R3' => 'Revocation of all Authorisations Order',
132
+ 'R3' => 'Revocation of all Authorisation Orders',
122
133
  '1A' => 'Strong Customer Authentication required'
123
134
  }
124
135
 
@@ -130,7 +141,7 @@ module ActiveMerchant #:nodoc:
130
141
  def purchase(amount, payment_method, options = {})
131
142
  post = {}
132
143
  add_invoice(post, amount, options)
133
- add_payment_method(post, payment_method)
144
+ add_payment_method(post, payment_method, options)
134
145
  add_customer_data(post, options)
135
146
  add_email(post, options)
136
147
  add_3d_secure(post, options)
@@ -146,7 +157,7 @@ module ActiveMerchant #:nodoc:
146
157
  def authorize(amount, payment_method, options = {})
147
158
  post = {}
148
159
  add_invoice(post, amount, options)
149
- add_payment_method(post, payment_method)
160
+ add_payment_method(post, payment_method, options)
150
161
  add_customer_data(post, options)
151
162
  add_email(post, options)
152
163
  add_3d_secure(post, options)
@@ -206,13 +217,14 @@ module ActiveMerchant #:nodoc:
206
217
  def credit(amount, payment_method, options = {})
207
218
  post = {}
208
219
  add_invoice(post, amount, options)
209
- add_payment_method(post, payment_method)
220
+ add_payment_method(post, payment_method, options)
210
221
  add_customer_data(post, options)
211
222
  add_email(post, options)
212
223
  add_echo(post, options)
213
224
  add_submerchant_id(post, options)
214
225
  add_transaction_type(post, options)
215
226
  add_processor(post, options)
227
+ add_customer_name(post, options)
216
228
 
217
229
  commit(:credit, post)
218
230
  end
@@ -271,8 +283,9 @@ module ActiveMerchant #:nodoc:
271
283
  'maestro' => '9'
272
284
  }
273
285
 
274
- def add_payment_method(post, payment_method)
275
- post[:c1] = payment_method.name
286
+ def add_payment_method(post, payment_method, options)
287
+ post[:c1] = payment_method&.name || ''
288
+ add_network_tokenization_card(post, payment_method, options) if payment_method.is_a? NetworkTokenizationCreditCard
276
289
  post[:b2] = CARD_TYPES[payment_method.brand] || ''
277
290
  post[:b1] = payment_method.number
278
291
  post[:b5] = payment_method.verification_value
@@ -280,6 +293,13 @@ module ActiveMerchant #:nodoc:
280
293
  post[:b3] = format(payment_method.month, :two_digits)
281
294
  end
282
295
 
296
+ def add_network_tokenization_card(post, payment_method, options)
297
+ post[:b21] = NETWORK_TOKENIZATION_CARD_SOURCE[payment_method.source.to_s]
298
+ post[:token_eci] = post[:b21] == 'vts_mdes_token' ? '07' : nil
299
+ post[:token_eci] = options[:eci] || payment_method&.eci || (payment_method.brand.to_s == 'master' ? '00' : '07')
300
+ post[:token_crypto] = payment_method&.payment_cryptogram if payment_method.source.to_s == 'network_token'
301
+ end
302
+
283
303
  def add_stored_credential(post, options)
284
304
  add_transaction_type(post, options)
285
305
  # if :transaction_type option is not passed, then check for :stored_credential options
@@ -288,10 +308,11 @@ module ActiveMerchant #:nodoc:
288
308
  if stored_credential[:initiator] == 'merchant'
289
309
  case stored_credential[:reason_type]
290
310
  when 'recurring'
291
- stored_credential[:initial_transaction] ? post[:a9] = '1' : post[:a9] = '2'
311
+ post[:a9] = stored_credential[:initial_transaction] ? '1' : '2'
292
312
  when 'installment', 'unscheduled'
293
313
  post[:a9] = '8'
294
314
  end
315
+ post[:g6] = stored_credential[:network_transaction_id] if stored_credential[:network_transaction_id]
295
316
  else
296
317
  post[:a9] = '9'
297
318
  end
@@ -324,10 +345,11 @@ module ActiveMerchant #:nodoc:
324
345
  def add_recipient(post, options)
325
346
  return unless options[:recipient_street_address] || options[:recipient_city] || options[:recipient_province_code] || options[:recipient_country_code]
326
347
 
348
+ recipient_country_code = options[:recipient_country_code]&.length == 3 ? options[:recipient_country_code] : Country.find(options[:recipient_country_code]).code(:alpha3).value if options[:recipient_country_code]
327
349
  post[:j6] = options[:recipient_street_address] if options[:recipient_street_address]
328
350
  post[:j7] = options[:recipient_city] if options[:recipient_city]
329
351
  post[:j8] = options[:recipient_province_code] if options[:recipient_province_code]
330
- post[:j9] = options[:recipient_country_code] if options[:recipient_country_code]
352
+ post[:j9] = recipient_country_code
331
353
  end
332
354
 
333
355
  def add_customer_name(post, options)
@@ -434,7 +456,7 @@ module ActiveMerchant #:nodoc:
434
456
  capture: '3',
435
457
  authorize_void: '4',
436
458
  refund: '5',
437
- credit: '6',
459
+ credit: '35',
438
460
  purchase_void: '7',
439
461
  refund_void: '8',
440
462
  capture_void: '9',
@@ -475,11 +497,9 @@ module ActiveMerchant #:nodoc:
475
497
  end
476
498
 
477
499
  def request_action(action, reference_action)
478
- if reference_action
479
- ACTIONS["#{reference_action}_#{action}".to_sym]
480
- else
481
- ACTIONS[action]
482
- end
500
+ return ACTIONS["#{reference_action}_#{action}".to_sym] if reference_action
501
+
502
+ ACTIONS[action]
483
503
  end
484
504
 
485
505
  def url
@@ -0,0 +1,36 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module CyberSourceCommon
4
+ def check_billing_field_value(default, submitted)
5
+ if submitted.nil?
6
+ nil
7
+ elsif submitted.blank?
8
+ default
9
+ else
10
+ submitted
11
+ end
12
+ end
13
+
14
+ def address_names(address_name, payment_method)
15
+ names = split_names(address_name)
16
+ return names if names.any?(&:present?)
17
+
18
+ [
19
+ payment_method&.first_name,
20
+ payment_method&.last_name
21
+ ]
22
+ end
23
+
24
+ def lookup_country_code(country_field)
25
+ return unless country_field.present?
26
+
27
+ country_code = Country.find(country_field)
28
+ country_code&.code(:alpha2)
29
+ end
30
+
31
+ def eligible_for_zero_auth?(payment_method, options = {})
32
+ payment_method.is_a?(CreditCard) && options[:zero_amount_auth]
33
+ end
34
+ end
35
+ end
36
+ end