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

Ebanx: Add support for Stored Credentials #5243

Merged
merged 1 commit into from
Sep 11, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
* Iveri: Add AuthorisationReversal for Auth Void [almalee24] #5233
* Stripe PI: Update Stored Credentials [almalee24] #5236
* Checkout V2: Update stored credential options function [jherreraa] #5239
* Ebanx: Add support for Stored Credentials [almalee24] #5243

== Version 1.137.0 (August 2, 2024)
* Unlock dependency on `rexml` to allow fixing a CVE (#5181).
Expand Down
24 changes: 24 additions & 0 deletions lib/active_merchant/billing/gateways/ebanx.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def purchase(money, payment, options = {})
add_address(post, options)
add_customer_responsible_person(post, payment, options)
add_additional_data(post, options)
add_stored_credentials(post, options)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purchase and authorize methods are almost the same, I think it would be good to take advantage of the opportunity we have now to abstract the entire post population into a new method.


commit(:purchase, post)
end
Expand All @@ -64,6 +65,7 @@ def authorize(money, payment, options = {})
add_address(post, options)
add_customer_responsible_person(post, payment, options)
add_additional_data(post, options)
add_stored_credentials(post, options)
post[:payment][:creditcard][:auto_capture] = false

commit(:authorize, post)
Expand Down Expand Up @@ -168,6 +170,28 @@ def add_customer_responsible_person(post, payment, options)
end
end

def add_stored_credentials(post, options)
return unless (stored_creds = options[:stored_credential])

post[:cof_info] = {
cof_type: stored_creds[:initial_transaction] ? 'initial' : 'stored',
initiator: stored_creds[:initiator] == 'cardholder' ? 'CIT' : 'MIT',
trans_type: add_trans_type(stored_creds),
mandate_id: stored_creds[:network_transaction_id]
}.compact
end

def add_trans_type(options)
case options[:reason_type]
when 'recurring'
'SCHEDULED_RECURRING'
when 'installment'
'INSTALLMENT'
else
options[:initiator] == 'cardholder' ? 'CUSTOMER_COF' : 'MERCHANT_COF'
end
end

def add_address(post, options)
if address = options[:billing_address] || options[:address]
post[:payment][:address] = address[:address1].split[1..-1].join(' ') if address[:address1]
Expand Down
92 changes: 92 additions & 0 deletions test/remote/gateways/remote_ebanx_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -344,4 +344,96 @@ def test_successful_purchase_with_long_order_id
assert_success response
assert_equal 'Accepted', response.message
end

def test_successful_purchase_with_stored_credentials_cardholder_recurring
options = @options.merge!({
stored_credential: {
initial_transaction: true,
initiator: 'cardholder',
reason_type: 'recurring',
network_transaction_id: nil
}
})
response = @gateway.purchase(@amount, @credit_card, options)
assert_success response
end

def test_successful_purchase_with_stored_credentials_cardholder_unscheduled
options = @options.merge!({
stored_credential: {
initial_transaction: true,
initiator: 'cardholder',
reason_type: 'unscheduled',
network_transaction_id: nil
}
})
response = @gateway.purchase(@amount, @credit_card, options)
assert_success response
end

def test_successful_purchase_with_stored_credentials_cardholder_installment
options = @options.merge!({
stored_credential: {
initial_transaction: true,
initiator: 'cardholder',
reason_type: 'installment',
network_transaction_id: nil
}
})
response = @gateway.purchase(@amount, @credit_card, options)
assert_success response
end

def test_successful_purchase_with_stored_credentials_merchant_installment
options = @options.merge!({
stored_credential: {
initial_transaction: false,
initiator: 'merchant',
reason_type: 'installment',
network_transaction_id: '1234'
}
})
response = @gateway.purchase(@amount, @credit_card, options)
assert_success response
end

def test_successful_purchase_with_stored_credentials_merchant_unscheduled
options = @options.merge!({
stored_credential: {
initial_transaction: false,
initiator: 'merchant',
reason_type: 'unscheduled',
network_transaction_id: '1234'
}
})
response = @gateway.purchase(@amount, @credit_card, options)
assert_success response
end

def test_successful_purchase_with_stored_credentials_merchant_recurring
options = @options.merge!({
stored_credential: {
initial_transaction: false,
initiator: 'merchant',
reason_type: 'recurring',
network_transaction_id: '1234'
}
})
response = @gateway.purchase(@amount, @credit_card, options)

assert_success response
end

def test_successful_purchase_with_stored_credentials_cardholder_not_initial
options = @options.merge!({
stored_credential: {
initial_transaction: false,
initiator: 'cardholder',
reason_type: 'unscheduled',
network_transaction_id: '1234'
}
})
response = @gateway.purchase(@amount, @credit_card, options)
assert_success response
end
end
147 changes: 147 additions & 0 deletions test/unit/gateways/ebanx_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,153 @@ def test_successful_purchase_with_soft_descriptor
assert_success response
end

def test_successful_purchase_with_stored_credentials_cardholder_recurring
options = @options.merge!({
stored_credential: {
initial_transaction: true,
initiator: 'cardholder',
reason_type: 'recurring',
network_transaction_id: nil
}
})
response = stub_comms(@gateway, :ssl_request) do
@gateway.purchase(@amount, @credit_card, options)
end.check_request do |_method, _endpoint, data, _headers|
assert_match %r{"cof_type\":\"initial\"}, data
assert_match %r{"initiator\":\"CIT\"}, data
assert_match %r{"trans_type\":\"SCHEDULED_RECURRING\"}, data
assert_not_match %r{"mandate_id\"}, data
end.respond_with(successful_purchase_response)

assert_success response
end

def test_successful_purchase_with_stored_credentials_cardholder_unscheduled
options = @options.merge!({
stored_credential: {
initial_transaction: true,
initiator: 'cardholder',
reason_type: 'unscheduled',
network_transaction_id: nil
}
})
response = stub_comms(@gateway, :ssl_request) do
@gateway.purchase(@amount, @credit_card, options)
end.check_request do |_method, _endpoint, data, _headers|
assert_match %r{"cof_type\":\"initial\"}, data
assert_match %r{"initiator\":\"CIT\"}, data
assert_match %r{"trans_type\":\"CUSTOMER_COF\"}, data
assert_not_match %r{"mandate_id\"}, data
end.respond_with(successful_purchase_response)

assert_success response
end

def test_successful_purchase_with_stored_credentials_cardholder_installment
options = @options.merge!({
stored_credential: {
initial_transaction: true,
initiator: 'cardholder',
reason_type: 'installment',
network_transaction_id: nil
}
})
response = stub_comms(@gateway, :ssl_request) do
@gateway.purchase(@amount, @credit_card, options)
end.check_request do |_method, _endpoint, data, _headers|
assert_match %r{"cof_type\":\"initial\"}, data
assert_match %r{"initiator\":\"CIT\"}, data
assert_match %r{"trans_type\":\"INSTALLMENT\"}, data
assert_not_match %r{"mandate_id\"}, data
end.respond_with(successful_purchase_response)

assert_success response
end

def test_successful_purchase_with_stored_credentials_merchant_installment
options = @options.merge!({
stored_credential: {
initial_transaction: false,
initiator: 'merchant',
reason_type: 'installment',
network_transaction_id: '1234'
}
})
response = stub_comms(@gateway, :ssl_request) do
@gateway.purchase(@amount, @credit_card, options)
end.check_request do |_method, _endpoint, data, _headers|
assert_match %r{"cof_type\":\"stored\"}, data
assert_match %r{"initiator\":\"MIT\"}, data
assert_match %r{"trans_type\":\"INSTALLMENT\"}, data
assert_match %r{"mandate_id\":\"1234\"}, data
end.respond_with(successful_purchase_response)

assert_success response
end

def test_successful_purchase_with_stored_credentials_merchant_unscheduled
options = @options.merge!({
stored_credential: {
initial_transaction: false,
initiator: 'merchant',
reason_type: 'unscheduled',
network_transaction_id: '1234'
}
})
response = stub_comms(@gateway, :ssl_request) do
@gateway.purchase(@amount, @credit_card, options)
end.check_request do |_method, _endpoint, data, _headers|
assert_match %r{"cof_type\":\"stored\"}, data
assert_match %r{"initiator\":\"MIT\"}, data
assert_match %r{"trans_type\":\"MERCHANT_COF\"}, data
assert_match %r{"mandate_id\":\"1234\"}, data
end.respond_with(successful_purchase_response)

assert_success response
end

def test_successful_purchase_with_stored_credentials_merchant_recurring
options = @options.merge!({
stored_credential: {
initial_transaction: false,
initiator: 'merchant',
reason_type: 'recurring',
network_transaction_id: '1234'
}
})
response = stub_comms(@gateway, :ssl_request) do
@gateway.purchase(@amount, @credit_card, options)
end.check_request do |_method, _endpoint, data, _headers|
assert_match %r{"cof_type\":\"stored\"}, data
assert_match %r{"initiator\":\"MIT\"}, data
assert_match %r{"trans_type\":\"SCHEDULED_RECURRING\"}, data
assert_match %r{"mandate_id\":\"1234\"}, data
end.respond_with(successful_purchase_response)

assert_success response
end

def test_successful_purchase_with_stored_credentials_cardholder_not_initial
options = @options.merge!({
stored_credential: {
initial_transaction: false,
initiator: 'cardholder',
reason_type: 'unscheduled',
network_transaction_id: '1234'
}
})
response = stub_comms(@gateway, :ssl_request) do
@gateway.purchase(@amount, @credit_card, options)
end.check_request do |_method, _endpoint, data, _headers|
assert_match %r{"cof_type\":\"stored\"}, data
assert_match %r{"initiator\":\"CIT\"}, data
assert_match %r{"trans_type\":\"CUSTOMER_COF\"}, data
assert_match %r{"mandate_id\":\"1234\"}, data
end.respond_with(successful_purchase_response)

assert_success response
end

def test_failed_purchase
@gateway.expects(:ssl_request).returns(failed_purchase_response)

Expand Down
Loading