activemerchant 1.126.0 → 1.131.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +269 -0
- data/lib/active_merchant/billing/check.rb +40 -8
- data/lib/active_merchant/billing/credit_card.rb +28 -1
- data/lib/active_merchant/billing/credit_card_methods.rb +80 -24
- data/lib/active_merchant/billing/gateways/adyen.rb +69 -10
- data/lib/active_merchant/billing/gateways/airwallex.rb +40 -11
- data/lib/active_merchant/billing/gateways/alelo.rb +256 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +24 -6
- data/lib/active_merchant/billing/gateways/beanstream.rb +18 -0
- data/lib/active_merchant/billing/gateways/blue_snap.rb +22 -1
- data/lib/active_merchant/billing/gateways/bogus.rb +4 -0
- data/lib/active_merchant/billing/gateways/borgun.rb +57 -16
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +72 -24
- data/lib/active_merchant/billing/gateways/card_connect.rb +27 -9
- data/lib/active_merchant/billing/gateways/card_stream.rb +23 -0
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +238 -57
- data/lib/active_merchant/billing/gateways/commerce_hub.rb +366 -0
- data/lib/active_merchant/billing/gateways/credorax.rb +47 -27
- data/lib/active_merchant/billing/gateways/cyber_source/cyber_source_common.rb +36 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +119 -33
- data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +454 -0
- data/lib/active_merchant/billing/gateways/d_local.rb +45 -5
- data/lib/active_merchant/billing/gateways/decidir.rb +15 -4
- data/lib/active_merchant/billing/gateways/ebanx.rb +36 -24
- data/lib/active_merchant/billing/gateways/element.rb +21 -1
- data/lib/active_merchant/billing/gateways/global_collect.rb +113 -40
- data/lib/active_merchant/billing/gateways/ipg.rb +13 -8
- data/lib/active_merchant/billing/gateways/iveri.rb +39 -3
- data/lib/active_merchant/billing/gateways/kushki.rb +21 -1
- data/lib/active_merchant/billing/gateways/litle.rb +25 -5
- data/lib/active_merchant/billing/gateways/mastercard.rb +1 -8
- data/lib/active_merchant/billing/gateways/mercado_pago.rb +17 -0
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +44 -10
- data/lib/active_merchant/billing/gateways/monei.rb +2 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +20 -5
- data/lib/active_merchant/billing/gateways/mundipagg.rb +3 -0
- data/lib/active_merchant/billing/gateways/ogone.rb +35 -7
- data/lib/active_merchant/billing/gateways/openpay.rb +20 -3
- data/lib/active_merchant/billing/gateways/orbital.rb +43 -22
- data/lib/active_merchant/billing/gateways/pay_trace.rb +64 -18
- data/lib/active_merchant/billing/gateways/payeezy.rb +59 -4
- data/lib/active_merchant/billing/gateways/paymentez.rb +18 -6
- data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +4 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +2 -0
- data/lib/active_merchant/billing/gateways/paysafe.rb +22 -14
- data/lib/active_merchant/billing/gateways/payu_latam.rb +4 -1
- data/lib/active_merchant/billing/gateways/plexo.rb +308 -0
- data/lib/active_merchant/billing/gateways/priority.rb +29 -6
- data/lib/active_merchant/billing/gateways/rapyd.rb +110 -49
- data/lib/active_merchant/billing/gateways/reach.rb +277 -0
- data/lib/active_merchant/billing/gateways/redsys.rb +11 -6
- data/lib/active_merchant/billing/gateways/sage_pay.rb +1 -1
- data/lib/active_merchant/billing/gateways/securion_pay.rb +40 -0
- data/lib/active_merchant/billing/gateways/shift4.rb +345 -0
- data/lib/active_merchant/billing/gateways/simetrik.rb +28 -22
- data/lib/active_merchant/billing/gateways/stripe.rb +30 -6
- data/lib/active_merchant/billing/gateways/stripe_payment_intents.rb +62 -22
- data/lib/active_merchant/billing/gateways/tns.rb +2 -5
- data/lib/active_merchant/billing/gateways/trans_first_transaction_express.rb +1 -1
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +14 -3
- data/lib/active_merchant/billing/gateways/vanco.rb +12 -3
- data/lib/active_merchant/billing/gateways/visanet_peru.rb +1 -1
- data/lib/active_merchant/billing/gateways/vpos.rb +7 -4
- data/lib/active_merchant/billing/gateways/wompi.rb +8 -4
- data/lib/active_merchant/billing/gateways/worldpay.rb +128 -13
- data/lib/active_merchant/billing/response.rb +15 -1
- data/lib/active_merchant/connection.rb +0 -2
- data/lib/active_merchant/country.rb +1 -0
- data/lib/active_merchant/errors.rb +4 -1
- data/lib/active_merchant/version.rb +1 -1
- metadata +24 -3
@@ -42,6 +42,7 @@ module ActiveMerchant #:nodoc:
|
|
42
42
|
add_error_on_requires_action(post, options)
|
43
43
|
add_fulfillment_date(post, options)
|
44
44
|
request_three_d_secure(post, options)
|
45
|
+
add_level_three(post, options)
|
45
46
|
|
46
47
|
CREATE_INTENT_ATTRIBUTES.each do |attribute|
|
47
48
|
add_whitelisted_attribute(post, options, attribute)
|
@@ -55,6 +56,11 @@ module ActiveMerchant #:nodoc:
|
|
55
56
|
commit(:get, "payment_intents/#{intent_id}", nil, options)
|
56
57
|
end
|
57
58
|
|
59
|
+
def create_test_customer
|
60
|
+
response = api_request(:post, 'customers')
|
61
|
+
response['id']
|
62
|
+
end
|
63
|
+
|
58
64
|
def confirm_intent(intent_id, payment_method, options = {})
|
59
65
|
post = {}
|
60
66
|
result = add_payment_method_token(post, payment_method, options)
|
@@ -116,23 +122,27 @@ module ActiveMerchant #:nodoc:
|
|
116
122
|
end
|
117
123
|
|
118
124
|
def create_setup_intent(payment_method, options = {})
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
125
|
+
MultiResponse.run do |r|
|
126
|
+
r.process do
|
127
|
+
post = {}
|
128
|
+
add_customer(post, options)
|
129
|
+
result = add_payment_method_token(post, payment_method, options, r)
|
130
|
+
return result if result.is_a?(ActiveMerchant::Billing::Response)
|
123
131
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
132
|
+
add_metadata(post, options)
|
133
|
+
add_return_url(post, options)
|
134
|
+
add_fulfillment_date(post, options)
|
135
|
+
request_three_d_secure(post, options)
|
136
|
+
post[:on_behalf_of] = options[:on_behalf_of] if options[:on_behalf_of]
|
137
|
+
post[:usage] = options[:usage] if %w(on_session off_session).include?(options[:usage])
|
138
|
+
post[:description] = options[:description] if options[:description]
|
131
139
|
|
132
|
-
|
140
|
+
commit(:post, 'setup_intents', post, options)
|
141
|
+
end
|
142
|
+
end
|
133
143
|
end
|
134
144
|
|
135
|
-
def retrieve_setup_intent(setup_intent_id)
|
145
|
+
def retrieve_setup_intent(setup_intent_id, options = {})
|
136
146
|
# Retrieving a setup_intent passing 'expand[]=latest_attempt' allows the caller to
|
137
147
|
# check for a network_transaction_id and ds_transaction_id
|
138
148
|
# eg (latest_attempt -> payment_method_details -> card -> network_transaction_id)
|
@@ -140,7 +150,7 @@ module ActiveMerchant #:nodoc:
|
|
140
150
|
# Being able to retrieve these fields enables payment flows that rely on MIT exemptions, e.g: off_session
|
141
151
|
commit(:post, "setup_intents/#{setup_intent_id}", {
|
142
152
|
'expand[]': 'latest_attempt'
|
143
|
-
},
|
153
|
+
}, options)
|
144
154
|
end
|
145
155
|
|
146
156
|
def authorize(money, payment_method, options = {})
|
@@ -231,7 +241,7 @@ module ActiveMerchant #:nodoc:
|
|
231
241
|
end
|
232
242
|
|
233
243
|
def verify(payment_method, options = {})
|
234
|
-
create_setup_intent(payment_method, options.merge!(confirm: true))
|
244
|
+
create_setup_intent(payment_method, options.merge!({ confirm: true, verify: true }))
|
235
245
|
end
|
236
246
|
|
237
247
|
def setup_purchase(money, options = {})
|
@@ -284,6 +294,19 @@ module ActiveMerchant #:nodoc:
|
|
284
294
|
post[:metadata][:event_type] = options[:event_type] if options[:event_type]
|
285
295
|
end
|
286
296
|
|
297
|
+
def add_level_three(post, options = {})
|
298
|
+
level_three = {}
|
299
|
+
|
300
|
+
level_three[:merchant_reference] = options[:merchant_reference] if options[:merchant_reference]
|
301
|
+
level_three[:customer_reference] = options[:customer_reference] if options[:customer_reference]
|
302
|
+
level_three[:shipping_address_zip] = options[:shipping_address_zip] if options[:shipping_address_zip]
|
303
|
+
level_three[:shipping_from_zip] = options[:shipping_from_zip] if options[:shipping_from_zip]
|
304
|
+
level_three[:shipping_amount] = options[:shipping_amount] if options[:shipping_amount]
|
305
|
+
level_three[:line_items] = options[:line_items] if options[:line_items]
|
306
|
+
|
307
|
+
post[:level3] = level_three unless level_three.empty?
|
308
|
+
end
|
309
|
+
|
287
310
|
def add_return_url(post, options)
|
288
311
|
return unless options[:confirm]
|
289
312
|
|
@@ -291,7 +314,7 @@ module ActiveMerchant #:nodoc:
|
|
291
314
|
post[:return_url] = options[:return_url] if options[:return_url]
|
292
315
|
end
|
293
316
|
|
294
|
-
def add_payment_method_token(post, payment_method, options)
|
317
|
+
def add_payment_method_token(post, payment_method, options, responses = [])
|
295
318
|
case payment_method
|
296
319
|
when StripePaymentToken
|
297
320
|
post[:payment_method_data] = {
|
@@ -304,7 +327,9 @@ module ActiveMerchant #:nodoc:
|
|
304
327
|
when String
|
305
328
|
extract_token_from_string_and_maybe_add_customer_id(post, payment_method)
|
306
329
|
when ActiveMerchant::Billing::CreditCard
|
307
|
-
|
330
|
+
return create_payment_method_and_extract_token(post, payment_method, options, responses) if options[:verify]
|
331
|
+
|
332
|
+
get_payment_method_data_from_card(post, payment_method, options, responses)
|
308
333
|
end
|
309
334
|
end
|
310
335
|
|
@@ -333,6 +358,7 @@ module ActiveMerchant #:nodoc:
|
|
333
358
|
cryptogram: payment.payment_cryptogram
|
334
359
|
}
|
335
360
|
}
|
361
|
+
add_billing_address_for_card_tokenization(post, options) if %i(apple_pay android_pay).include?(tokenization_method)
|
336
362
|
token_response = api_request(:post, 'tokens', post, options)
|
337
363
|
success = token_response['error'].nil?
|
338
364
|
if success && token_response['id']
|
@@ -344,16 +370,17 @@ module ActiveMerchant #:nodoc:
|
|
344
370
|
end
|
345
371
|
end
|
346
372
|
|
347
|
-
def get_payment_method_data_from_card(post, payment_method, options)
|
348
|
-
return create_payment_method_and_extract_token(post, payment_method, options) unless off_session_request?(options)
|
373
|
+
def get_payment_method_data_from_card(post, payment_method, options, responses)
|
374
|
+
return create_payment_method_and_extract_token(post, payment_method, options, responses) unless off_session_request?(options)
|
349
375
|
|
350
376
|
post[:payment_method_data] = add_payment_method_data(payment_method, options)
|
351
377
|
end
|
352
378
|
|
353
|
-
def create_payment_method_and_extract_token(post, payment_method, options)
|
379
|
+
def create_payment_method_and_extract_token(post, payment_method, options, responses)
|
354
380
|
payment_method_response = create_payment_method(payment_method, options)
|
355
381
|
return payment_method_response if payment_method_response.failure?
|
356
382
|
|
383
|
+
responses << payment_method_response
|
357
384
|
add_payment_method_token(post, payment_method_response.params['id'], options)
|
358
385
|
end
|
359
386
|
|
@@ -448,9 +475,22 @@ module ActiveMerchant #:nodoc:
|
|
448
475
|
post
|
449
476
|
end
|
450
477
|
|
478
|
+
def add_billing_address_for_card_tokenization(post, options = {})
|
479
|
+
return unless (billing = options[:billing_address] || options[:address])
|
480
|
+
|
481
|
+
post[:card][:address_city] = billing[:city] if billing[:city]
|
482
|
+
post[:card][:address_country] = billing[:country] if billing[:country]
|
483
|
+
post[:card][:address_line1] = billing[:address1] if billing[:address1]
|
484
|
+
post[:card][:address_line2] = billing[:address2] if billing[:address2]
|
485
|
+
post[:card][:address_zip] = billing[:zip] if billing[:zip]
|
486
|
+
post[:card][:address_state] = billing[:state] if billing[:state]
|
487
|
+
end
|
488
|
+
|
451
489
|
def add_billing_address(post, options = {})
|
452
490
|
return unless billing = options[:billing_address] || options[:address]
|
453
491
|
|
492
|
+
email = billing[:email] || options[:email]
|
493
|
+
|
454
494
|
post[:billing_details] = {}
|
455
495
|
post[:billing_details][:address] = {}
|
456
496
|
post[:billing_details][:address][:city] = billing[:city] if billing[:city]
|
@@ -459,7 +499,7 @@ module ActiveMerchant #:nodoc:
|
|
459
499
|
post[:billing_details][:address][:line2] = billing[:address2] if billing[:address2]
|
460
500
|
post[:billing_details][:address][:postal_code] = billing[:zip] if billing[:zip]
|
461
501
|
post[:billing_details][:address][:state] = billing[:state] if billing[:state]
|
462
|
-
post[:billing_details][:email] =
|
502
|
+
post[:billing_details][:email] = email if email
|
463
503
|
post[:billing_details][:name] = billing[:name] if billing[:name]
|
464
504
|
post[:billing_details][:phone] = billing[:phone] if billing[:phone]
|
465
505
|
end
|
@@ -501,7 +541,7 @@ module ActiveMerchant #:nodoc:
|
|
501
541
|
def success_from(response, options)
|
502
542
|
if response['status'] == 'requires_action' && !options[:execute_threed]
|
503
543
|
response['error'] = {}
|
504
|
-
response['error']['message'] = 'Received unexpected 3DS authentication response
|
544
|
+
response['error']['message'] = 'Received unexpected 3DS authentication response, but a 3DS initiation flag was not included in the request.'
|
505
545
|
return false
|
506
546
|
end
|
507
547
|
|
@@ -8,13 +8,10 @@ module ActiveMerchant
|
|
8
8
|
VERSION = '52'
|
9
9
|
|
10
10
|
self.live_na_url = "https://secure.na.tnspayments.com/api/rest/version/#{VERSION}/"
|
11
|
-
self.test_na_url = "https://secure.na.tnspayments.com/api/rest/version/#{VERSION}/"
|
12
|
-
|
13
11
|
self.live_ap_url = "https://secure.ap.tnspayments.com/api/rest/version/#{VERSION}/"
|
14
|
-
self.test_ap_url = "https://secure.ap.tnspayments.com/api/rest/version/#{VERSION}/"
|
15
|
-
|
16
12
|
self.live_eu_url = "https://secure.eu.tnspayments.com/api/rest/version/#{VERSION}/"
|
17
|
-
|
13
|
+
|
14
|
+
self.test_url = "https://secure.uat.tnspayments.com/api/rest/version/#{VERSION}/"
|
18
15
|
|
19
16
|
self.display_name = 'TNS'
|
20
17
|
self.homepage_url = 'http://www.tnsi.com/'
|
@@ -482,7 +482,7 @@ module ActiveMerchant #:nodoc:
|
|
482
482
|
|
483
483
|
doc = Nokogiri::XML::Document.parse(request)
|
484
484
|
merc_nodeset = doc.xpath('//v1:merc', 'v1' => V1_NAMESPACE)
|
485
|
-
merc_nodeset.after "<tranCode>#{TRANSACTION_CODES[action]}</tranCode>"
|
485
|
+
merc_nodeset.after "<v1:tranCode>#{TRANSACTION_CODES[action]}</v1:tranCode>"
|
486
486
|
doc.root.to_xml
|
487
487
|
end
|
488
488
|
|
@@ -248,6 +248,12 @@ module ActiveMerchant #:nodoc:
|
|
248
248
|
commit(action, parameters)
|
249
249
|
end
|
250
250
|
|
251
|
+
def verify(credit_card, options = {})
|
252
|
+
parameters = {}
|
253
|
+
add_creditcard(parameters, credit_card)
|
254
|
+
commit('verify', parameters)
|
255
|
+
end
|
256
|
+
|
251
257
|
# recurring() a TrustCommerce account that is activated for Citadel, TrustCommerce's
|
252
258
|
# hosted customer billing info database.
|
253
259
|
#
|
@@ -476,9 +482,14 @@ module ActiveMerchant #:nodoc:
|
|
476
482
|
end
|
477
483
|
|
478
484
|
def authorization_from(action, data)
|
479
|
-
|
480
|
-
|
481
|
-
|
485
|
+
case action
|
486
|
+
when 'store'
|
487
|
+
data['billingid']
|
488
|
+
when *VOIDABLE_ACTIONS
|
489
|
+
"#{data['transid']}|#{action}"
|
490
|
+
else
|
491
|
+
data['transid']
|
492
|
+
end
|
482
493
|
end
|
483
494
|
|
484
495
|
def split_authorization(authorization)
|
@@ -15,15 +15,24 @@ module ActiveMerchant
|
|
15
15
|
self.homepage_url = 'http://vancopayments.com/'
|
16
16
|
self.display_name = 'Vanco Payment Solutions'
|
17
17
|
|
18
|
+
SECONDS_PER_DAY = 3600 * 24
|
19
|
+
BUFFER_TIME_IN_SECS = 60 * 3
|
20
|
+
|
18
21
|
def initialize(options = {})
|
19
22
|
requires!(options, :user_id, :password, :client_id)
|
20
23
|
super
|
21
24
|
end
|
22
25
|
|
23
26
|
def purchase(money, payment_method, options = {})
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
moment_less_than_24_hours_ago = Time.now - SECONDS_PER_DAY - BUFFER_TIME_IN_SECS
|
28
|
+
|
29
|
+
if options[:session_id] && options[:session_id][:created_at] >= moment_less_than_24_hours_ago
|
30
|
+
commit(purchase_request(money, payment_method, options[:session_id][:id], options), :response_transactionref)
|
31
|
+
else
|
32
|
+
MultiResponse.run do |r|
|
33
|
+
r.process { login }
|
34
|
+
r.process { commit(purchase_request(money, payment_method, r.params['response_sessionid'], options), :response_transactionref) }
|
35
|
+
end
|
27
36
|
end
|
28
37
|
end
|
29
38
|
|
@@ -27,6 +27,7 @@ module ActiveMerchant #:nodoc:
|
|
27
27
|
requires!(options, :private_key, :public_key)
|
28
28
|
@private_key = options[:private_key]
|
29
29
|
@public_key = options[:public_key]
|
30
|
+
@encryption_key = OpenSSL::PKey::RSA.new(options[:encryption_key]) if options[:encryption_key]
|
30
31
|
@shop_process_id = options[:shop_process_id] || SecureRandom.random_number(10**15)
|
31
32
|
super
|
32
33
|
end
|
@@ -114,15 +115,15 @@ module ActiveMerchant #:nodoc:
|
|
114
115
|
transcript.encode('UTF-8', 'binary', undef: :replace, replace: '')
|
115
116
|
end
|
116
117
|
|
117
|
-
private
|
118
|
-
|
119
118
|
# Required to encrypt PAN data.
|
120
119
|
def one_time_public_key
|
121
120
|
token = generate_token('get_encription_public_key', @public_key)
|
122
121
|
response = commit(:pci_encryption_key, token: token)
|
123
|
-
|
122
|
+
response.params['encryption_key']
|
124
123
|
end
|
125
124
|
|
125
|
+
private
|
126
|
+
|
126
127
|
def generate_token(*elements)
|
127
128
|
Digest::MD5.hexdigest(@private_key + elements.join)
|
128
129
|
end
|
@@ -138,7 +139,9 @@ module ActiveMerchant #:nodoc:
|
|
138
139
|
|
139
140
|
payload = { card_number: card_number, 'cvv': cvv }.to_json
|
140
141
|
|
141
|
-
|
142
|
+
encryption_key = @encryption_key || OpenSSL::PKey::RSA.new(one_time_public_key)
|
143
|
+
|
144
|
+
post[:card_encrypted_data] = JWE.encrypt(payload, encryption_key)
|
142
145
|
post[:card_month_expiration] = format(payment.month, :two_digits)
|
143
146
|
post[:card_year_expiration] = format(payment.year, :two_digits)
|
144
147
|
end
|
@@ -61,12 +61,16 @@ module ActiveMerchant #:nodoc:
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def refund(money, authorization, options = {})
|
64
|
-
post = { amount_in_cents: amount(money).to_i, transaction_id: authorization.to_s }
|
65
|
-
commit('refund', post, '/refunds_sync')
|
64
|
+
# post = { amount_in_cents: amount(money).to_i, transaction_id: authorization.to_s }
|
65
|
+
# commit('refund', post, '/refunds_sync')
|
66
|
+
|
67
|
+
# All refunds will instead be voided. This is temporary.
|
68
|
+
void(authorization, options, money)
|
66
69
|
end
|
67
70
|
|
68
|
-
def void(authorization, options = {})
|
69
|
-
|
71
|
+
def void(authorization, options = {}, money = nil)
|
72
|
+
post = money ? { amount_in_cents: amount(money).to_i } : {}
|
73
|
+
commit('void', post, "/transactions/#{authorization}/void_sync")
|
70
74
|
end
|
71
75
|
|
72
76
|
def supports_scrubbing?
|
@@ -144,6 +144,11 @@ module ActiveMerchant #:nodoc:
|
|
144
144
|
store_request(credit_card, options)
|
145
145
|
end
|
146
146
|
|
147
|
+
def inquire(authorization, options = {})
|
148
|
+
order_id = order_id_from_authorization(authorization.to_s) || options[:order_id]
|
149
|
+
commit('direct_inquiry', build_order_inquiry_request(order_id, options), :ok, options)
|
150
|
+
end
|
151
|
+
|
147
152
|
def supports_scrubbing
|
148
153
|
true
|
149
154
|
end
|
@@ -237,6 +242,7 @@ module ActiveMerchant #:nodoc:
|
|
237
242
|
add_sub_merchant_data(xml, options[:sub_merchant_data]) if options[:sub_merchant_data]
|
238
243
|
add_hcg_additional_data(xml, options) if options[:hcg_additional_data]
|
239
244
|
add_instalments_data(xml, options) if options[:instalments]
|
245
|
+
add_additional_data(xml, money, options) if options[:level_2_data] || options[:level_3_data]
|
240
246
|
add_moto_flag(xml, options) if options.dig(:metadata, :manual_entry)
|
241
247
|
add_additional_3ds_data(xml, options) if options[:execute_threed] && options[:three_ds_version] && options[:three_ds_version] =~ /^2/
|
242
248
|
add_3ds_exemption(xml, options) if options[:exemption_type]
|
@@ -245,6 +251,91 @@ module ActiveMerchant #:nodoc:
|
|
245
251
|
end
|
246
252
|
end
|
247
253
|
|
254
|
+
def add_additional_data(xml, amount, options)
|
255
|
+
level_two_data = options[:level_2_data] || {}
|
256
|
+
level_three_data = options[:level_3_data] || {}
|
257
|
+
level_two_and_three_data = level_two_data.merge(level_three_data).symbolize_keys
|
258
|
+
|
259
|
+
xml.branchSpecificExtension do
|
260
|
+
xml.purchase do
|
261
|
+
add_level_two_and_three_data(xml, amount, level_two_and_three_data)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def add_level_two_and_three_data(xml, amount, data)
|
267
|
+
xml.invoiceReferenceNumber data[:invoice_reference_number] if data.include?(:invoice_reference_number)
|
268
|
+
xml.customerReference data[:customer_reference] if data.include?(:customer_reference)
|
269
|
+
xml.cardAcceptorTaxId data[:card_acceptor_tax_id] if data.include?(:card_acceptor_tax_id)
|
270
|
+
|
271
|
+
{
|
272
|
+
sales_tax: 'salesTax',
|
273
|
+
discount_amount: 'discountAmount',
|
274
|
+
shipping_amount: 'shippingAmount',
|
275
|
+
duty_amount: 'dutyAmount'
|
276
|
+
}.each do |key, tag|
|
277
|
+
next unless data.include?(key)
|
278
|
+
|
279
|
+
xml.tag! tag do
|
280
|
+
data_amount = data[key].symbolize_keys
|
281
|
+
add_amount(xml, data_amount[:amount].to_i, data_amount)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
xml.discountName data[:discount_name] if data.include?(:discount_name)
|
286
|
+
xml.discountCode data[:discount_code] if data.include?(:discount_code)
|
287
|
+
|
288
|
+
add_date_element(xml, 'shippingDate', data[:shipping_date]) if data.include?(:shipping_date)
|
289
|
+
|
290
|
+
if data.include?(:shipping_courier)
|
291
|
+
xml.shippingCourier(
|
292
|
+
data[:shipping_courier][:priority],
|
293
|
+
data[:shipping_courier][:tracking_number],
|
294
|
+
data[:shipping_courier][:name]
|
295
|
+
)
|
296
|
+
end
|
297
|
+
|
298
|
+
add_optional_data_level_two_and_three(xml, data)
|
299
|
+
|
300
|
+
if data.include?(:item) && data[:item].kind_of?(Array)
|
301
|
+
data[:item].each { |item| add_items_into_level_three_data(xml, item.symbolize_keys) }
|
302
|
+
elsif data.include?(:item)
|
303
|
+
add_items_into_level_three_data(xml, data[:item].symbolize_keys)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def add_items_into_level_three_data(xml, item)
|
308
|
+
xml.item do
|
309
|
+
xml.description item[:description] if item[:description]
|
310
|
+
xml.productCode item[:product_code] if item[:product_code]
|
311
|
+
xml.commodityCode item[:commodity_code] if item[:commodity_code]
|
312
|
+
xml.quantity item[:quantity] if item[:quantity]
|
313
|
+
|
314
|
+
{
|
315
|
+
unit_cost: 'unitCost',
|
316
|
+
item_total: 'itemTotal',
|
317
|
+
item_total_with_tax: 'itemTotalWithTax',
|
318
|
+
item_discount_amount: 'itemDiscountAmount',
|
319
|
+
tax_amount: 'taxAmount'
|
320
|
+
}.each do |key, tag|
|
321
|
+
next unless item.include?(key)
|
322
|
+
|
323
|
+
xml.tag! tag do
|
324
|
+
data_amount = item[key].symbolize_keys
|
325
|
+
add_amount(xml, data_amount[:amount].to_i, data_amount)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def add_optional_data_level_two_and_three(xml, data)
|
332
|
+
xml.shipFromPostalCode data[:ship_from_postal_code] if data.include?(:ship_from_postal_code)
|
333
|
+
xml.destinationPostalCode data[:destination_postal_code] if data.include?(:destination_postal_code)
|
334
|
+
xml.destinationCountryCode data[:destination_country_code] if data.include?(:destination_country_code)
|
335
|
+
add_date_element(xml, 'orderDate', data[:order_date].symbolize_keys) if data.include?(:order_date)
|
336
|
+
xml.taxExempt data[:tax_exempt] if data.include?(:tax_exempt)
|
337
|
+
end
|
338
|
+
|
248
339
|
def order_tag_attributes(options)
|
249
340
|
{ 'orderCode' => clean_order_id(options[:order_id]), 'installationId' => options[:inst_id] || @options[:inst_id] }.reject { |_, v| !v.present? }
|
250
341
|
end
|
@@ -592,7 +683,8 @@ module ActiveMerchant #:nodoc:
|
|
592
683
|
'year' => format(payment_method.year, :four_digits_year)
|
593
684
|
)
|
594
685
|
end
|
595
|
-
|
686
|
+
name = card_holder_name(payment_method, options)
|
687
|
+
xml.cardHolderName name if name.present?
|
596
688
|
xml.cvc payment_method.verification_value
|
597
689
|
|
598
690
|
add_address(xml, (options[:billing_address] || options[:address]), options)
|
@@ -718,9 +810,18 @@ module ActiveMerchant #:nodoc:
|
|
718
810
|
resp_params = { action: action }
|
719
811
|
|
720
812
|
parse_elements(doc.root, resp_params)
|
813
|
+
extract_issuer_response(doc.root, resp_params)
|
814
|
+
|
721
815
|
resp_params
|
722
816
|
end
|
723
817
|
|
818
|
+
def extract_issuer_response(doc, response)
|
819
|
+
return unless issuer_response = doc.at_xpath('//paymentService//reply//orderStatus//payment//IssuerResponseCode')
|
820
|
+
|
821
|
+
response[:issuer_response_code] = issuer_response['code']
|
822
|
+
response[:issuer_response_description] = issuer_response['description']
|
823
|
+
end
|
824
|
+
|
724
825
|
def parse_elements(node, response)
|
725
826
|
node_name = node.name.underscore
|
726
827
|
node.attributes.each do |k, v|
|
@@ -743,9 +844,11 @@ module ActiveMerchant #:nodoc:
|
|
743
844
|
'Content-Type' => 'text/xml',
|
744
845
|
'Authorization' => encoded_credentials
|
745
846
|
}
|
746
|
-
|
747
|
-
|
748
|
-
|
847
|
+
|
848
|
+
# ensure cookie included on follow-up '3ds' and 'capture_request' calls, using the cookie saved from the preceding response
|
849
|
+
# cookie should be present in options on the 3ds and capture calls, but also still saved in the instance var in case
|
850
|
+
cookie = options[:cookie] || @cookie || nil
|
851
|
+
headers['Cookie'] = cookie if cookie
|
749
852
|
|
750
853
|
headers['Idempotency-Key'] = idempotency_key if idempotency_key
|
751
854
|
headers
|
@@ -761,7 +864,7 @@ module ActiveMerchant #:nodoc:
|
|
761
864
|
raw[:is3DSOrder] = true
|
762
865
|
end
|
763
866
|
success = success_from(action, raw, success_criteria)
|
764
|
-
message = message_from(success, raw, success_criteria)
|
867
|
+
message = message_from(success, raw, success_criteria, action)
|
765
868
|
|
766
869
|
Response.new(
|
767
870
|
success,
|
@@ -798,7 +901,8 @@ module ActiveMerchant #:nodoc:
|
|
798
901
|
def handle_response(response)
|
799
902
|
case response.code.to_i
|
800
903
|
when 200...300
|
801
|
-
|
904
|
+
cookie = response.header['Set-Cookie']&.match('^[^;]*')
|
905
|
+
@cookie = cookie[0] if cookie
|
802
906
|
response.body
|
803
907
|
else
|
804
908
|
raise ResponseError.new(response)
|
@@ -809,10 +913,10 @@ module ActiveMerchant #:nodoc:
|
|
809
913
|
success_criteria_success?(raw, success_criteria) || action_success?(action, raw)
|
810
914
|
end
|
811
915
|
|
812
|
-
def message_from(success, raw, success_criteria)
|
916
|
+
def message_from(success, raw, success_criteria, action)
|
813
917
|
return 'SUCCESS' if success
|
814
918
|
|
815
|
-
raw[:iso8583_return_code_description] || raw[:error] || required_status_message(raw, success_criteria)
|
919
|
+
raw[:iso8583_return_code_description] || raw[:error] || required_status_message(raw, success_criteria, action) || raw[:issuer_response_description]
|
816
920
|
end
|
817
921
|
|
818
922
|
# success_criteria can be:
|
@@ -829,6 +933,8 @@ module ActiveMerchant #:nodoc:
|
|
829
933
|
case action
|
830
934
|
when 'store'
|
831
935
|
raw[:token].present?
|
936
|
+
when 'direct_inquiry'
|
937
|
+
raw[:last_event].present?
|
832
938
|
else
|
833
939
|
false
|
834
940
|
end
|
@@ -838,8 +944,11 @@ module ActiveMerchant #:nodoc:
|
|
838
944
|
raw[:iso8583_return_code_code] || raw[:error_code] || nil unless success == 'SUCCESS'
|
839
945
|
end
|
840
946
|
|
841
|
-
def required_status_message(raw, success_criteria)
|
842
|
-
|
947
|
+
def required_status_message(raw, success_criteria, action)
|
948
|
+
return if success_criteria.include?(raw[:last_event])
|
949
|
+
return unless %w[cancel refund inquiry credit fast_credit].include?(action)
|
950
|
+
|
951
|
+
"A transaction status of #{success_criteria.collect { |c| "'#{c}'" }.join(' or ')} is required."
|
843
952
|
end
|
844
953
|
|
845
954
|
def authorization_from(action, raw, options)
|
@@ -887,13 +996,19 @@ module ActiveMerchant #:nodoc:
|
|
887
996
|
case payment_method
|
888
997
|
when String
|
889
998
|
token_type_and_details(payment_method)
|
890
|
-
when NetworkTokenizationCreditCard
|
891
|
-
{ payment_type: :network_token }
|
892
999
|
else
|
893
|
-
|
1000
|
+
type = network_token?(payment_method) ? :network_token : :credit
|
1001
|
+
|
1002
|
+
{ payment_type: type }
|
894
1003
|
end
|
895
1004
|
end
|
896
1005
|
|
1006
|
+
def network_token?(payment_method)
|
1007
|
+
payment_method.respond_to?(:source) &&
|
1008
|
+
payment_method.respond_to?(:payment_cryptogram) &&
|
1009
|
+
payment_method.respond_to?(:eci)
|
1010
|
+
end
|
1011
|
+
|
897
1012
|
def token_type_and_details(token)
|
898
1013
|
token_details = token_details_from_authorization(token)
|
899
1014
|
token_details[:payment_type] = token_details.has_key?(:token_id) ? :token : :pay_as_order
|
@@ -85,7 +85,21 @@ module ActiveMerchant #:nodoc:
|
|
85
85
|
(primary_response ? primary_response.success? : true)
|
86
86
|
end
|
87
87
|
|
88
|
-
|
88
|
+
def avs_result
|
89
|
+
return @primary_response.try(:avs_result) if @use_first_response
|
90
|
+
|
91
|
+
result = responses.reverse.find { |r| r.avs_result['code'].present? }
|
92
|
+
result.try(:avs_result) || responses.last.try(:avs_result)
|
93
|
+
end
|
94
|
+
|
95
|
+
def cvv_result
|
96
|
+
return @primary_response.try(:cvv_result) if @use_first_response
|
97
|
+
|
98
|
+
result = responses.reverse.find { |r| r.cvv_result['code'].present? }
|
99
|
+
result.try(:cvv_result) || responses.last.try(:cvv_result)
|
100
|
+
end
|
101
|
+
|
102
|
+
%w(params message test authorization error_code emv_authorization test? fraud_review?).each do |m|
|
89
103
|
class_eval %(
|
90
104
|
def #{m}
|
91
105
|
(@responses.empty? ? nil : primary_response.#{m})
|
@@ -184,6 +184,7 @@ module ActiveMerchant #:nodoc:
|
|
184
184
|
{ alpha2: 'KP', name: 'Korea, Democratic People\'s Republic of', alpha3: 'PRK', numeric: '408' },
|
185
185
|
{ alpha2: 'KR', name: 'Korea, Republic of', alpha3: 'KOR', numeric: '410' },
|
186
186
|
{ alpha2: 'XK', name: 'Kosovo', alpha3: 'XKX', numeric: '900' },
|
187
|
+
{ alpha2: 'QZ', name: 'Kosovo', alpha3: 'XKX', numeric: '900' },
|
187
188
|
{ alpha2: 'KW', name: 'Kuwait', alpha3: 'KWT', numeric: '414' },
|
188
189
|
{ alpha2: 'KG', name: 'Kyrgyzstan', alpha3: 'KGZ', numeric: '417' },
|
189
190
|
{ alpha2: 'LA', name: 'Lao People\'s Democratic Republic', alpha3: 'LAO', numeric: '418' },
|
@@ -23,10 +23,13 @@ module ActiveMerchant #:nodoc:
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def to_s
|
26
|
-
"Failed with #{response.code} #{response.message if response.respond_to?(:message)}"
|
26
|
+
"Failed with #{response.code if response.respond_to?(:code)} #{response.message if response.respond_to?(:message)}"
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
+
class OAuthResponseError < ResponseError # :nodoc:
|
31
|
+
end
|
32
|
+
|
30
33
|
class ClientCertificateError < ActiveMerchantError # :nodoc
|
31
34
|
end
|
32
35
|
|