Skip to content

Commit

Permalink
StripePI: Skip add_network_token_cryptogram_and_eci method to accept …
Browse files Browse the repository at this point in the history
…ApplePay recurring payments and add unit/remote tests
  • Loading branch information
Luis Urrea committed Aug 16, 2024
1 parent 59545a5 commit 1ee70c2
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 23 deletions.
13 changes: 8 additions & 5 deletions lib/active_merchant/billing/gateways/stripe_payment_intents.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def create_intent(money, payment_method, options = {})
return result if result.is_a?(ActiveMerchant::Billing::Response)
end

add_network_token_cryptogram_and_eci(post, payment_method)
add_network_token_cryptogram_and_eci(post, payment_method, options)
add_external_three_d_secure_auth_data(post, options)
add_metadata(post, options)
add_return_url(post, options)
Expand Down Expand Up @@ -316,8 +316,11 @@ def digital_wallet_payment_method?(payment_method)
payment_method.source == :google_pay || payment_method.source == :apple_pay
end

def adding_network_token_card_data?(payment_method)
return true if payment_method.is_a?(ActiveMerchant::Billing::NetworkTokenizationCreditCard) && payment_method.source == :network_token
def adding_network_token_card_data?(payment_method, options = {})
return true if payment_method.is_a?(ActiveMerchant::Billing::NetworkTokenizationCreditCard) &&
payment_method.source == :network_token &&
payment_method.source != :apple_pay &&
options.dig(:stored_credential, :initiator) != 'merchant'

false
end
Expand Down Expand Up @@ -423,8 +426,8 @@ def add_network_token_data(post_data, payment_method, options)
post_data
end

def add_network_token_cryptogram_and_eci(post, payment_method)
return unless adding_network_token_card_data?(payment_method)
def add_network_token_cryptogram_and_eci(post, payment_method, options)
return unless adding_network_token_card_data?(payment_method, options)

post[:payment_method_options] ||= {}
post[:payment_method_options][:card] ||= {}
Expand Down
51 changes: 51 additions & 0 deletions test/remote/gateways/remote_stripe_payment_intents_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,57 @@ def test_successful_purchase_with_apple_pay_when_sending_the_billing_address
assert_match('apple_pay', purchase.params.dig('charges', 'data')[0]['payment_method_details']['card']['wallet']['type'])
end

def test_successful_purchase_with_apple_pay_and_cit
options = {
currency: 'GBP',
new_ap_gp_route: true,
stored_credential_transaction_type: true,
stored_credential: {
initiator: 'cardholder',
reason_type: 'unscheduled',
initial_transaction: true
}
}

purchase = @gateway.purchase(@amount, @apple_pay, options)
assert purchase.success?
assert_match('apple_pay', purchase.params.dig('charges', 'data')[0]['payment_method_details']['card']['wallet']['type'])
end

def test_succeeds_apple_pay_ntid_and_passes_it_to_mit
options = {
currency: 'GBP',
new_ap_gp_route: true,
stored_credential_transaction_type: true,
stored_credential: {
initiator: 'cardholder',
reason_type: 'unscheduled',
initial_transaction: true
}
}

cit_purchase = @gateway.purchase(@amount, @apple_pay, options)
assert cit_purchase.success?

assert purchase = @gateway.purchase(@amount, @apple_pay, {
currency: 'USD',
execute_threed: true,
confirm: true,
stored_credential_transaction_type: true,
stored_credential: {
initiator: 'merchant',
reason_type: 'recurring',
initial_transaction: false,
network_transaction_id: cit_purchase.params.dig('charges', 'data', 0, 'payment_method_details', 'card', 'network_transaction_id'),
off_session: 'true'
}
})
assert_success purchase
assert_equal 'succeeded', purchase.params['status']
assert purchase.params.dig('charges', 'data')[0]['captured']
assert purchase.params.dig('charges', 'data')[0]['payment_method_details']['card']['network_transaction_id']
end

def test_purchases_with_same_idempotency_key
options = {
currency: 'GBP',
Expand Down
83 changes: 65 additions & 18 deletions test/unit/gateways/stripe_payment_intents_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ def setup
first_name: 'Longbob',
last_name: 'Longsen'
)

@network_transaction_id = '1098510912210968'
end

