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.
- checksums.yaml +4 -4
- data/CHANGELOG +241 -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 +79 -23
- data/lib/active_merchant/billing/gateways/adyen.rb +67 -8
- 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 +21 -4
- 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 +56 -16
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +64 -17
- 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 +228 -57
- data/lib/active_merchant/billing/gateways/commerce_hub.rb +361 -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 +100 -26
- data/lib/active_merchant/billing/gateways/cyber_source_rest.rb +456 -0
- data/lib/active_merchant/billing/gateways/d_local.rb +44 -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 +73 -22
- 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/paysafe.rb +22 -14
- data/lib/active_merchant/billing/gateways/payu_latam.rb +3 -0
- 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 +9 -5
- 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 +342 -0
- data/lib/active_merchant/billing/gateways/simetrik.rb +28 -22
- data/lib/active_merchant/billing/gateways/stripe.rb +21 -1
- 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 +117 -9
- 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
|
@@ -718,9 +809,18 @@ module ActiveMerchant #:nodoc:
|
|
718
809
|
resp_params = { action: action }
|
719
810
|
|
720
811
|
parse_elements(doc.root, resp_params)
|
812
|
+
extract_issuer_response(doc.root, resp_params)
|
813
|
+
|
721
814
|
resp_params
|
722
815
|
end
|
723
816
|
|
817
|
+
def extract_issuer_response(doc, response)
|
818
|
+
return unless issuer_response = doc.at_xpath('//paymentService//reply//orderStatus//payment//IssuerResponseCode')
|
819
|
+
|
820
|
+
response[:issuer_response_code] = issuer_response['code']
|
821
|
+
response[:issuer_response_description] = issuer_response['description']
|
822
|
+
end
|
823
|
+
|
724
824
|
def parse_elements(node, response)
|
725
825
|
node_name = node.name.underscore
|
726
826
|
node.attributes.each do |k, v|
|
@@ -743,9 +843,11 @@ module ActiveMerchant #:nodoc:
|
|
743
843
|
'Content-Type' => 'text/xml',
|
744
844
|
'Authorization' => encoded_credentials
|
745
845
|
}
|
746
|
-
|
747
|
-
|
748
|
-
|
846
|
+
|
847
|
+
# ensure cookie included on follow-up '3ds' and 'capture_request' calls, using the cookie saved from the preceding response
|
848
|
+
# cookie should be present in options on the 3ds and capture calls, but also still saved in the instance var in case
|
849
|
+
cookie = options[:cookie] || @cookie || nil
|
850
|
+
headers['Cookie'] = cookie if cookie
|
749
851
|
|
750
852
|
headers['Idempotency-Key'] = idempotency_key if idempotency_key
|
751
853
|
headers
|
@@ -761,7 +863,7 @@ module ActiveMerchant #:nodoc:
|
|
761
863
|
raw[:is3DSOrder] = true
|
762
864
|
end
|
763
865
|
success = success_from(action, raw, success_criteria)
|
764
|
-
message = message_from(success, raw, success_criteria)
|
866
|
+
message = message_from(success, raw, success_criteria, action)
|
765
867
|
|
766
868
|
Response.new(
|
767
869
|
success,
|
@@ -798,7 +900,8 @@ module ActiveMerchant #:nodoc:
|
|
798
900
|
def handle_response(response)
|
799
901
|
case response.code.to_i
|
800
902
|
when 200...300
|
801
|
-
|
903
|
+
cookie = response.header['Set-Cookie']&.match('^[^;]*')
|
904
|
+
@cookie = cookie[0] if cookie
|
802
905
|
response.body
|
803
906
|
else
|
804
907
|
raise ResponseError.new(response)
|
@@ -809,10 +912,10 @@ module ActiveMerchant #:nodoc:
|
|
809
912
|
success_criteria_success?(raw, success_criteria) || action_success?(action, raw)
|
810
913
|
end
|
811
914
|
|
812
|
-
def message_from(success, raw, success_criteria)
|
915
|
+
def message_from(success, raw, success_criteria, action)
|
813
916
|
return 'SUCCESS' if success
|
814
917
|
|
815
|
-
raw[:iso8583_return_code_description] || raw[:error] || required_status_message(raw, success_criteria)
|
918
|
+
raw[:iso8583_return_code_description] || raw[:error] || required_status_message(raw, success_criteria, action) || raw[:issuer_response_description]
|
816
919
|
end
|
817
920
|
|
818
921
|
# success_criteria can be:
|
@@ -829,6 +932,8 @@ module ActiveMerchant #:nodoc:
|
|
829
932
|
case action
|
830
933
|
when 'store'
|
831
934
|
raw[:token].present?
|
935
|
+
when 'direct_inquiry'
|
936
|
+
raw[:last_event].present?
|
832
937
|
else
|
833
938
|
false
|
834
939
|
end
|
@@ -838,8 +943,11 @@ module ActiveMerchant #:nodoc:
|
|
838
943
|
raw[:iso8583_return_code_code] || raw[:error_code] || nil unless success == 'SUCCESS'
|
839
944
|
end
|
840
945
|
|
841
|
-
def required_status_message(raw, success_criteria)
|
842
|
-
|
946
|
+
def required_status_message(raw, success_criteria, action)
|
947
|
+
return if success_criteria.include?(raw[:last_event])
|
948
|
+
return unless %w[cancel refund inquiry credit fast_credit].include?(action)
|
949
|
+
|
950
|
+
"A transaction status of #{success_criteria.collect { |c| "'#{c}'" }.join(' or ')} is required."
|
843
951
|
end
|
844
952
|
|
845
953
|
def authorization_from(action, raw, options)
|
@@ -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
|
|