mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-03 05:17:02 +08:00
refactor(routing): Api v2 for routing create and activate endpoints (#5423)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -7,15 +7,23 @@ use api_models::{
|
||||
self as routing_types, RoutingAlgorithmId, RoutingRetrieveLinkQuery, RoutingRetrieveQuery,
|
||||
},
|
||||
};
|
||||
#[cfg(all(feature = "v2", feature = "routing_v2"))]
|
||||
use diesel_models::routing_algorithm::RoutingAlgorithm;
|
||||
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "routing_v2")))]
|
||||
use diesel_models::routing_algorithm::RoutingAlgorithm;
|
||||
use error_stack::ResultExt;
|
||||
#[cfg(all(feature = "v2", feature = "routing_v2"))]
|
||||
use masking::Secret;
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use super::payments;
|
||||
#[cfg(feature = "payouts")]
|
||||
use super::payouts;
|
||||
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "routing_v2")))]
|
||||
use crate::consts;
|
||||
#[cfg(all(feature = "v2", feature = "routing_v2"))]
|
||||
use crate::{consts, core::errors::RouterResult, db::StorageInterface};
|
||||
use crate::{
|
||||
consts,
|
||||
core::{
|
||||
errors::{self, RouterResponse, StorageErrorExt},
|
||||
metrics, utils as core_utils,
|
||||
@ -28,7 +36,6 @@ use crate::{
|
||||
},
|
||||
utils::{self, OptionExt, ValueExt},
|
||||
};
|
||||
|
||||
pub enum TransactionData<'a, F>
|
||||
where
|
||||
F: Clone,
|
||||
@ -38,6 +45,77 @@ where
|
||||
Payout(&'a payouts::PayoutData),
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "routing_v2"))]
|
||||
struct RoutingAlgorithmUpdate(RoutingAlgorithm);
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "routing_v2"))]
|
||||
impl RoutingAlgorithmUpdate {
|
||||
pub fn create_new_routing_algorithm(
|
||||
algorithm: routing_types::RoutingAlgorithm,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
name: String,
|
||||
description: String,
|
||||
profile_id: String,
|
||||
transaction_type: &enums::TransactionType,
|
||||
) -> Self {
|
||||
let algorithm_id = common_utils::generate_id(
|
||||
consts::ROUTING_CONFIG_ID_LENGTH,
|
||||
&format!("routing_{}", merchant_id.get_string_repr()),
|
||||
);
|
||||
let timestamp = common_utils::date_time::now();
|
||||
let algo = RoutingAlgorithm {
|
||||
algorithm_id,
|
||||
profile_id,
|
||||
merchant_id: merchant_id.clone(),
|
||||
name,
|
||||
description: Some(description),
|
||||
kind: algorithm.get_kind().foreign_into(),
|
||||
algorithm_data: serde_json::json!(algorithm),
|
||||
created_at: timestamp,
|
||||
modified_at: timestamp,
|
||||
algorithm_for: transaction_type.to_owned(),
|
||||
};
|
||||
Self(algo)
|
||||
}
|
||||
pub async fn fetch_routing_algo(
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
algorithm_id: &str,
|
||||
db: &dyn StorageInterface,
|
||||
) -> RouterResult<Self> {
|
||||
let routing_algo = db
|
||||
.find_routing_algorithm_by_algorithm_id_merchant_id(algorithm_id, merchant_id)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::ResourceIdNotFound)?;
|
||||
Ok(Self(routing_algo))
|
||||
}
|
||||
|
||||
pub fn update_routing_ref_with_algorithm_id(
|
||||
&self,
|
||||
transaction_type: &enums::TransactionType,
|
||||
routing_ref: &mut routing_types::RoutingAlgorithmRef,
|
||||
) -> RouterResult<()> {
|
||||
utils::when(self.0.algorithm_for != *transaction_type, || {
|
||||
Err(errors::ApiErrorResponse::PreconditionFailed {
|
||||
message: format!(
|
||||
"Cannot use {}'s routing algorithm for {} operation",
|
||||
self.0.algorithm_for, transaction_type
|
||||
),
|
||||
})
|
||||
})?;
|
||||
|
||||
utils::when(
|
||||
routing_ref.algorithm_id == Some(self.0.algorithm_id.clone()),
|
||||
|| {
|
||||
Err(errors::ApiErrorResponse::PreconditionFailed {
|
||||
message: "Algorithm is already active".to_string(),
|
||||
})
|
||||
},
|
||||
)?;
|
||||
routing_ref.update_algorithm_id(self.0.algorithm_id.clone());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn retrieve_merchant_routing_dictionary(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
@ -67,6 +145,94 @@ pub async fn retrieve_merchant_routing_dictionary(
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "routing_v2"))]
|
||||
pub async fn create_routing_config(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
key_store: domain::MerchantKeyStore,
|
||||
request: routing_types::RoutingConfigRequest,
|
||||
transaction_type: &enums::TransactionType,
|
||||
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
|
||||
metrics::ROUTING_CREATE_REQUEST_RECEIVED.add(&metrics::CONTEXT, 1, &[]);
|
||||
let db = &*state.store;
|
||||
let name = request
|
||||
.name
|
||||
.get_required_value("name")
|
||||
.change_context(errors::ApiErrorResponse::MissingRequiredField { field_name: "name" })
|
||||
.attach_printable("Name of config not given")?;
|
||||
|
||||
let description = request
|
||||
.description
|
||||
.get_required_value("description")
|
||||
.change_context(errors::ApiErrorResponse::MissingRequiredField {
|
||||
field_name: "description",
|
||||
})
|
||||
.attach_printable("Description of config not given")?;
|
||||
|
||||
let algorithm = request
|
||||
.algorithm
|
||||
.get_required_value("algorithm")
|
||||
.change_context(errors::ApiErrorResponse::MissingRequiredField {
|
||||
field_name: "algorithm",
|
||||
})
|
||||
.attach_printable("Algorithm of config not given")?;
|
||||
|
||||
let business_profile = core_utils::validate_and_get_business_profile(
|
||||
db,
|
||||
request.profile_id.as_ref(),
|
||||
merchant_account.get_id(),
|
||||
)
|
||||
.await?
|
||||
.get_required_value("BusinessProfile")?;
|
||||
|
||||
let all_mcas = helpers::MerchantConnectorAccounts::get_all_mcas(
|
||||
merchant_account.get_id(),
|
||||
&key_store,
|
||||
&state,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let name_mca_id_set = helpers::ConnectNameAndMCAIdForProfile(
|
||||
all_mcas.filter_by_profile(&business_profile.profile_id, |mca| {
|
||||
(&mca.connector_name, &mca.merchant_connector_id)
|
||||
}),
|
||||
);
|
||||
|
||||
let name_set = helpers::ConnectNameForProfile(
|
||||
all_mcas.filter_by_profile(&business_profile.profile_id, |mca| &mca.connector_name),
|
||||
);
|
||||
|
||||
let algorithm_helper = helpers::RoutingAlgorithmHelpers {
|
||||
name_mca_id_set,
|
||||
name_set,
|
||||
routing_algorithm: &algorithm,
|
||||
};
|
||||
|
||||
algorithm_helper.validate_connectors_in_routing_config()?;
|
||||
|
||||
let algo = RoutingAlgorithmUpdate::create_new_routing_algorithm(
|
||||
algorithm,
|
||||
merchant_account.get_id(),
|
||||
name,
|
||||
description,
|
||||
business_profile.profile_id,
|
||||
transaction_type,
|
||||
);
|
||||
|
||||
let record = state
|
||||
.store
|
||||
.as_ref()
|
||||
.insert_routing_algorithm(algo.0)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;
|
||||
|
||||
let new_record = record.foreign_into();
|
||||
|
||||
metrics::ROUTING_CREATE_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]);
|
||||
Ok(service_api::ApplicationResponse::Json(new_record))
|
||||
}
|
||||
|
||||
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "routing_v2")))]
|
||||
pub async fn create_routing_config(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
@ -76,7 +242,6 @@ pub async fn create_routing_config(
|
||||
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
|
||||
metrics::ROUTING_CREATE_REQUEST_RECEIVED.add(&metrics::CONTEXT, 1, &[]);
|
||||
let db = state.store.as_ref();
|
||||
|
||||
let name = request
|
||||
.name
|
||||
.get_required_value("name")
|
||||
@ -148,6 +313,56 @@ pub async fn create_routing_config(
|
||||
Ok(service_api::ApplicationResponse::Json(new_record))
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "routing_v2"))]
|
||||
pub async fn link_routing_config(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
profile_id: String,
|
||||
algorithm_id: String,
|
||||
transaction_type: &enums::TransactionType,
|
||||
) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
|
||||
metrics::ROUTING_LINK_CONFIG.add(&metrics::CONTEXT, 1, &[]);
|
||||
let db = state.store.as_ref();
|
||||
|
||||
let routing_algorithm =
|
||||
RoutingAlgorithmUpdate::fetch_routing_algo(merchant_account.get_id(), &algorithm_id, db)
|
||||
.await?;
|
||||
utils::when(routing_algorithm.0.profile_id != profile_id, || {
|
||||
Err(errors::ApiErrorResponse::PreconditionFailed {
|
||||
message: "Profile Id is invalid for the routing config".to_string(),
|
||||
})
|
||||
})?;
|
||||
let business_profile = core_utils::validate_and_get_business_profile(
|
||||
db,
|
||||
Some(&profile_id),
|
||||
merchant_account.get_id(),
|
||||
)
|
||||
.await?
|
||||
.get_required_value("BusinessProfile")?;
|
||||
|
||||
let mut routing_ref = routing_types::RoutingAlgorithmRef::parse_routing_algorithm(
|
||||
business_profile.routing_algorithm.clone().map(Secret::new),
|
||||
)
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("unable to deserialize routing algorithm ref from merchant account")?
|
||||
.unwrap_or_default();
|
||||
|
||||
routing_algorithm.update_routing_ref_with_algorithm_id(transaction_type, &mut routing_ref)?;
|
||||
// TODO move to business profile
|
||||
helpers::update_business_profile_active_algorithm_ref(
|
||||
db,
|
||||
business_profile,
|
||||
routing_ref,
|
||||
transaction_type,
|
||||
)
|
||||
.await?;
|
||||
metrics::ROUTING_LINK_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]);
|
||||
Ok(service_api::ApplicationResponse::Json(
|
||||
routing_algorithm.0.foreign_into(),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "routing_v2")))]
|
||||
pub async fn link_routing_config(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
@ -249,6 +464,7 @@ pub async fn retrieve_routing_config(
|
||||
metrics::ROUTING_RETRIEVE_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]);
|
||||
Ok(service_api::ApplicationResponse::Json(response))
|
||||
}
|
||||
|
||||
pub async fn unlink_routing_config(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
@ -326,6 +542,7 @@ pub async fn unlink_routing_config(
|
||||
}
|
||||
}
|
||||
|
||||
//feature update
|
||||
pub async fn update_default_routing_config(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
|
||||
@ -12,6 +12,8 @@ use error_stack::ResultExt;
|
||||
use rustc_hash::FxHashSet;
|
||||
use storage_impl::redis::cache;
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "routing_v2"))]
|
||||
use crate::types::domain::MerchantConnectorAccount;
|
||||
use crate::{
|
||||
core::errors::{self, RouterResult},
|
||||
db::StorageInterface,
|
||||
@ -20,54 +22,6 @@ use crate::{
|
||||
utils::StringExt,
|
||||
};
|
||||
|
||||
/// provides the complete merchant routing dictionary that is basically a list of all the routing
|
||||
/// configs a merchant configured with an active_id field that specifies the current active routing
|
||||
/// config
|
||||
// pub async fn get_merchant_routing_dictionary(
|
||||
// db: &dyn StorageInterface,
|
||||
// merchant_id: &str,
|
||||
// ) -> RouterResult<routing_types::RoutingDictionary> {
|
||||
// let key = get_routing_dictionary_key(merchant_id);
|
||||
// let maybe_dict = db.find_config_by_key(&key).await;
|
||||
|
||||
// match maybe_dict {
|
||||
// Ok(config) => config
|
||||
// .config
|
||||
// .parse_struct("RoutingDictionary")
|
||||
// .change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
// .attach_printable("Merchant routing dictionary has invalid structure"),
|
||||
|
||||
// Err(e) if e.current_context().is_db_not_found() => {
|
||||
// let new_dictionary = routing_types::RoutingDictionary {
|
||||
// merchant_id: merchant_id.to_owned(),
|
||||
// active_id: None,
|
||||
// records: Vec::new(),
|
||||
// };
|
||||
|
||||
// let serialized = new_dictionary
|
||||
// .encode_to_string_of_json()
|
||||
// .change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
// .attach_printable("Error serializing newly created merchant dictionary")?;
|
||||
|
||||
// let new_config = configs::ConfigNew {
|
||||
// key,
|
||||
// config: serialized,
|
||||
// };
|
||||
|
||||
// db.insert_config(new_config)
|
||||
// .await
|
||||
// .change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
// .attach_printable("Error inserting new routing dictionary for merchant")?;
|
||||
|
||||
// Ok(new_dictionary)
|
||||
// }
|
||||
|
||||
// Err(e) => Err(e)
|
||||
// .change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
// .attach_printable("Error fetching routing dictionary for merchant"),
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Provides us with all the configured configs of the Merchant in the ascending time configured
|
||||
/// manner and chooses the first of them
|
||||
pub async fn get_merchant_default_config(
|
||||
@ -163,28 +117,6 @@ pub async fn update_merchant_routing_dictionary(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_routing_algorithm(
|
||||
db: &dyn StorageInterface,
|
||||
algorithm_id: String,
|
||||
algorithm: routing_types::RoutingAlgorithm,
|
||||
) -> RouterResult<()> {
|
||||
let algorithm_str = algorithm
|
||||
.encode_to_string_of_json()
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Unable to serialize routing algorithm to string")?;
|
||||
|
||||
let config_update = configs::ConfigUpdate::Update {
|
||||
config: Some(algorithm_str),
|
||||
};
|
||||
|
||||
db.update_config_by_key(&algorithm_id, config_update)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.attach_printable("Error updating the routing algorithm in DB")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This will help make one of all configured algorithms to be in active state for a particular
|
||||
/// merchant
|
||||
pub async fn update_merchant_active_algorithm_ref(
|
||||
@ -238,7 +170,7 @@ pub async fn update_merchant_active_algorithm_ref(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: Move it to business_profile
|
||||
pub async fn update_business_profile_active_algorithm_ref(
|
||||
db: &dyn StorageInterface,
|
||||
current_business_profile: BusinessProfile,
|
||||
@ -307,6 +239,157 @@ pub async fn update_business_profile_active_algorithm_ref(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "routing_v2"))]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RoutingAlgorithmHelpers<'h> {
|
||||
pub name_mca_id_set: ConnectNameAndMCAIdForProfile<'h>,
|
||||
pub name_set: ConnectNameForProfile<'h>,
|
||||
pub routing_algorithm: &'h routing_types::RoutingAlgorithm,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ConnectNameAndMCAIdForProfile<'a>(pub FxHashSet<(&'a String, &'a String)>);
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ConnectNameForProfile<'a>(pub FxHashSet<&'a String>);
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "routing_v2"))]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MerchantConnectorAccounts(pub Vec<MerchantConnectorAccount>);
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "routing_v2"))]
|
||||
impl MerchantConnectorAccounts {
|
||||
pub async fn get_all_mcas(
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
key_store: &domain::MerchantKeyStore,
|
||||
state: &SessionState,
|
||||
) -> RouterResult<Self> {
|
||||
let db = &*state.store;
|
||||
let key_manager_state = &state.into();
|
||||
Ok(Self(
|
||||
db.find_merchant_connector_account_by_merchant_id_and_disabled_list(
|
||||
key_manager_state,
|
||||
merchant_id,
|
||||
true,
|
||||
key_store,
|
||||
)
|
||||
.await
|
||||
.change_context(
|
||||
errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
|
||||
id: merchant_id.get_string_repr().to_owned(),
|
||||
},
|
||||
)?,
|
||||
))
|
||||
}
|
||||
|
||||
fn filter_and_map<'a, T>(
|
||||
&'a self,
|
||||
filter: impl Fn(&'a MerchantConnectorAccount) -> bool,
|
||||
func: impl Fn(&'a MerchantConnectorAccount) -> T,
|
||||
) -> FxHashSet<T>
|
||||
where
|
||||
T: std::hash::Hash + Eq,
|
||||
{
|
||||
self.0
|
||||
.iter()
|
||||
.filter(|mca| filter(mca))
|
||||
.map(func)
|
||||
.collect::<FxHashSet<_>>()
|
||||
}
|
||||
|
||||
pub fn filter_by_profile<'a, T>(
|
||||
&'a self,
|
||||
profile_id: &'a str,
|
||||
func: impl Fn(&'a MerchantConnectorAccount) -> T,
|
||||
) -> FxHashSet<T>
|
||||
where
|
||||
T: std::hash::Hash + Eq,
|
||||
{
|
||||
self.filter_and_map(|mca| mca.profile_id.as_deref() == Some(profile_id), func)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "v2", feature = "routing_v2"))]
|
||||
impl<'h> RoutingAlgorithmHelpers<'h> {
|
||||
fn connector_choice(
|
||||
&self,
|
||||
choice: &routing_types::RoutableConnectorChoice,
|
||||
) -> RouterResult<()> {
|
||||
if let Some(ref mca_id) = choice.merchant_connector_id {
|
||||
error_stack::ensure!(
|
||||
self.name_mca_id_set.0.contains(&(&choice.connector.to_string(), mca_id)),
|
||||
errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: format!(
|
||||
"connector with name '{}' and merchant connector account id '{}' not found for the given profile",
|
||||
choice.connector,
|
||||
mca_id,
|
||||
)
|
||||
}
|
||||
);
|
||||
} else {
|
||||
error_stack::ensure!(
|
||||
self.name_set.0.contains(&choice.connector.to_string()),
|
||||
errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: format!(
|
||||
"connector with name '{}' not found for the given profile",
|
||||
choice.connector,
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn validate_connectors_in_routing_config(&self) -> RouterResult<()> {
|
||||
match self.routing_algorithm {
|
||||
routing_types::RoutingAlgorithm::Single(choice) => {
|
||||
self.connector_choice(choice)?;
|
||||
}
|
||||
|
||||
routing_types::RoutingAlgorithm::Priority(list) => {
|
||||
for choice in list {
|
||||
self.connector_choice(choice)?;
|
||||
}
|
||||
}
|
||||
|
||||
routing_types::RoutingAlgorithm::VolumeSplit(splits) => {
|
||||
for split in splits {
|
||||
self.connector_choice(&split.connector)?;
|
||||
}
|
||||
}
|
||||
|
||||
routing_types::RoutingAlgorithm::Advanced(program) => {
|
||||
let check_connector_selection =
|
||||
|selection: &routing_types::ConnectorSelection| -> RouterResult<()> {
|
||||
match selection {
|
||||
routing_types::ConnectorSelection::VolumeSplit(splits) => {
|
||||
for split in splits {
|
||||
self.connector_choice(&split.connector)?;
|
||||
}
|
||||
}
|
||||
|
||||
routing_types::ConnectorSelection::Priority(list) => {
|
||||
for choice in list {
|
||||
self.connector_choice(choice)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
check_connector_selection(&program.default_selection)?;
|
||||
|
||||
for rule in &program.rules {
|
||||
check_connector_selection(&rule.connector_selection)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "routing_v2")))]
|
||||
pub async fn validate_connectors_in_routing_config(
|
||||
state: &SessionState,
|
||||
key_store: &domain::MerchantKeyStore,
|
||||
@ -326,7 +409,6 @@ pub async fn validate_connectors_in_routing_config(
|
||||
.change_context(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
|
||||
id: merchant_id.get_string_repr().to_owned(),
|
||||
})?;
|
||||
|
||||
let name_mca_id_set = all_mcas
|
||||
.iter()
|
||||
.filter(|mca| mca.profile_id.as_deref() == Some(profile_id))
|
||||
@ -339,7 +421,7 @@ pub async fn validate_connectors_in_routing_config(
|
||||
.map(|mca| &mca.connector_name)
|
||||
.collect::<FxHashSet<_>>();
|
||||
|
||||
let check_connector_choice = |choice: &routing_types::RoutableConnectorChoice| {
|
||||
let connector_choice = |choice: &routing_types::RoutableConnectorChoice| {
|
||||
if let Some(ref mca_id) = choice.merchant_connector_id {
|
||||
error_stack::ensure!(
|
||||
name_mca_id_set.contains(&(&choice.connector.to_string(), mca_id)),
|
||||
@ -368,18 +450,18 @@ pub async fn validate_connectors_in_routing_config(
|
||||
|
||||
match routing_algorithm {
|
||||
routing_types::RoutingAlgorithm::Single(choice) => {
|
||||
check_connector_choice(choice)?;
|
||||
connector_choice(choice)?;
|
||||
}
|
||||
|
||||
routing_types::RoutingAlgorithm::Priority(list) => {
|
||||
for choice in list {
|
||||
check_connector_choice(choice)?;
|
||||
connector_choice(choice)?;
|
||||
}
|
||||
}
|
||||
|
||||
routing_types::RoutingAlgorithm::VolumeSplit(splits) => {
|
||||
for split in splits {
|
||||
check_connector_choice(&split.connector)?;
|
||||
connector_choice(&split.connector)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,13 +471,13 @@ pub async fn validate_connectors_in_routing_config(
|
||||
match selection {
|
||||
routing_types::ConnectorSelection::VolumeSplit(splits) => {
|
||||
for split in splits {
|
||||
check_connector_choice(&split.connector)?;
|
||||
connector_choice(&split.connector)?;
|
||||
}
|
||||
}
|
||||
|
||||
routing_types::ConnectorSelection::Priority(list) => {
|
||||
for choice in list {
|
||||
check_connector_choice(choice)?;
|
||||
connector_choice(choice)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user