activemerchant 1.126.0 → 1.129.0

Sign up to get free protection for your applications and to get access to all the features.
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