def test_successful_create_and_confirm_intent
Expand Down Expand Up @@ -401,7 +403,6 @@ def test_successful_purchase_with_card_brand

def test_succesful_purchase_with_stored_credentials_without_sending_ntid
[@three_ds_off_session_credit_card, @three_ds_authentication_required_setup_for_off_session].each do |card_to_use|
network_transaction_id = '1098510912210968'
stub_comms(@gateway, :ssl_request) do
@gateway.purchase(@amount, card_to_use, {
currency: 'USD',
Expand All @@ -413,7 +414,7 @@ def test_succesful_purchase_with_stored_credentials_without_sending_ntid
initiator: 'cardholder',
reason_type: 'installment',
initial_transaction: true,
network_transaction_id: network_transaction_id, # TEST env seems happy with any value :/
network_transaction_id: @network_transaction_id, # TEST env seems happy with any value :/
ds_transaction_id: 'null' # this is optional and can be null if not available.
}
})
Expand All @@ -427,7 +428,6 @@ def test_succesful_purchase_with_stored_credentials_without_sending_ntid
def test_succesful_purchase_with_ntid_when_off_session
# don't send NTID if setup_future_usage == off_session
[@three_ds_off_session_credit_card, @three_ds_authentication_required_setup_for_off_session].each do |card_to_use|
network_transaction_id = '1098510912210968'
stub_comms(@gateway, :ssl_request) do
@gateway.purchase(@amount, card_to_use, {
currency: 'USD',
Expand All @@ -439,7 +439,7 @@ def test_succesful_purchase_with_ntid_when_off_session
initiator: 'cardholder',
reason_type: 'installment',
initial_transaction: true,
network_transaction_id: network_transaction_id, # TEST env seems happy with any value :/
network_transaction_id: @network_transaction_id, # TEST env seems happy with any value :/
ds_transaction_id: 'null' # this is optional and can be null if not available.
}
})
Expand All @@ -452,40 +452,38 @@ def test_succesful_purchase_with_ntid_when_off_session

