From c0c08d05ef04d914e07d49f163e43bdddf5c885b Mon Sep 17 00:00:00 2001 From: Sarthak Soni <76486416+Sarthak1799@users.noreply.github.com> Date: Wed, 12 Mar 2025 15:16:59 +0530 Subject: [PATCH] fix(routing): Enable filtering of default connectors for contract based routing (#7420) --- crates/api_models/src/routing.rs | 8 ++++- crates/router/src/core/payments/routing.rs | 36 +++++++++++++++++----- crates/router/src/core/routing.rs | 30 ++++++++++++++++++ crates/router/src/core/routing/helpers.rs | 9 +++++- 4 files changed, 73 insertions(+), 10 deletions(-) diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index d4b4f76e17..cc87b85c1c 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -1018,12 +1018,18 @@ impl ContractBasedRoutingConfig { if let Some(new_label_info) = new.label_info { new_label_info.iter().for_each(|new_label_info| { if let Some(existing_label_infos) = &mut self.label_info { - for existing_label_info in existing_label_infos { + let mut updated = false; + for existing_label_info in &mut *existing_label_infos { if existing_label_info.mca_id == new_label_info.mca_id { existing_label_info.update_target_time(new_label_info); existing_label_info.update_target_count(new_label_info); + updated = true; } } + + if !updated { + existing_label_infos.push(new_label_info.clone()); + } } else { self.label_info = Some(vec![new_label_info.clone()]); } diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index e78861d432..ceac9eaf43 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -1600,12 +1600,37 @@ pub async fn perform_contract_based_routing( .change_context(errors::RoutingError::ContractBasedRoutingConfigError) .attach_printable("unable to fetch contract based dynamic routing configs")?; + let label_info = contract_based_routing_configs + .label_info + .clone() + .ok_or(errors::RoutingError::ContractBasedRoutingConfigError) + .attach_printable("Label information not found in contract routing configs")?; + + let contract_based_connectors = routable_connectors + .clone() + .into_iter() + .filter(|conn| { + label_info + .iter() + .any(|info| Some(info.mca_id.clone()) == conn.merchant_connector_id.clone()) + }) + .collect::>(); + + let mut other_connectors = routable_connectors + .into_iter() + .filter(|conn| { + label_info + .iter() + .all(|info| Some(info.mca_id.clone()) != conn.merchant_connector_id.clone()) + }) + .collect::>(); + let contract_based_connectors_result = client .calculate_contract_score( profile_id.get_string_repr().into(), contract_based_routing_configs.clone(), "".to_string(), - routable_connectors, + contract_based_connectors, state.get_grpc_headers(), ) .await @@ -1617,13 +1642,6 @@ pub async fn perform_contract_based_routing( Ok(resp) => resp, Err(err) => match err.current_context() { DynamicRoutingError::ContractNotFound => { - let label_info = contract_based_routing_configs - .label_info - .ok_or(errors::RoutingError::ContractBasedRoutingConfigError) - .attach_printable( - "Label information not found in contract routing configs", - )?; - client .update_contracts( profile_id.get_string_repr().into(), @@ -1683,6 +1701,8 @@ pub async fn perform_contract_based_routing( }); } + connectors.append(&mut other_connectors); + logger::debug!(contract_based_routing_connectors=?connectors); Ok(connectors) } else { diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs index 64207b4b5d..6c13848824 100644 --- a/crates/router/src/core/routing.rs +++ b/crates/router/src/core/routing.rs @@ -1639,7 +1639,23 @@ pub async fn contract_based_dynamic_routing_setup( }; // validate the contained mca_ids + let mut contained_mca = Vec::new(); if let Some(info_vec) = &config.label_info { + for info in info_vec { + utils::when( + contained_mca.iter().any(|mca_id| mca_id == &info.mca_id), + || { + Err(error_stack::Report::new( + errors::ApiErrorResponse::InvalidRequestData { + message: "Duplicate mca configuration received".to_string(), + }, + )) + }, + )?; + + contained_mca.push(info.mca_id.to_owned()); + } + let validation_futures: Vec<_> = info_vec .iter() .map(|info| async { @@ -1724,6 +1740,7 @@ pub async fn contract_based_routing_update_configs( .attach_printable("unable to deserialize algorithm data from routing table into ContractBasedRoutingConfig")?; // validate the contained mca_ids + let mut contained_mca = Vec::new(); if let Some(info_vec) = &request.label_info { for info in info_vec { let mca = db @@ -1743,6 +1760,19 @@ pub async fn contract_based_routing_update_configs( message: "Incorrect mca configuration received".to_string(), }) })?; + + utils::when( + contained_mca.iter().any(|mca_id| mca_id == &info.mca_id), + || { + Err(error_stack::Report::new( + errors::ApiErrorResponse::InvalidRequestData { + message: "Duplicate mca configuration received".to_string(), + }, + )) + }, + )?; + + contained_mca.push(info.mca_id.to_owned()); } } diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs index 17edc50a30..1d40039e2a 100644 --- a/crates/router/src/core/routing/helpers.rs +++ b/crates/router/src/core/routing/helpers.rs @@ -1062,12 +1062,19 @@ pub async fn push_metrics_with_update_window_for_contract_based_routing( )?; } + let contract_based_connectors = routable_connectors + .into_iter() + .filter(|conn| { + conn.merchant_connector_id.clone() == Some(final_label_info.mca_id.clone()) + }) + .collect::>(); + let contract_scores = client .calculate_contract_score( profile_id.get_string_repr().into(), contract_based_routing_config.clone(), "".to_string(), - routable_connectors.clone(), + contract_based_connectors, state.get_grpc_headers(), ) .await