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

Kushki: Enable 3ds2 #4832

Closed
wants to merge 1 commit into from
Closed
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
40 changes: 36 additions & 4 deletions lib/active_merchant/billing/gateways/kushki.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ def initialize(options = {})
def purchase(amount, payment_method, options = {})
MultiResponse.run() do |r|
r.process { tokenize(amount, payment_method, options) }
r.process { charge(amount, r.authorization, options) }
r.process { charge(amount, r.authorization, options, payment_method) }
end
end

def authorize(amount, payment_method, options = {})
MultiResponse.run() do |r|
r.process { tokenize(amount, payment_method, options) }
r.process { preauthorize(amount, r.authorization, options) }
r.process { preauthorize(amount, r.authorization, options, payment_method) }
end
end

Expand Down Expand Up @@ -89,7 +89,7 @@ def tokenize(amount, payment_method, options)
commit(action, post)
end

def charge(amount, authorization, options)
def charge(amount, authorization, options, payment_method = {})
action = 'charge'

post = {}
Expand All @@ -100,11 +100,12 @@ def charge(amount, authorization, options)
add_metadata(post, options)
add_months(post, options)
add_deferred(post, options)
add_three_d_secure(post, payment_method, options)

commit(action, post)
end

def preauthorize(amount, authorization, options)
def preauthorize(amount, authorization, options, payment_method = {})
action = 'preAuthorization'

post = {}
Expand All @@ -114,6 +115,7 @@ def preauthorize(amount, authorization, options)
add_metadata(post, options)
add_months(post, options)
add_deferred(post, options)
add_three_d_secure(post, payment_method, options)

commit(action, post)
end
Expand Down Expand Up @@ -204,6 +206,36 @@ def add_deferred(post, options)
}
end

def add_three_d_secure(post, payment_method, options)
three_d_secure = options[:three_d_secure]
return unless three_d_secure.present?

post[:threeDomainSecure] = {
eci: three_d_secure[:eci],
specificationVersion: three_d_secure[:version]
}

if payment_method.brand == 'master'
post[:threeDomainSecure][:acceptRisk] = three_d_secure[:eci] == '00'
post[:threeDomainSecure][:ucaf] = three_d_secure[:cavv]
post[:threeDomainSecure][:directoryServerTransactionID] = three_d_secure[:ds_transaction_id]
case three_d_secure[:eci]
when '07'
post[:threeDomainSecure][:collectionIndicator] = '0'
when '06'
post[:threeDomainSecure][:collectionIndicator] = '1'
else
post[:threeDomainSecure][:collectionIndicator] = '2'
end
elsif payment_method.brand == 'visa'
post[:threeDomainSecure][:acceptRisk] = three_d_secure[:eci] == '07'
post[:threeDomainSecure][:cavv] = three_d_secure[:cavv]
post[:threeDomainSecure][:xid] = three_d_secure[:xid]
else
raise ArgumentError.new 'Kushki supports 3ds2 authentication for only Visa and Mastercard brands.'
end
end

ENDPOINT = {
'tokenize' => 'tokens',
'charge' => 'charges',
Expand Down
80 changes: 80 additions & 0 deletions test/remote/gateways/remote_kushki_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,86 @@ def test_failed_authorize
assert_equal 'Monto de la transacción es diferente al monto de la venta inicial', response.message
end

def test_successful_3ds2_authorize_with_visa_card
options = {
currency: 'PEN',
three_d_secure: {
version: '2.2.0',
cavv: 'AAABBoVBaZKAR3BkdkFpELpWIiE=',
xid: 'NEpab1F1MEdtaWJ2bEY3ckYxQzE=',
eci: '07'
}
}
response = @gateway.authorize(@amount, @credit_card, options)
assert_success response
assert_equal 'Succeeded', response.message
assert_match %r(^\d+$), response.authorization
end

def test_successful_3ds2_authorize_with_master_card
options = {
currency: 'PEN',
three_d_secure: {
version: '2.2.0',
cavv: 'AAABBoVBaZKAR3BkdkFpELpWIiE=',
eci: '00',
ds_transaction_id: 'b23e0264-1209-41L6-Jca4-b82143c1a782'
}
}

credit_card = credit_card('5223450000000007', brand: 'master', verification_value: '777')
response = @gateway.authorize(@amount, credit_card, options)
assert_success response
assert_equal 'Succeeded', response.message
end

def test_successful_3ds2_purchase
options = {
three_d_secure: {
version: '2.2.0',
cavv: 'AAABBoVBaZKAR3BkdkFpELpWIiE=',
xid: 'NEpab1F1MEdtaWJ2bEY3ckYxQzE=',
eci: '07'
}
}

response = @gateway.purchase(@amount, @credit_card, options)

assert_success response
assert_equal 'Succeeded', response.message
assert_match %r(^\d+$), response.authorization
end

def test_failed_3ds2_authorize
options = {
currency: 'PEN',
three_d_secure: {
version: '2.2.0',
authentication_response_status: 'Y',
cavv: 'AAABBoVBaZKAR3BkdkFpELpWIiE=',
xid: 'NEpab1F1MEdtaWJ2bEY3ckYxQzE='
}
}
response = @gateway.authorize(@amount, @credit_card, options)
assert_failure response
assert_equal 'K001', response.responses.last.error_code
end

def test_failed_3ds2_authorize_with_different_card
options = {
currency: 'PEN',
three_d_secure: {
version: '2.2.0',
cavv: 'AAABBoVBaZKAR3BkdkFpELpWIiE=',
xid: 'NEpab1F1MEdtaWJ2bEY3ckYxQzE='
}
}
credit_card = credit_card('6011111111111117', brand: 'discover', verification_value: '777')
assert_raise ArgumentError do
@gateway.authorize(@amount, credit_card, options)
end
end

def test_successful_capture
auth = @gateway.authorize(@amount, @credit_card)
assert_success auth
Expand Down
Loading