def test_succesful_purchase_with_stored_credentials
[@three_ds_off_session_credit_card, @three_ds_authentication_required_setup_for_off_session].each do |card_to_use|
network_transaction_id = '1098510912210968'
stub_comms(@gateway, :ssl_request) do
@gateway.purchase(@amount, card_to_use, {
currency: 'USD',
execute_threed: true,
confirm: true,
off_session: true,
stored_credential: {
network_transaction_id: network_transaction_id, # TEST env seems happy with any value :/
network_transaction_id: @network_transaction_id, # TEST env seems happy with any value :/
ds_transaction_id: 'null' # this is optional and can be null if not available.
}
})
end.check_request do |_method, _endpoint, data, _headers|
assert_match(%r{payment_method_options\[card\]\[mit_exemption\]\[network_transaction_id\]=#{network_transaction_id}}, data)
assert_match(%r{payment_method_options\[card\]\[mit_exemption\]\[network_transaction_id\]=#{@network_transaction_id}}, data)
assert_match(%r{payment_method_options\[card\]\[mit_exemption\]\[ds_transaction_id\]=null}, data)
end.respond_with(successful_create_intent_response)
end
end

def test_succesful_purchase_with_stored_credentials_without_optional_ds_transaction_id
[@three_ds_off_session_credit_card, @three_ds_authentication_required_setup_for_off_session].each do |card_to_use|
network_transaction_id = '1098510912210968'
stub_comms(@gateway, :ssl_request) do
@gateway.purchase(@amount, card_to_use, {
currency: 'USD',
execute_threed: true,
confirm: true,
off_session: true,
stored_credential: {
network_transaction_id: network_transaction_id # TEST env seems happy with any value :/
network_transaction_id: @network_transaction_id # TEST env seems happy with any value :/
}
})
end.check_request do |_method, _endpoint, data, _headers|
assert_match(%r{payment_method_options\[card\]\[mit_exemption\]\[network_transaction_id\]=#{network_transaction_id}}, data)
assert_match(%r{payment_method_options\[card\]\[mit_exemption\]\[network_transaction_id\]=#{@network_transaction_id}}, data)
assert_no_match(%r{payment_method_options\[card\]\[mit_exemption\]\[ds_transaction_id\]=null}, data)
end.respond_with(successful_create_intent_response)
end
Expand All @@ -505,15 +503,12 @@ def test_succesful_purchase_without_stored_credentials_introduces_no_exemption_f
end

def test_sends_network_transaction_id_separate_from_stored_creds
network_transaction_id = '1098510912210968'
options = @options.merge(
network_transaction_id: network_transaction_id
)
options = @options.merge(network_transaction_id: @network_transaction_id)

stub_comms(@gateway, :ssl_request) do
@gateway.purchase(@amount, @visa_token, options)
end.check_request do |_method, _endpoint, data, _headers|
assert_match(%r{payment_method_options\[card\]\[mit_exemption\]\[network_transaction_id\]=#{network_transaction_id}}, data)
assert_match(%r{payment_method_options\[card\]\[mit_exemption\]\[network_transaction_id\]=#{@network_transaction_id}}, data)
end.respond_with(successful_create_intent_response)
end

Expand Down Expand Up @@ -661,10 +656,9 @@ def test_authorize_with_apple_pay_with_billing_address
end

def test_stored_credentials_does_not_override_ntid_field
network_transaction_id = '1098510912210968'
sc_network_transaction_id = '1078784111114777'
options = @options.merge(
network_transaction_id: network_transaction_id,
network_transaction_id: @network_transaction_id,
stored_credential: {
network_transaction_id: sc_network_transaction_id,
ds_transaction_id: 'null'
Expand All @@ -674,7 +668,7 @@ def test_stored_credentials_does_not_override_ntid_field
stub_comms(@gateway, :ssl_request) do
@gateway.purchase(@amount, @visa_token, options)
end.check_request do |_method, _endpoint, data, _headers|
assert_match(%r{payment_method_options\[card\]\[mit_exemption\]\[network_transaction_id\]=#{network_transaction_id}}, data)
assert_match(%r{payment_method_options\[card\]\[mit_exemption\]\[network_transaction_id\]=#{@network_transaction_id}}, data)
end.respond_with(successful_create_intent_response)
end

Expand Down Expand Up @@ -945,6 +939,59 @@ def test_create_setup_intent_with_moto_exemption
end.respond_with(successful_verify_response)
end

def test_add_network_token_cryptogram_and_eci_for_apple_pay_cit
options = {
currency: 'USD',
execute_threed: true,
confirm: true,
off_session: true,
stored_credential_transaction_type: true,
stored_credential: {
initiator: 'cardholder',
reason_type: 'installment',
initial_transaction: true,
network_transaction_id: @network_transaction_id, # TEST env seems happy with any value :/
ds_transaction_id: 'null' # this is optional and can be null if not available.
}
}

stub_comms(@gateway, :ssl_request) do
@gateway.create_intent(@amount, @apple_pay, options)
end.check_request do |_method, endpoint, data, _headers|
if /payment_intents/.match?(endpoint)
assert_match(/payment_method_options\[card\]\[stored_credential_transaction_type\]=setup_on_session/, data)
assert_match(/card\[eci\]=05/, data)
assert_match(/card\[cryptogram\]=dGVzdGNyeXB0b2dyYW1YWFhYWFhYWFhYWFg9PQ%3D%3D/, data)
end
end.respond_with(successful_create_intent_response_with_apple_pay_and_billing_address)
end

def test_skip_network_token_cryptogram_and_eci_for_apple_pay_mit
options = {
currency: 'USD',
execute_threed: true,
confirm: true,
stored_credential_transaction_type: true,
stored_credential: {
initiator: 'merchant',
reason_type: 'recurring',
initial_transaction: false,
network_transaction_id: @network_transaction_id,
off_session: 'true'
}
}

stub_comms(@gateway, :ssl_request) do
@gateway.create_intent(@amount, @apple_pay, options)
end.check_request do |_method, endpoint, data, _headers|
if /payment_intents/.match?(endpoint)
assert_match(/payment_method_options\[card\]\[stored_credential_transaction_type\]=stored_off_session_recurring/, data)
assert_not_match(/card\[eci\]/, data)
assert_not_match(/card\[cryptogram\]/, data)
end
end.respond_with(successful_verify_response)
end

private

def successful_setup_purchase
Expand Down

0 comments on commit 1ee70c2

Please sign in to comment.