From 2e2afe42b30d8d04d4c766fa83563e45539588c8 Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Wed, 8 Nov 2023 13:22:26 +0530 Subject: [PATCH 01/12] feat(router): profile specific fallback derivation while routing payments --- crates/router/Cargo.toml | 5 +- crates/router/src/core/payments/routing.rs | 58 +++++++++++++++++++--- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index 9ab955813336..b3fcee789aae 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -9,13 +9,13 @@ readme = "README.md" license.workspace = true [features] -default = ["kv_store", "stripe", "oltp", "olap", "backwards_compatibility", "accounts_cache", "dummy_connector", "payouts"] +default = ["kv_store", "stripe", "oltp", "olap", "backwards_compatibility", "accounts_cache", "dummy_connector", "payouts", "profile_specific_fallback_routing"] s3 = ["dep:aws-sdk-s3", "dep:aws-config"] kms = ["external_services/kms", "dep:aws-config"] email = ["external_services/email", "dep:aws-config"] basilisk = ["kms"] stripe = ["dep:serde_qs"] -release = ["kms", "stripe", "basilisk", "s3", "email", "business_profile_routing", "accounts_cache", "kv_store"] +release = ["kms", "stripe", "basilisk", "s3", "email", "business_profile_routing", "accounts_cache", "kv_store", "profile_specific_fallback_routing"] olap = ["data_models/olap", "storage_impl/olap", "scheduler/olap"] oltp = ["data_models/oltp", "storage_impl/oltp"] kv_store = ["scheduler/kv_store"] @@ -24,6 +24,7 @@ openapi = ["olap", "oltp", "payouts"] vergen = ["router_env/vergen"] backwards_compatibility = ["api_models/backwards_compatibility", "euclid/backwards_compatibility", "kgraph_utils/backwards_compatibility"] business_profile_routing=["api_models/business_profile_routing"] +profile_specific_fallback_routing = [] dummy_connector = ["api_models/dummy_connector", "euclid/dummy_connector", "kgraph_utils/dummy_connector"] connector_choice_mca_id = ["api_models/connector_choice_mca_id", "euclid/connector_choice_mca_id", "kgraph_utils/connector_choice_mca_id"] external_access_dc = ["dummy_connector"] diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 4134ddf65ea0..8b3a12ce9e83 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -207,10 +207,22 @@ pub async fn perform_static_routing_v1( let algorithm_id = if let Some(id) = algorithm_ref.algorithm_id { id } else { - let fallback_config = - routing_helpers::get_merchant_default_config(&*state.clone().store, merchant_id) - .await - .change_context(errors::RoutingError::FallbackConfigFetchFailed)?; + let fallback_config = routing_helpers::get_merchant_default_config( + &*state.clone().store, + #[cfg(not(feature = "profile_specific_fallback_routing"))] + merchant_id, + #[cfg(feature = "profile_specific_fallback_routing")] + { + payment_data + .payment_intent + .profile_id + .as_ref() + .get_required_value("profile_id") + .change_context(errors::RoutingError::ProfileIdMissing)? + }, + ) + .await + .change_context(errors::RoutingError::FallbackConfigFetchFailed)?; return Ok(fallback_config); }; @@ -616,10 +628,22 @@ pub async fn perform_fallback_routing( eligible_connectors: Option<&Vec>, #[cfg(feature = "business_profile_routing")] profile_id: Option, ) -> RoutingResult> { - let fallback_config = - routing_helpers::get_merchant_default_config(&*state.store, &key_store.merchant_id) - .await - .change_context(errors::RoutingError::FallbackConfigFetchFailed)?; + let fallback_config = routing_helpers::get_merchant_default_config( + &*state.store, + #[cfg(not(feature = "profile_specific_fallback_routing"))] + &key_store.merchant_id, + #[cfg(feature = "profile_specific_fallback_routing")] + { + payment_data + .payment_intent + .profile_id + .as_ref() + .get_required_value("profile_id") + .change_context(errors::RoutingError::ProfileIdMissing)? + }, + ) + .await + .change_context(errors::RoutingError::FallbackConfigFetchFailed)?; let backend_input = make_dsl_input(payment_data)?; perform_kgraph_filtering( @@ -880,7 +904,16 @@ async fn perform_session_routing_for_pm_type( } else { routing_helpers::get_merchant_default_config( &*session_pm_input.state.clone().store, + #[cfg(not(feature = "profile_specific_fallback_routing"))] merchant_id, + #[cfg(feature = "profile_specific_fallback_routing")] + { + session_pm_input + .profile_id + .as_ref() + .get_required_value("profile_id") + .change_context(errors::RoutingError::ProfileIdMissing)? + }, ) .await .change_context(errors::RoutingError::FallbackConfigFetchFailed)? @@ -903,7 +936,16 @@ async fn perform_session_routing_for_pm_type( if final_selection.is_empty() { let fallback = routing_helpers::get_merchant_default_config( &*session_pm_input.state.clone().store, + #[cfg(not(feature = "profile_specific_fallback_routing"))] merchant_id, + #[cfg(feature = "profile_specific_fallback_routing")] + { + session_pm_input + .profile_id + .as_ref() + .get_required_value("profile_id") + .change_context(errors::RoutingError::ProfileIdMissing)? + }, ) .await .change_context(errors::RoutingError::FallbackConfigFetchFailed)?; From 48ce244edebaa75baabacc063e8bc34a1a6cf0db Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Wed, 8 Nov 2023 14:58:31 +0530 Subject: [PATCH 02/12] refactor(router): resolved open-api errors --- crates/router/src/core/payments/routing.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 8b3a12ce9e83..3b89d4e38e4e 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -71,7 +71,10 @@ pub struct SessionRoutingPmTypeInput<'a> { routing_algorithm: &'a MerchantAccountRoutingAlgorithm, backend_input: dsl_inputs::BackendInput, allowed_connectors: FxHashMap, - #[cfg(feature = "business_profile_routing")] + #[cfg(any( + feature = "business_profile_routing", + feature = "profile_specific_fallback_routing" + ))] profile_id: Option, } static ROUTING_CACHE: StaticCache = StaticCache::new(); @@ -843,8 +846,11 @@ pub async fn perform_session_flow_routing( routing_algorithm: &routing_algorithm, backend_input: backend_input.clone(), allowed_connectors, - #[cfg(feature = "business_profile_routing")] - profile_id: session_input.payment_intent.clone().profile_id, + #[cfg(any( + feature = "business_profile_routing", + feature = "profile_specific_fallback_routing" + ))] + profile_id: session_input.payment_intent.profile_id.clone(), }; let maybe_choice = perform_session_routing_for_pm_type(session_pm_input).await?; From 83acfcfd25216cb61bc43e917e9af04763dbb213 Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Wed, 8 Nov 2023 17:31:57 +0530 Subject: [PATCH 03/12] feat(euclid): added routes for profile based fallbacks --- crates/api_models/src/routing.rs | 6 ++ crates/router/src/core/admin.rs | 19 +++- crates/router/src/core/routing.rs | 129 ++++++++++++++++++++++++++-- crates/router/src/routes/app.rs | 10 +++ crates/router/src/routes/routing.rs | 54 ++++++++++++ 5 files changed, 208 insertions(+), 10 deletions(-) diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index 95d4c5e10ece..1b043974fd5a 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -40,6 +40,12 @@ pub struct RoutingConfigRequest { pub profile_id: Option, } +#[derive(Debug, serde::Serialize)] +pub struct ProfileDefaultRoutingConfig { + pub profile_id: String, + pub connectors: Vec, +} + #[cfg(feature = "business_profile_routing")] #[derive(Debug, serde::Deserialize, serde::Serialize)] pub struct RoutingRetrieveQuery { diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index e1e5ea744e2f..24366ed36728 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -916,13 +916,19 @@ pub async fn create_payment_connector( let mut default_routing_config = routing_helpers::get_merchant_default_config(&*state.store, merchant_id).await?; + let mut default_routing_config_for_profile = routing_helpers::get_merchant_default_config( + &*state.clone().store, + &profile_id, + ) + .await?; + let mca = state .store .insert_merchant_connector_account(merchant_connector_account, &key_store) .await .to_duplicate_response( errors::ApiErrorResponse::DuplicateMerchantConnectorAccount { - profile_id, + profile_id: profile_id.clone(), connector_name: req.connector_name.to_string(), }, )?; @@ -939,7 +945,7 @@ pub async fn create_payment_connector( }; if !default_routing_config.contains(&choice) { - default_routing_config.push(choice); + default_routing_config.push(choice.clone()); routing_helpers::update_merchant_default_config( &*state.store, merchant_id, @@ -947,6 +953,15 @@ pub async fn create_payment_connector( ) .await?; } + if !default_routing_config_for_profile.contains(&choice.clone()) { + default_routing_config_for_profile.push(choice); + routing_helpers::update_merchant_default_config( + &*state.store, + &profile_id.clone(), + default_routing_config_for_profile, + ) + .await?; + } } metrics::MCA_CREATE.add( diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs index 8033cc792b54..9f7b2ead3741 100644 --- a/crates/router/src/core/routing.rs +++ b/crates/router/src/core/routing.rs @@ -13,13 +13,11 @@ use diesel_models::routing_algorithm::RoutingAlgorithm; use error_stack::{IntoReport, ResultExt}; use rustc_hash::FxHashSet; -#[cfg(feature = "business_profile_routing")] -use crate::core::utils::validate_and_get_business_profile; #[cfg(feature = "business_profile_routing")] use crate::types::transformers::{ForeignInto, ForeignTryInto}; use crate::{ consts, - core::errors::{RouterResponse, StorageErrorExt}, + core::errors::{RouterResponse, StorageErrorExt, utils as core_utils}, routes::AppState, types::domain, utils::{self, OptionExt, ValueExt}, @@ -111,7 +109,7 @@ pub async fn create_routing_config( }) .attach_printable("Profile_id not provided")?; - validate_and_get_business_profile(db, Some(&profile_id), &merchant_account.merchant_id) + core_utils::validate_and_get_business_profile(db, Some(&profile_id), &merchant_account.merchant_id) .await?; helpers::validate_connectors_in_routing_config( @@ -229,7 +227,7 @@ pub async fn link_routing_config( .await .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?; - let business_profile = validate_and_get_business_profile( + let business_profile = care_utils::validate_and_get_business_profile( db, Some(&routing_algorithm.profile_id), &merchant_account.merchant_id, @@ -332,7 +330,7 @@ pub async fn retrieve_routing_config( .await .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?; - validate_and_get_business_profile( + core_utils::validate_and_get_business_profile( db, Some(&routing_algorithm.profile_id), &merchant_account.merchant_id, @@ -402,7 +400,7 @@ pub async fn unlink_routing_config( }) .attach_printable("Profile_id not provided")?; let business_profile = - validate_and_get_business_profile(db, Some(&profile_id), &merchant_account.merchant_id) + core_utils::validate_and_get_business_profile(db, Some(&profile_id), &merchant_account.merchant_id) .await?; match business_profile { Some(business_profile) => { @@ -622,7 +620,7 @@ pub async fn retrieve_linked_routing_config( #[cfg(feature = "business_profile_routing")] { let business_profiles = if let Some(profile_id) = query_params.profile_id { - validate_and_get_business_profile(db, Some(&profile_id), &merchant_account.merchant_id) + core_utils::validate_and_get_business_profile(db, Some(&profile_id), &merchant_account.merchant_id) .await? .map(|profile| vec![profile]) .get_required_value("BusinessProfile") @@ -711,3 +709,118 @@ pub async fn retrieve_linked_routing_config( Ok(service_api::ApplicationResponse::Json(response)) } } + +pub async fn retrieve_default_routing_config_for_profiles( + state: AppState, + merchant_account: domain::MerchantAccount, +) -> RouterResponse> { + let db = state.store.as_ref(); + + let all_profiles = db + .list_business_profile_by_merchant_id(&merchant_account.merchant_id) + .await + .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound) + .attach_printable("error retrieving all business profiles for merchant")?; + + let retrieve_config_futures = all_profiles + .iter() + .map(|prof| helpers::get_merchant_default_config(db, &prof.profile_id)) + .collect::>(); + + let configs = futures::future::join_all(retrieve_config_futures) + .await + .into_iter() + .collect::, _>>()?; + + let default_configs = configs + .into_iter() + .zip(all_profiles.iter().map(|prof| prof.profile_id.clone())) + .map( + |(config, profile_id)| routing_types::ProfileDefaultRoutingConfig { + profile_id, + connectors: config, + }, + ) + .collect::>(); + + Ok(service_api::ApplicationResponse::Json(default_configs)) +} + +pub async fn update_default_routing_config_for_profile( + state: AppState, + merchant_account: domain::MerchantAccount, + updated_config: Vec, + profile_id: String, +) -> RouterResponse { + let db = state.store.as_ref(); + + let business_profile = core_utils::validate_and_get_business_profile( + db, + Some(&profile_id), + &merchant_account.merchant_id, + ) + .await? + .get_required_value("BusinessProfile") + .change_context(errors::ApiErrorResponse::BusinessProfileNotFound { id: profile_id })?; + let default_config = + helpers::get_merchant_default_config(db, &business_profile.profile_id).await?; + + utils::when(default_config.len() != updated_config.len(), || { + Err(errors::ApiErrorResponse::PreconditionFailed { + message: "current config and updated config have different lengths".to_string(), + }) + .into_report() + })?; + + let existing_set = FxHashSet::from_iter(default_config.iter().map(|c| { + ( + c.connector.to_string(), + #[cfg(feature = "connector_choice_mca_id")] + c.merchant_connector_id.as_ref(), + #[cfg(not(feature = "connector_choice_mca_id"))] + c.sub_label.as_ref(), + ) + })); + + let updated_set = FxHashSet::from_iter(updated_config.iter().map(|c| { + ( + c.connector.to_string(), + #[cfg(feature = "connector_choice_mca_id")] + c.merchant_connector_id.as_ref(), + #[cfg(not(feature = "connector_choice_mca_id"))] + c.sub_label.as_ref(), + ) + })); + + let symmetric_diff = existing_set + .symmetric_difference(&updated_set) + .cloned() + .collect::>(); + + utils::when(!symmetric_diff.is_empty(), || { + let error_str = symmetric_diff + .into_iter() + .map(|(connector, ident)| format!("'{connector}:{ident:?}'")) + .collect::>() + .join(", "); + + Err(errors::ApiErrorResponse::InvalidRequestData { + message: format!("connector mismatch between old and new configs ({error_str})"), + }) + .into_report() + })?; + + helpers::update_merchant_default_config( + db, + &business_profile.profile_id, + updated_config.clone(), + ) + .await?; + + Ok(service_api::ApplicationResponse::Json( + routing_types::ProfileDefaultRoutingConfig { + profile_id: business_profile.profile_id, + connectors: updated_config, + }, + )) +} diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 268b2ed703bf..8dbc440aa7de 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -312,6 +312,16 @@ impl Routing { web::resource("/{algorithm_id}/activate") .route(web::post().to(cloud_routing::routing_link_config)), ) + .service( + web::resource("/default/profile/{profile_id}").route( + web::post().to(cloud_routing::routing_update_default_config_for_profile), + ), + ) + .service( + web::resource("/default/profile").route( + web::get().to(cloud_routing::routing_retrieve_default_config_for_profiles), + ), + ) } } diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs index 1d5ccdf502fc..671bd3321472 100644 --- a/crates/router/src/routes/routing.rs +++ b/crates/router/src/routes/routing.rs @@ -296,3 +296,57 @@ pub async fn routing_retrieve_linked_config( .await } } + +#[cfg(feature = "olap")] +#[instrument(skip_all)] +pub async fn routing_retrieve_default_config_for_profiles( + state: web::Data, + req: HttpRequest, +) -> impl Responder { + oss_api::server_wrap( + Flow::RoutingRetrieveDefaultConfig, + state, + &req, + (), + |state, auth: oss_auth::AuthenticationData, _| { + routing::retrieve_default_routing_config_for_profiles(state, auth.merchant_account) + }, + #[cfg(not(feature = "release"))] + auth::auth_type(&oss_auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), + #[cfg(feature = "release")] + &auth::JWTAuth, + api_locking::LockAction::NotApplicable, + ) + .await +} + +#[cfg(feature = "olap")] +#[instrument(skip_all)] +pub async fn routing_update_default_config_for_profile( + state: web::Data, + req: HttpRequest, + path: web::Path, + json_payload: web::Json>, +) -> impl Responder { + oss_api::server_wrap( + Flow::RoutingUpdateDefaultConfig, + state, + &req, + (json_payload.into_inner(), path.into_inner()), + |state, auth: oss_auth::AuthenticationData, (updated_config, profile_id)| { + routing::update_default_routing_config_for_profile( + state, + auth.merchant_account, + updated_config, + profile_id, + ) + }, + #[cfg(not(feature = "release"))] + auth::auth_type(&oss_auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), + #[cfg(feature = "release")] + &auth::JWTAuth, + api_locking::LockAction::NotApplicable, + ) + .await +} + From aa6426ed54f28f475a5950bf723dbdee936f898e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 12:02:34 +0000 Subject: [PATCH 04/12] chore: run formatter --- crates/router/src/core/admin.rs | 7 ++---- crates/router/src/core/routing.rs | 35 ++++++++++++++++++----------- crates/router/src/routes/routing.rs | 1 - 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 24366ed36728..5ccd9e964866 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -916,11 +916,8 @@ pub async fn create_payment_connector( let mut default_routing_config = routing_helpers::get_merchant_default_config(&*state.store, merchant_id).await?; - let mut default_routing_config_for_profile = routing_helpers::get_merchant_default_config( - &*state.clone().store, - &profile_id, - ) - .await?; + let mut default_routing_config_for_profile = + routing_helpers::get_merchant_default_config(&*state.clone().store, &profile_id).await?; let mca = state .store diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs index 9f7b2ead3741..e331e8368091 100644 --- a/crates/router/src/core/routing.rs +++ b/crates/router/src/core/routing.rs @@ -17,7 +17,7 @@ use rustc_hash::FxHashSet; use crate::types::transformers::{ForeignInto, ForeignTryInto}; use crate::{ consts, - core::errors::{RouterResponse, StorageErrorExt, utils as core_utils}, + core::errors::{utils as core_utils, RouterResponse, StorageErrorExt}, routes::AppState, types::domain, utils::{self, OptionExt, ValueExt}, @@ -109,8 +109,12 @@ pub async fn create_routing_config( }) .attach_printable("Profile_id not provided")?; - core_utils::validate_and_get_business_profile(db, Some(&profile_id), &merchant_account.merchant_id) - .await?; + core_utils::validate_and_get_business_profile( + db, + Some(&profile_id), + &merchant_account.merchant_id, + ) + .await?; helpers::validate_connectors_in_routing_config( db, @@ -399,9 +403,12 @@ pub async fn unlink_routing_config( field_name: "profile_id", }) .attach_printable("Profile_id not provided")?; - let business_profile = - core_utils::validate_and_get_business_profile(db, Some(&profile_id), &merchant_account.merchant_id) - .await?; + let business_profile = core_utils::validate_and_get_business_profile( + db, + Some(&profile_id), + &merchant_account.merchant_id, + ) + .await?; match business_profile { Some(business_profile) => { let routing_algo_ref: routing_types::RoutingAlgorithmRef = business_profile @@ -620,13 +627,15 @@ pub async fn retrieve_linked_routing_config( #[cfg(feature = "business_profile_routing")] { let business_profiles = if let Some(profile_id) = query_params.profile_id { - core_utils::validate_and_get_business_profile(db, Some(&profile_id), &merchant_account.merchant_id) - .await? - .map(|profile| vec![profile]) - .get_required_value("BusinessProfile") - .change_context(errors::ApiErrorResponse::BusinessProfileNotFound { - id: profile_id, - })? + core_utils::validate_and_get_business_profile( + db, + Some(&profile_id), + &merchant_account.merchant_id, + ) + .await? + .map(|profile| vec![profile]) + .get_required_value("BusinessProfile") + .change_context(errors::ApiErrorResponse::BusinessProfileNotFound { id: profile_id })? } else { db.list_business_profile_by_merchant_id(&merchant_account.merchant_id) .await diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs index 671bd3321472..83976928b232 100644 --- a/crates/router/src/routes/routing.rs +++ b/crates/router/src/routes/routing.rs @@ -349,4 +349,3 @@ pub async fn routing_update_default_config_for_profile( ) .await } - From d6ae03ce0418171bf8ec81d0619730ea73919506 Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Wed, 8 Nov 2023 19:28:00 +0530 Subject: [PATCH 05/12] feat(euclid): added routes for profile based fallbacks --- crates/router/src/core/routing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs index 9f7b2ead3741..e7fae828111d 100644 --- a/crates/router/src/core/routing.rs +++ b/crates/router/src/core/routing.rs @@ -17,7 +17,7 @@ use rustc_hash::FxHashSet; use crate::types::transformers::{ForeignInto, ForeignTryInto}; use crate::{ consts, - core::errors::{RouterResponse, StorageErrorExt, utils as core_utils}, + core::{errors::{RouterResponse, StorageErrorExt}, utils as core_utils}, routes::AppState, types::domain, utils::{self, OptionExt, ValueExt}, From 0d88d925e07bac37c988630953f60c21c29a6ab5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 8 Nov 2023 13:59:53 +0000 Subject: [PATCH 06/12] chore: run formatter --- crates/router/src/core/routing.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs index fb03d49892c4..580d3140a809 100644 --- a/crates/router/src/core/routing.rs +++ b/crates/router/src/core/routing.rs @@ -17,7 +17,10 @@ use rustc_hash::FxHashSet; use crate::types::transformers::{ForeignInto, ForeignTryInto}; use crate::{ consts, - core::{errors::{RouterResponse, StorageErrorExt}, utils as core_utils}, + core::{ + errors::{RouterResponse, StorageErrorExt}, + utils as core_utils, + }, routes::AppState, types::domain, utils::{self, OptionExt, ValueExt}, From 73b0e5e2c387b09b44a0222bd267688cd3482cdd Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Wed, 8 Nov 2023 19:40:25 +0530 Subject: [PATCH 07/12] feat(euclid): updated imports --- crates/router/src/core/routing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs index fb03d49892c4..fd401091609a 100644 --- a/crates/router/src/core/routing.rs +++ b/crates/router/src/core/routing.rs @@ -231,7 +231,7 @@ pub async fn link_routing_config( .await .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?; - let business_profile = care_utils::validate_and_get_business_profile( + let business_profile = core_utils::validate_and_get_business_profile( db, Some(&routing_algorithm.profile_id), &merchant_account.merchant_id, From 3d6a634550f744efe953af1d88843bc3b3c24136 Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Thu, 9 Nov 2023 18:06:20 +0530 Subject: [PATCH 08/12] feat(euclid): ApiEventMetric addition --- crates/api_models/src/events/routing.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/api_models/src/events/routing.rs b/crates/api_models/src/events/routing.rs index 5eca01acc6fb..b14ca81cd702 100644 --- a/crates/api_models/src/events/routing.rs +++ b/crates/api_models/src/events/routing.rs @@ -2,7 +2,7 @@ use common_utils::events::{ApiEventMetric, ApiEventsType}; use crate::routing::{ LinkedRoutingConfigRetrieveResponse, MerchantRoutingAlgorithm, RoutingAlgorithmId, - RoutingConfigRequest, RoutingDictionaryRecord, RoutingKind, + RoutingConfigRequest, RoutingDictionaryRecord, RoutingKind, RoutableConnectorChoice, ProfileDefaultRoutingConfig, }; #[cfg(feature = "business_profile_routing")] use crate::routing::{RoutingRetrieveLinkQuery, RoutingRetrieveQuery}; @@ -37,6 +37,19 @@ impl ApiEventMetric for LinkedRoutingConfigRetrieveResponse { } } +impl ApiEventMetric for Vec +{ + fn get_api_event_type(&self) -> Option { + Some(ApiEventsType::Routing) + } +} + +impl ApiEventMetric for ProfileDefaultRoutingConfig { + fn get_api_event_type(&self) -> Option { + Some(ApiEventsType::Routing) + } +} + #[cfg(feature = "business_profile_routing")] impl ApiEventMetric for RoutingRetrieveQuery { fn get_api_event_type(&self) -> Option { From 49d35bb5b80c6ac3f5555f73c6e157f4178152a3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 9 Nov 2023 12:37:05 +0000 Subject: [PATCH 09/12] chore: run formatter --- crates/api_models/src/events/routing.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/api_models/src/events/routing.rs b/crates/api_models/src/events/routing.rs index b14ca81cd702..2392c3c96b6d 100644 --- a/crates/api_models/src/events/routing.rs +++ b/crates/api_models/src/events/routing.rs @@ -1,8 +1,9 @@ use common_utils::events::{ApiEventMetric, ApiEventsType}; use crate::routing::{ - LinkedRoutingConfigRetrieveResponse, MerchantRoutingAlgorithm, RoutingAlgorithmId, - RoutingConfigRequest, RoutingDictionaryRecord, RoutingKind, RoutableConnectorChoice, ProfileDefaultRoutingConfig, + LinkedRoutingConfigRetrieveResponse, MerchantRoutingAlgorithm, ProfileDefaultRoutingConfig, + RoutableConnectorChoice, RoutingAlgorithmId, RoutingConfigRequest, RoutingDictionaryRecord, + RoutingKind, }; #[cfg(feature = "business_profile_routing")] use crate::routing::{RoutingRetrieveLinkQuery, RoutingRetrieveQuery}; @@ -37,8 +38,7 @@ impl ApiEventMetric for LinkedRoutingConfigRetrieveResponse { } } -impl ApiEventMetric for Vec -{ +impl ApiEventMetric for Vec { fn get_api_event_type(&self) -> Option { Some(ApiEventsType::Routing) } From f68465f679d4fbccb98ca0752469f5f2d3950e9d Mon Sep 17 00:00:00 2001 From: Aprabhat19 Date: Thu, 9 Nov 2023 23:23:59 +0530 Subject: [PATCH 10/12] feat(euclid): add APiEventMetric impl to a Wrapper struct --- crates/api_models/src/events/routing.rs | 7 +++---- crates/api_models/src/routing.rs | 4 ++++ crates/router/src/routes/routing.rs | 7 +++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/crates/api_models/src/events/routing.rs b/crates/api_models/src/events/routing.rs index 2392c3c96b6d..a09735bc5722 100644 --- a/crates/api_models/src/events/routing.rs +++ b/crates/api_models/src/events/routing.rs @@ -2,8 +2,8 @@ use common_utils::events::{ApiEventMetric, ApiEventsType}; use crate::routing::{ LinkedRoutingConfigRetrieveResponse, MerchantRoutingAlgorithm, ProfileDefaultRoutingConfig, - RoutableConnectorChoice, RoutingAlgorithmId, RoutingConfigRequest, RoutingDictionaryRecord, - RoutingKind, + RoutingAlgorithmId, RoutingConfigRequest, RoutingDictionaryRecord, RoutingKind, + RoutingPayloadWrapper, }; #[cfg(feature = "business_profile_routing")] use crate::routing::{RoutingRetrieveLinkQuery, RoutingRetrieveQuery}; @@ -38,12 +38,11 @@ impl ApiEventMetric for LinkedRoutingConfigRetrieveResponse { } } -impl ApiEventMetric for Vec { +impl ApiEventMetric for RoutingPayloadWrapper { fn get_api_event_type(&self) -> Option { Some(ApiEventsType::Routing) } } - impl ApiEventMetric for ProfileDefaultRoutingConfig { fn get_api_event_type(&self) -> Option { Some(ApiEventsType::Routing) diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index c781ca425d49..d2d6639191a6 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -395,6 +395,10 @@ pub enum RoutingAlgorithmKind { Advanced, } +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] + +pub struct RoutingPayloadWrapper(pub Vec, pub String); + #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde( tag = "type", diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs index db35322ddf08..7b95144b98eb 100644 --- a/crates/router/src/routes/routing.rs +++ b/crates/router/src/routes/routing.rs @@ -328,12 +328,15 @@ pub async fn routing_update_default_config_for_profile( path: web::Path, json_payload: web::Json>, ) -> impl Responder { + let routing_payload_wrapper = + routing_types::RoutingPayloadWrapper(json_payload.into_inner(), path.into_inner()); oss_api::server_wrap( Flow::RoutingUpdateDefaultConfig, state, &req, - (json_payload.into_inner(), path.into_inner()), - |state, auth: oss_auth::AuthenticationData, (updated_config, profile_id)| { + routing_payload_wrapper, + |state, auth: oss_auth::AuthenticationData, wrapper| { + let (updated_config, profile_id) = (wrapper.0, wrapper.1); routing::update_default_routing_config_for_profile( state, auth.merchant_account, From b85493024104c5b0d70908a18297092f09c56092 Mon Sep 17 00:00:00 2001 From: Aprabhat19 Date: Fri, 10 Nov 2023 13:36:05 +0530 Subject: [PATCH 11/12] make the type as a struct --- crates/api_models/src/routing.rs | 5 ++++- crates/router/src/routes/routing.rs | 11 ++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs index d2d6639191a6..363df5389a79 100644 --- a/crates/api_models/src/routing.rs +++ b/crates/api_models/src/routing.rs @@ -397,7 +397,10 @@ pub enum RoutingAlgorithmKind { #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct RoutingPayloadWrapper(pub Vec, pub String); +pub struct RoutingPayloadWrapper { + pub updated_config: Vec, + pub profile_id: String, +} #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde( diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs index 7b95144b98eb..7c6f1528f169 100644 --- a/crates/router/src/routes/routing.rs +++ b/crates/router/src/routes/routing.rs @@ -328,20 +328,21 @@ pub async fn routing_update_default_config_for_profile( path: web::Path, json_payload: web::Json>, ) -> impl Responder { - let routing_payload_wrapper = - routing_types::RoutingPayloadWrapper(json_payload.into_inner(), path.into_inner()); + let routing_payload_wrapper = routing_types::RoutingPayloadWrapper { + updated_config: json_payload.into_inner(), + profile_id: path.into_inner(), + }; oss_api::server_wrap( Flow::RoutingUpdateDefaultConfig, state, &req, routing_payload_wrapper, |state, auth: oss_auth::AuthenticationData, wrapper| { - let (updated_config, profile_id) = (wrapper.0, wrapper.1); routing::update_default_routing_config_for_profile( state, auth.merchant_account, - updated_config, - profile_id, + wrapper.updated_config, + wrapper.profile_id, ) }, #[cfg(not(feature = "release"))] From bcf1a5798068c1c7873ab7cda0b8da24fb5e93b3 Mon Sep 17 00:00:00 2001 From: prajjwalkumar17 Date: Mon, 13 Nov 2023 14:12:26 +0530 Subject: [PATCH 12/12] feat(euclid): added the auth --- crates/router/src/routes/routing.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs index f2bd31576743..606111a88818 100644 --- a/crates/router/src/routes/routing.rs +++ b/crates/router/src/routes/routing.rs @@ -308,11 +308,11 @@ pub async fn routing_retrieve_default_config_for_profiles( state, &req, (), - |state, auth: oss_auth::AuthenticationData, _| { + |state, auth: auth::AuthenticationData, _| { routing::retrieve_default_routing_config_for_profiles(state, auth.merchant_account) }, #[cfg(not(feature = "release"))] - auth::auth_type(&oss_auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), + auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), #[cfg(feature = "release")] &auth::JWTAuth, api_locking::LockAction::NotApplicable, @@ -337,7 +337,7 @@ pub async fn routing_update_default_config_for_profile( state, &req, routing_payload_wrapper, - |state, auth: oss_auth::AuthenticationData, wrapper| { + |state, auth: auth::AuthenticationData, wrapper| { routing::update_default_routing_config_for_profile( state, auth.merchant_account, @@ -346,7 +346,7 @@ pub async fn routing_update_default_config_for_profile( ) }, #[cfg(not(feature = "release"))] - auth::auth_type(&oss_auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), + auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()), #[cfg(feature = "release")] &auth::JWTAuth, api_locking::LockAction::NotApplicable,