fix(routing): Enable filtering of default connectors for contract based routing (#7420)

This commit is contained in:
Sarthak Soni
2025-03-12 15:16:59 +05:30
committed by GitHub
parent 44c0a55235
commit c0c08d05ef
4 changed files with 73 additions and 10 deletions

View File

@ -1018,12 +1018,18 @@ impl ContractBasedRoutingConfig {
if let Some(new_label_info) = new.label_info { if let Some(new_label_info) = new.label_info {
new_label_info.iter().for_each(|new_label_info| { new_label_info.iter().for_each(|new_label_info| {
if let Some(existing_label_infos) = &mut self.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 { 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_time(new_label_info);
existing_label_info.update_target_count(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 { } else {
self.label_info = Some(vec![new_label_info.clone()]); self.label_info = Some(vec![new_label_info.clone()]);
} }

View File

@ -1600,12 +1600,37 @@ pub async fn perform_contract_based_routing(
.change_context(errors::RoutingError::ContractBasedRoutingConfigError) .change_context(errors::RoutingError::ContractBasedRoutingConfigError)
.attach_printable("unable to fetch contract based dynamic routing configs")?; .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::<Vec<_>>();
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::<Vec<_>>();
let contract_based_connectors_result = client let contract_based_connectors_result = client
.calculate_contract_score( .calculate_contract_score(
profile_id.get_string_repr().into(), profile_id.get_string_repr().into(),
contract_based_routing_configs.clone(), contract_based_routing_configs.clone(),
"".to_string(), "".to_string(),
routable_connectors, contract_based_connectors,
state.get_grpc_headers(), state.get_grpc_headers(),
) )
.await .await
@ -1617,13 +1642,6 @@ pub async fn perform_contract_based_routing(
Ok(resp) => resp, Ok(resp) => resp,
Err(err) => match err.current_context() { Err(err) => match err.current_context() {
DynamicRoutingError::ContractNotFound => { 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 client
.update_contracts( .update_contracts(
profile_id.get_string_repr().into(), 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); logger::debug!(contract_based_routing_connectors=?connectors);
Ok(connectors) Ok(connectors)
} else { } else {

View File

@ -1639,7 +1639,23 @@ pub async fn contract_based_dynamic_routing_setup(
}; };
// validate the contained mca_ids // validate the contained mca_ids
let mut contained_mca = Vec::new();
if let Some(info_vec) = &config.label_info { 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 let validation_futures: Vec<_> = info_vec
.iter() .iter()
.map(|info| async { .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")?; .attach_printable("unable to deserialize algorithm data from routing table into ContractBasedRoutingConfig")?;
// validate the contained mca_ids // validate the contained mca_ids
let mut contained_mca = Vec::new();
if let Some(info_vec) = &request.label_info { if let Some(info_vec) = &request.label_info {
for info in info_vec { for info in info_vec {
let mca = db let mca = db
@ -1743,6 +1760,19 @@ pub async fn contract_based_routing_update_configs(
message: "Incorrect mca configuration received".to_string(), 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());
} }
} }

View File

@ -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::<Vec<_>>();
let contract_scores = client let contract_scores = client
.calculate_contract_score( .calculate_contract_score(
profile_id.get_string_repr().into(), profile_id.get_string_repr().into(),
contract_based_routing_config.clone(), contract_based_routing_config.clone(),
"".to_string(), "".to_string(),
routable_connectors.clone(), contract_based_connectors,
state.get_grpc_headers(), state.get_grpc_headers(),
) )
.await .await