Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adyen: Set 3DS exemptions via API #3331

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
= ActiveMerchant CHANGELOG

== HEAD
* Adyen: Add functionality to set 3DS exemptions via API [britth] #3331

== Version 1.98.0 (Sep 9, 2019)
* Stripe Payment Intents: Add new gateway [britth] #3290
* Stripe: Send cardholder name and address when creating sources for 3DS 1.0 [jknipp] #3300
Expand Down
5 changes: 5 additions & 0 deletions lib/active_merchant/billing/gateways/adyen.rb
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,11 @@ def add_3ds(post, options)
add_browser_info(three_ds_2_options[:browser_info], post)
post[:threeDS2RequestData] = { deviceChannel: device_channel, notificationURL: three_ds_2_options[:notification_url] }
end

if options.has_key?(:execute_threed)
post[:additionalData][:executeThreeD] = options[:execute_threed]
post[:additionalData][:scaExemption] = options[:sca_exemption] if options[:sca_exemption]
end
else
return unless options[:execute_threed] || options[:threed_dynamic]
post[:browserInfo] = { userAgent: options[:user_agent], acceptHeader: options[:accept_header] }
Expand Down
24 changes: 23 additions & 1 deletion test/remote/gateways/remote_adyen_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def setup
:brand => 'elo'
)

@three_ds_enrolled_card = credit_card('4917610000000000', brand: :visa)
@three_ds_enrolled_card = credit_card('4917610000000000', month: 10, year: 2020, verification_value: '737', brand: :visa)

@declined_card = credit_card('4000300011112220')

Expand Down Expand Up @@ -165,6 +165,28 @@ def test_successful_authorize_with_3ds2_browser_client_data
refute response.params['additionalData']['threeds2.threeDSMethodURL'].blank?
end

def test_successful_purchase_with_3ds2_exemption_requested_and_execute_threed_false
assert response = @gateway.authorize(@amount, @three_ds_enrolled_card, @normalized_3ds_2_options.merge(execute_threed: false, sca_exemption: 'lowValue'))
assert response.test?
refute response.authorization.blank?

assert_equal response.params['resultCode'], 'Authorised'
end

# According to Adyen documentation, if execute_threed is set to true and an exemption provided
# the gateway will apply and request for the specified exemption in the authentication request,
# after the device fingerprint is submitted to the issuer.
def test_successful_purchase_with_3ds2_exemption_requested_and_execute_threed_true
assert response = @gateway.authorize(@amount, @three_ds_enrolled_card, @normalized_3ds_2_options.merge(execute_threed: true, sca_exemption: 'lowValue'))
assert response.test?
refute response.authorization.blank?

assert_equal response.params['resultCode'], 'IdentifyShopper'
refute response.params['additionalData']['threeds2.threeDS2Token'].blank?
refute response.params['additionalData']['threeds2.threeDSServerTransID'].blank?
refute response.params['additionalData']['threeds2.threeDSMethodURL'].blank?
end

def test_successful_authorize_with_3ds2_app_based_request
three_ds_app_based_options = {
reference: '345123',
Expand Down
54 changes: 54 additions & 0 deletions test/unit/gateways/adyen_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,60 @@ def test_custom_routing_sent
end.respond_with(successful_authorize_response)
end

def test_execute_threed_false_sent_3ds2
stub_comms do
@gateway.authorize(@amount, '123', @normalized_3ds_2_options.merge({execute_threed: false}))
end.check_request do |endpoint, data, headers|
refute JSON.parse(data)['additionalData']['scaExemption']
assert_false JSON.parse(data)['additionalData']['executeThreeD']
end.respond_with(successful_authorize_response)
end

def test_sca_exemption_not_sent_if_execute_threed_missing_3ds2
stub_comms do
@gateway.authorize(@amount, '123', @normalized_3ds_2_options.merge({scaExemption: 'lowValue'}))
end.check_request do |endpoint, data, headers|
refute JSON.parse(data)['additionalData']['scaExemption']
refute JSON.parse(data)['additionalData']['executeThreeD']
end.respond_with(successful_authorize_response)
end

def test_sca_exemption_and_execute_threed_false_sent_3ds2
stub_comms do
@gateway.authorize(@amount, '123', @normalized_3ds_2_options.merge({sca_exemption: 'lowValue', execute_threed: false}))
end.check_request do |endpoint, data, headers|
assert_equal 'lowValue', JSON.parse(data)['additionalData']['scaExemption']
assert_false JSON.parse(data)['additionalData']['executeThreeD']
end.respond_with(successful_authorize_response)
end

def test_sca_exemption_and_execute_threed_true_sent_3ds2
stub_comms do
@gateway.authorize(@amount, '123', @normalized_3ds_2_options.merge({sca_exemption: 'lowValue', execute_threed: true}))
end.check_request do |endpoint, data, headers|
assert_equal 'lowValue', JSON.parse(data)['additionalData']['scaExemption']
assert JSON.parse(data)['additionalData']['executeThreeD']
end.respond_with(successful_authorize_response)
end

def test_sca_exemption_not_sent_when_execute_threed_true_3ds1
stub_comms do
@gateway.authorize(@amount, '123', @options.merge({sca_exemption: 'lowValue', execute_threed: true}))
end.check_request do |endpoint, data, headers|
refute JSON.parse(data)['additionalData']['scaExemption']
assert JSON.parse(data)['additionalData']['executeThreeD']
end.respond_with(successful_authorize_response)
end

def test_sca_exemption_not_sent_when_execute_threed_false_3ds1
stub_comms do
@gateway.authorize(@amount, '123', @options.merge({sca_exemption: 'lowValue', execute_threed: false}))
end.check_request do |endpoint, data, headers|
refute JSON.parse(data)['additionalData']['scaExemption']
refute JSON.parse(data)['additionalData']['executeThreeD']
end.respond_with(successful_authorize_response)
end

def test_update_shopper_statement_and_industry_usage_sent
stub_comms do
@gateway.adjust(@amount, '123', @options.merge({update_shopper_statement: 'statement note', industry_usage: 'DelayedCharge'}))
Expand Down