mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 04:04:55 +08:00
feat(euclid): integration with decision engine (#7930)
Co-authored-by: Jagan Elavarasan <jaganelavarasan@gmail.com> Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -31,7 +31,10 @@ use super::payouts;
|
||||
use super::{
|
||||
errors::RouterResult,
|
||||
payments::{
|
||||
routing::{self as payments_routing},
|
||||
routing::{
|
||||
utils::*,
|
||||
{self as payments_routing},
|
||||
},
|
||||
OperationSessionGetters,
|
||||
},
|
||||
};
|
||||
@ -118,6 +121,7 @@ impl RoutingAlgorithmUpdate {
|
||||
created_at: timestamp,
|
||||
modified_at: timestamp,
|
||||
algorithm_for: transaction_type,
|
||||
decision_engine_routing_id: None,
|
||||
};
|
||||
Self(algo)
|
||||
}
|
||||
@ -153,14 +157,34 @@ pub async fn retrieve_merchant_routing_dictionary(
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;
|
||||
let routing_metadata =
|
||||
super::utils::filter_objects_based_on_profile_id_list(profile_id_list, routing_metadata);
|
||||
let routing_metadata = super::utils::filter_objects_based_on_profile_id_list(
|
||||
profile_id_list.clone(),
|
||||
routing_metadata,
|
||||
);
|
||||
|
||||
let result = routing_metadata
|
||||
.into_iter()
|
||||
.map(ForeignInto::foreign_into)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if let Some(profile_ids) = profile_id_list {
|
||||
let mut de_result: Vec<routing_types::RoutingDictionaryRecord> = vec![];
|
||||
// DE_TODO: need to replace this with batch API call to reduce the number of network calls
|
||||
for profile_id in profile_ids {
|
||||
let list_request = ListRountingAlgorithmsRequest {
|
||||
created_by: profile_id.get_string_repr().to_string(),
|
||||
};
|
||||
list_de_euclid_routing_algorithms(&state, list_request)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
router_env::logger::error!(decision_engine_error=?e, "decision_engine_euclid");
|
||||
})
|
||||
.ok() // Avoid throwing error if Decision Engine is not available or other errors
|
||||
.map(|mut de_routing| de_result.append(&mut de_routing));
|
||||
}
|
||||
compare_and_log_result(de_result, result.clone(), "list_routing".to_string());
|
||||
}
|
||||
|
||||
metrics::ROUTING_MERCHANT_DICTIONARY_RETRIEVE_SUCCESS_RESPONSE.add(1, &[]);
|
||||
Ok(service_api::ApplicationResponse::Json(
|
||||
routing_types::RoutingKind::RoutingAlgorithm(result),
|
||||
@ -249,6 +273,10 @@ pub async fn create_routing_algorithm_under_profile(
|
||||
request: routing_types::RoutingConfigRequest,
|
||||
transaction_type: enums::TransactionType,
|
||||
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
|
||||
use api_models::routing::RoutingAlgorithm as EuclidAlgorithm;
|
||||
|
||||
use crate::services::logger;
|
||||
|
||||
metrics::ROUTING_CREATE_REQUEST_RECEIVED.add(1, &[]);
|
||||
let db = state.store.as_ref();
|
||||
let key_manager_state = &(&state).into();
|
||||
@ -269,6 +297,7 @@ pub async fn create_routing_algorithm_under_profile(
|
||||
|
||||
let algorithm = request
|
||||
.algorithm
|
||||
.clone()
|
||||
.get_required_value("algorithm")
|
||||
.change_context(errors::ApiErrorResponse::MissingRequiredField {
|
||||
field_name: "algorithm",
|
||||
@ -306,6 +335,37 @@ pub async fn create_routing_algorithm_under_profile(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut decision_engine_routing_id: Option<String> = None;
|
||||
|
||||
if let Some(EuclidAlgorithm::Advanced(program)) = request.algorithm.clone() {
|
||||
let internal_program: Program = program.into();
|
||||
let routing_rule = RoutingRule {
|
||||
name: name.clone(),
|
||||
description: Some(description.clone()),
|
||||
created_by: profile_id.get_string_repr().to_string(),
|
||||
algorithm: internal_program,
|
||||
metadata: Some(RoutingMetadata {
|
||||
kind: algorithm.get_kind().foreign_into(),
|
||||
algorithm_for: transaction_type.to_owned(),
|
||||
}),
|
||||
};
|
||||
|
||||
decision_engine_routing_id = create_de_euclid_routing_algo(&state, &routing_rule)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
// errors are ignored as this is just for diff checking as of now (optional flow).
|
||||
logger::error!(decision_engine_error=?e, "decision_engine_euclid");
|
||||
logger::debug!(decision_engine_request=?routing_rule, "decision_engine_euclid");
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
||||
if decision_engine_routing_id.is_some() {
|
||||
logger::info!(routing_flow=?"create_euclid_routing_algorithm", is_equal=?"true", "decision_engine_euclid");
|
||||
} else {
|
||||
logger::info!(routing_flow=?"create_euclid_routing_algorithm", is_equal=?"false", "decision_engine_euclid");
|
||||
}
|
||||
|
||||
let timestamp = common_utils::date_time::now();
|
||||
let algo = RoutingAlgorithm {
|
||||
algorithm_id: algorithm_id.clone(),
|
||||
@ -318,6 +378,7 @@ pub async fn create_routing_algorithm_under_profile(
|
||||
created_at: timestamp,
|
||||
modified_at: timestamp,
|
||||
algorithm_for: transaction_type.to_owned(),
|
||||
decision_engine_routing_id,
|
||||
};
|
||||
let record = db
|
||||
.insert_routing_algorithm(algo)
|
||||
@ -536,7 +597,7 @@ pub async fn link_routing_config(
|
||||
db,
|
||||
key_manager_state,
|
||||
merchant_context.get_merchant_key_store(),
|
||||
business_profile,
|
||||
business_profile.clone(),
|
||||
dynamic_routing_ref,
|
||||
)
|
||||
.await?;
|
||||
@ -578,14 +639,37 @@ pub async fn link_routing_config(
|
||||
db,
|
||||
key_manager_state,
|
||||
merchant_context.get_merchant_key_store(),
|
||||
business_profile,
|
||||
business_profile.clone(),
|
||||
routing_ref,
|
||||
transaction_type,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(euclid_routing_id) = routing_algorithm.decision_engine_routing_id.clone() {
|
||||
let routing_algo = ActivateRoutingConfigRequest {
|
||||
created_by: business_profile.get_id().get_string_repr().to_string(),
|
||||
routing_algorithm_id: euclid_routing_id,
|
||||
};
|
||||
let link_result = link_de_euclid_routing_algorithm(&state, routing_algo).await;
|
||||
match link_result {
|
||||
Ok(_) => {
|
||||
router_env::logger::info!(
|
||||
routing_flow=?"link_routing_algorithm",
|
||||
is_equal=?true,
|
||||
"decision_engine_euclid"
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
router_env::logger::info!(
|
||||
routing_flow=?"link_routing_algorithm",
|
||||
is_equal=?false,
|
||||
error=?e,
|
||||
"decision_engine_euclid"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
metrics::ROUTING_LINK_CONFIG_SUCCESS_RESPONSE.add(1, &[]);
|
||||
Ok(service_api::ApplicationResponse::Json(
|
||||
routing_algorithm.foreign_into(),
|
||||
@ -1436,6 +1520,7 @@ pub async fn success_based_routing_update_configs(
|
||||
created_at: timestamp,
|
||||
modified_at: timestamp,
|
||||
algorithm_for: dynamic_routing_algo_to_update.algorithm_for,
|
||||
decision_engine_routing_id: None,
|
||||
};
|
||||
let record = db
|
||||
.insert_routing_algorithm(algo)
|
||||
@ -1535,6 +1620,7 @@ pub async fn elimination_routing_update_configs(
|
||||
created_at: timestamp,
|
||||
modified_at: timestamp,
|
||||
algorithm_for: dynamic_routing_algo_to_update.algorithm_for,
|
||||
decision_engine_routing_id: None,
|
||||
};
|
||||
|
||||
let record = db
|
||||
@ -1680,6 +1766,7 @@ pub async fn contract_based_dynamic_routing_setup(
|
||||
created_at: timestamp,
|
||||
modified_at: timestamp,
|
||||
algorithm_for: common_enums::TransactionType::Payment,
|
||||
decision_engine_routing_id: None,
|
||||
};
|
||||
|
||||
// 1. if dynamic_routing_algo_ref already present, insert contract based algo and disable success based
|
||||
@ -1867,6 +1954,7 @@ pub async fn contract_based_routing_update_configs(
|
||||
created_at: timestamp,
|
||||
modified_at: timestamp,
|
||||
algorithm_for: dynamic_routing_algo_to_update.algorithm_for,
|
||||
decision_engine_routing_id: None,
|
||||
};
|
||||
let record = db
|
||||
.insert_routing_algorithm(algo)
|
||||
|
||||
Reference in New Issue
Block a user