From c275e13caf22362173e77d2260b440159abcabb3 Mon Sep 17 00:00:00 2001 From: Sarthak Soni <76486416+Sarthak1799@users.noreply.github.com> Date: Thu, 3 Jul 2025 12:21:59 +0530 Subject: [PATCH] fix: Update routing_approach for session_token flow (#8490) --- crates/common_enums/src/enums.rs | 2 + crates/diesel_models/src/payment_attempt.rs | 4 +- .../src/payments/payment_attempt.rs | 5 +- .../router/src/core/payment_methods/cards.rs | 3 +- crates/router/src/core/payments.rs | 12 ++- .../payments/operations/payment_create.rs | 3 + crates/router/src/core/payments/routing.rs | 80 ++++++++++++------- .../down.sql | 2 + .../up.sql | 3 + 9 files changed, 80 insertions(+), 34 deletions(-) create mode 100644 migrations/2025-06-27-120507_update_routing_approach/down.sql create mode 100644 migrations/2025-06-27-120507_update_routing_approach/up.sql diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index 29cf75ac50..1d00a45170 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -8523,6 +8523,7 @@ pub enum RoutingApproach { DebitRouting, RuleBasedRouting, VolumeBasedRouting, + StraightThroughRouting, #[default] DefaultFallback, } @@ -8533,6 +8534,7 @@ impl RoutingApproach { "SR_SELECTION_V3_ROUTING" => Self::SuccessRateExploitation, "SR_V3_HEDGING" => Self::SuccessRateExploration, "NTW_BASED_ROUTING" => Self::DebitRouting, + "DEFAULT" => Self::StraightThroughRouting, _ => Self::DefaultFallback, } } diff --git a/crates/diesel_models/src/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs index 0afea0574a..eeda9e7887 100644 --- a/crates/diesel_models/src/payment_attempt.rs +++ b/crates/diesel_models/src/payment_attempt.rs @@ -459,6 +459,7 @@ pub enum PaymentAttemptUpdate { tax_amount: Option, updated_by: String, merchant_connector_id: Option, + routing_approach: Option, }, AuthenticationTypeUpdate { authentication_type: storage_enums::AuthenticationType, @@ -3088,6 +3089,7 @@ impl From for PaymentAttemptUpdateInternal { tax_amount, updated_by, merchant_connector_id, + routing_approach, } => Self { payment_token, modified_at: common_utils::date_time::now(), @@ -3146,7 +3148,7 @@ impl From for PaymentAttemptUpdateInternal { issuer_error_code: None, issuer_error_message: None, setup_future_usage_applied: None, - routing_approach: None, + routing_approach, }, PaymentAttemptUpdate::UnresolvedResponseUpdate { status, diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index 3a2692e583..d644c519ea 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -1191,6 +1191,7 @@ pub enum PaymentAttemptUpdate { tax_amount: Option, updated_by: String, merchant_connector_id: Option, + routing_approach: Option, }, AuthenticationTypeUpdate { authentication_type: storage_enums::AuthenticationType, @@ -1227,7 +1228,7 @@ pub enum PaymentAttemptUpdate { customer_acceptance: Option, connector_mandate_detail: Option, card_discovery: Option, - routing_approach: Option, // where all to add this one + routing_approach: Option, }, RejectUpdate { status: storage_enums::AttemptStatus, @@ -1413,6 +1414,7 @@ impl PaymentAttemptUpdate { surcharge_amount, tax_amount, merchant_connector_id, + routing_approach, } => DieselPaymentAttemptUpdate::UpdateTrackers { payment_token, connector, @@ -1422,6 +1424,7 @@ impl PaymentAttemptUpdate { tax_amount, updated_by, merchant_connector_id, + routing_approach, }, Self::AuthenticationTypeUpdate { authentication_type, diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index c308d30e24..8f29e05e15 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -2843,7 +2843,7 @@ pub async fn list_payment_methods( payment_intent, chosen, }; - let result = routing::perform_session_flow_routing( + let (result, routing_approach) = routing::perform_session_flow_routing( sfr, &business_profile, &enums::TransactionType::Payment, @@ -3025,6 +3025,7 @@ pub async fn list_payment_methods( merchant_connector_id: None, surcharge_amount: None, tax_amount: None, + routing_approach, }; state diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index d87f0e8dcb..66334148b0 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -7331,6 +7331,10 @@ where .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed execution of straight through routing")?; + payment_data.set_routing_approach_in_attempt(Some( + common_enums::RoutingApproach::StraightThroughRouting, + )); + if check_eligibility { let transaction_data = core_routing::PaymentsDslInput::new( payment_data.get_setup_mandate(), @@ -7911,12 +7915,12 @@ pub async fn perform_session_token_routing( state: SessionState, merchant_context: &domain::MerchantContext, business_profile: &domain::Profile, - payment_data: &D, + payment_data: &mut D, connectors: api::SessionConnectorDatas, ) -> RouterResult where F: Clone, - D: OperationSessionGetters, + D: OperationSessionGetters + OperationSessionSetters, { let chosen = connectors.apply_filter_for_session_routing(); let sfr = SessionFlowRoutingInput { @@ -7932,7 +7936,7 @@ where payment_intent: payment_data.get_payment_intent(), chosen, }; - let result = self_routing::perform_session_flow_routing( + let (result, routing_approach) = self_routing::perform_session_flow_routing( sfr, business_profile, &enums::TransactionType::Payment, @@ -7941,6 +7945,8 @@ where .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("error performing session flow routing")?; + payment_data.set_routing_approach_in_attempt(routing_approach); + let final_list = connectors.filter_and_validate_for_session_flow(&result)?; Ok(final_list) diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 4c463c74ed..413aa121a9 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -880,6 +880,8 @@ impl UpdateTracker, api::PaymentsRequest> for .as_ref() .map(|surcharge_details| surcharge_details.tax_on_surcharge_amount); + let routing_approach = payment_data.payment_attempt.routing_approach; + payment_data.payment_attempt = state .store .update_payment_attempt_with_attempt_id( @@ -896,6 +898,7 @@ impl UpdateTracker, api::PaymentsRequest> for tax_amount, updated_by: storage_scheme.to_string(), merchant_connector_id, + routing_approach, }, storage_scheme, ) diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 7126ed9617..c3823aa2f3 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -515,7 +515,10 @@ pub async fn perform_static_routing_v1( ).unwrap_or_default(); let (routable_connectors, routing_approach) = match cached_algorithm.as_ref() { - CachedAlgorithm::Single(conn) => (vec![(**conn).clone()], None), + CachedAlgorithm::Single(conn) => ( + vec![(**conn).clone()], + Some(common_enums::RoutingApproach::StraightThroughRouting), + ), CachedAlgorithm::Priority(plist) => (plist.clone(), None), CachedAlgorithm::VolumeSplit(splits) => ( perform_volume_split(splits.to_vec()) @@ -1208,8 +1211,10 @@ pub async fn perform_session_flow_routing( session_input: SessionFlowRoutingInput<'_>, business_profile: &domain::Profile, transaction_type: &api_enums::TransactionType, -) -> RoutingResult>> -{ +) -> RoutingResult<( + FxHashMap>, + Option, +)> { let mut pm_type_map: FxHashMap> = FxHashMap::default(); @@ -1297,6 +1302,7 @@ pub async fn perform_session_flow_routing( api_enums::PaymentMethodType, Vec, > = FxHashMap::default(); + let mut final_routing_approach = None; for (pm_type, allowed_connectors) in pm_type_map { let euclid_pmt: euclid_enums::PaymentMethodType = pm_type; @@ -1315,12 +1321,15 @@ pub async fn perform_session_flow_routing( profile_id: &profile_id, }; - let routable_connector_choice_option = perform_session_routing_for_pm_type( - &session_pm_input, - transaction_type, - business_profile, - ) - .await?; + let (routable_connector_choice_option, routing_approach) = + perform_session_routing_for_pm_type( + &session_pm_input, + transaction_type, + business_profile, + ) + .await?; + + final_routing_approach = routing_approach; if let Some(routable_connector_choice) = routable_connector_choice_option { let mut session_routing_choice: Vec = Vec::new(); @@ -1348,7 +1357,7 @@ pub async fn perform_session_flow_routing( } } - Ok(result) + Ok((result, final_routing_approach)) } #[cfg(feature = "v1")] @@ -1356,14 +1365,17 @@ async fn perform_session_routing_for_pm_type( session_pm_input: &SessionRoutingPmTypeInput<'_>, transaction_type: &api_enums::TransactionType, _business_profile: &domain::Profile, -) -> RoutingResult>> { +) -> RoutingResult<( + Option>, + Option, +)> { let merchant_id = &session_pm_input.key_store.merchant_id; let algorithm_id = match session_pm_input.routing_algorithm { MerchantAccountRoutingAlgorithm::V1(algorithm_ref) => &algorithm_ref.algorithm_id, }; - let chosen_connectors = if let Some(ref algorithm_id) = algorithm_id { + let (chosen_connectors, routing_approach) = if let Some(ref algorithm_id) = algorithm_id { let cached_algorithm = ensure_algorithm_cached_v1( &session_pm_input.state.clone(), merchant_id, @@ -1374,23 +1386,35 @@ async fn perform_session_routing_for_pm_type( .await?; match cached_algorithm.as_ref() { - CachedAlgorithm::Single(conn) => vec![(**conn).clone()], - CachedAlgorithm::Priority(plist) => plist.clone(), - CachedAlgorithm::VolumeSplit(splits) => perform_volume_split(splits.to_vec()) - .change_context(errors::RoutingError::ConnectorSelectionFailed)?, - CachedAlgorithm::Advanced(interpreter) => execute_dsl_and_get_connector_v1( - session_pm_input.backend_input.clone(), - interpreter, - )?, + CachedAlgorithm::Single(conn) => ( + vec![(**conn).clone()], + Some(common_enums::RoutingApproach::StraightThroughRouting), + ), + CachedAlgorithm::Priority(plist) => (plist.clone(), None), + CachedAlgorithm::VolumeSplit(splits) => ( + perform_volume_split(splits.to_vec()) + .change_context(errors::RoutingError::ConnectorSelectionFailed)?, + Some(common_enums::RoutingApproach::VolumeBasedRouting), + ), + CachedAlgorithm::Advanced(interpreter) => ( + execute_dsl_and_get_connector_v1( + session_pm_input.backend_input.clone(), + interpreter, + )?, + Some(common_enums::RoutingApproach::RuleBasedRouting), + ), } } else { - routing::helpers::get_merchant_default_config( - &*session_pm_input.state.clone().store, - session_pm_input.profile_id.get_string_repr(), - transaction_type, + ( + routing::helpers::get_merchant_default_config( + &*session_pm_input.state.clone().store, + session_pm_input.profile_id.get_string_repr(), + transaction_type, + ) + .await + .change_context(errors::RoutingError::FallbackConfigFetchFailed)?, + None, ) - .await - .change_context(errors::RoutingError::FallbackConfigFetchFailed)? }; let mut final_selection = perform_cgraph_filtering( @@ -1426,9 +1450,9 @@ async fn perform_session_routing_for_pm_type( } if final_selection.is_empty() { - Ok(None) + Ok((None, routing_approach)) } else { - Ok(Some(final_selection)) + Ok((Some(final_selection), routing_approach)) } } diff --git a/migrations/2025-06-27-120507_update_routing_approach/down.sql b/migrations/2025-06-27-120507_update_routing_approach/down.sql new file mode 100644 index 0000000000..c7c9cbeb40 --- /dev/null +++ b/migrations/2025-06-27-120507_update_routing_approach/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +SELECT 1; \ No newline at end of file diff --git a/migrations/2025-06-27-120507_update_routing_approach/up.sql b/migrations/2025-06-27-120507_update_routing_approach/up.sql new file mode 100644 index 0000000000..c7f75cb523 --- /dev/null +++ b/migrations/2025-06-27-120507_update_routing_approach/up.sql @@ -0,0 +1,3 @@ +-- Your SQL goes here +ALTER TYPE "RoutingApproach" +ADD VALUE 'straight_through_routing';