Skip to content

Commit

Permalink
Nuvei: Add 3DS Global
Browse files Browse the repository at this point in the history
Description
-------------------------
 This commit enable 3ds Global for Nuvei

Unit test
-------------------------
Finished in 1.229216 seconds.

19 tests, 98 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed

15.46 tests/s, 79.73 assertions/s

Remote test
-------------------------
Finished in 106.016738 seconds.

30 tests, 99 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed

0.28 tests/s, 0.93 assertions/s

Rubocop
-------------------------
801 files inspected, no offenses detected
  • Loading branch information
Javier Pedroza committed Oct 15, 2024
1 parent d579b24 commit 5f83d5d
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 0 deletions.
23 changes: 23 additions & 0 deletions lib/active_merchant/billing/gateways/nuvei.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def authorize(money, payment, options = {}, transaction_type = 'Auth')
build_post_data(post)
add_amount(post, money, options)
add_payment_method(post, payment, :paymentOption, options)
add_3ds_global(post, options)
add_address(post, payment, options)
add_customer_ip(post, options)
add_stored_credentials(post, payment, options)
Expand Down Expand Up @@ -204,6 +205,28 @@ def add_customer_names(full_name, payment_method)
end
end

def add_3ds_global(post, options)
return unless (three_d_secure_options = options[:three_d_secure])

card_options = post[:paymentOption][:card] ||= {}
card_options[:threeD] = build_three_d_secure_options(three_d_secure_options, options)
end

def build_three_d_secure_options(three_d_secure_options, options)
three_d_secure_data = {
externalMpi: {
eci: three_d_secure_options[:eci],
cavv: three_d_secure_options[:cavv],
dsTransID: three_d_secure_options[:ds_transaction_id],
challenge_preference: options[:challenge_preference]
}
}.compact

three_d_secure_data[:externalMpi][:exemptionRequestReason] = options[:exemption_request_reason] if options[:challenge_preference] == 'ExemptionRequest'

three_d_secure_data
end

def add_address(post, payment, options)
return unless address = options[:billing_address] || options[:address]

Expand Down
33 changes: 33 additions & 0 deletions test/remote/gateways/remote_nuvei_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def setup
@challenge_credit_card = credit_card('2221008123677736', first_name: 'CL-BRW2', last_name: '')
@three_ds_amount = 151 # for challenge = 151, for frictionless >= 150
@frictionless_credit_card = credit_card('4000020951595032', first_name: 'FL-BRW2', last_name: '')
@credit_card_3ds = credit_card('4000020951595032')

@options = {
email: '[email protected]',
Expand Down Expand Up @@ -38,6 +39,14 @@ def setup
}
}
}

@three_d_secure_options = @options.merge({
three_d_secure: {
cavv: 'jJ81HADVRtXfCBATEp01CJUAAAA=',
ds_transaction_id: '97267598-FAE6-48F2-8083-C23433990FBC',
eci: '05'
}
})
end

def test_transcript_scrubbing
Expand Down Expand Up @@ -269,4 +278,28 @@ def test_purchase_using_stored_credentials_merchant_installments_cit
assert_success recurring_response
assert_match 'SUCCESS', recurring_response.params['status']
end

def test_failing_purchase_three_d_secure
@three_d_secure_options[:three_d_secure][:cavv] = 'wrong_cavv_value'
assert response = @gateway.purchase(@amount, @credit_card_3ds, @three_d_secure_options)
assert_failure response
assert_equal 'UNEXPECTED SYSTEM ERROR - PLEASE RETRY LATER', response.message
assert_match 'ERROR', response.params['transactionStatus']
end

def test_successful_purchase_with_three_d_secure
assert response = @gateway.purchase(@amount, @credit_card_3ds, @three_d_secure_options)
assert_success response
assert response.authorization
assert_equal 'APPROVED', response.message
assert_match 'SUCCESS', response.params['status']
end

def test_successful_purchase_three_d_secure_challenge_preference
assert response = @gateway.purchase(@amount, @credit_card_3ds, @three_d_secure_options.merge(challenge_preference: 'ExemptionRequest', exemption_request_reason: 'AccountVerification'))
assert_success response
assert_equal 'APPROVED', response.message
assert_match 'SUCCESS', response.params['status']
assert response.authorization
end
end
32 changes: 32 additions & 0 deletions test/unit/gateways/nuvei_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ def setup
}
}

@three_d_secure_options = @options.merge({
three_d_secure: {
cavv: 'jJ81HADVRtXfCBATEp01CJUAAAA=',
ds_transaction_id: '97267598-FAE6-48F2-8083-C23433990FBC',
eci: '05'
}
})

@post = {
merchantId: 'test_merchant_id',
merchantSiteId: 'test_merchant_site_id',
Expand Down Expand Up @@ -251,6 +259,30 @@ def test_successful_stored_credentials_merchant_recurring
end.respond_with(successful_purchase_response)
end

def test_add_3ds_global_params
stub_comms do
@gateway.authorize(@amount, @credit_card, @three_d_secure_options)
end.check_request do |_method, _endpoint, data, _headers|
assert_equal 'jJ81HADVRtXfCBATEp01CJUAAAA', JSON.parse(data)['threeD']['cavv']
assert_equal '97267598-FAE6-48F2-8083-C23433990FBC', JSON.parse(data)['threeD']['dsTransactionId']
assert_equal '05', JSON.parse(data)['threeD']['eci']
end.respond_with(successful_authorize_response)
end

def test_add_3ds_global_params_with_challenge_preference
chellange_preference_params = {
challenge_preference: 'ExemptionRequest',
exemption_request_reason: 'AccountVerification'
}

stub_comms do
@gateway.purchase(@amount, @credit_card, @three_d_secure_options.merge(chellange_preference_params))
end.check_request(skip_response: true) do |_method, _endpoint, data, _headers|
assert_equal 'ExemptionRequest', JSON.parse(data)['threeD']['externalMpi']['challenge_preference']
assert_equal 'AccountVerification', JSON.parse(data)['threeD']['externalMpi']['exemptionRequestReason']
end
end

private

def three_ds_assertions(payment_option_card)
Expand Down

0 comments on commit 5f83d5d

Please sign in to comment.