From d9bb97046e038d96a610a35068d8d0b1b5b5db7e Mon Sep 17 00:00:00 2001 From: Noa Date: Mon, 23 Sep 2024 13:26:10 +0000 Subject: [PATCH 1/2] fix(connector): add config cleanup on payment connector deletion --- crates/common_enums/src/enums.rs | 9 ++ crates/router/src/core/admin.rs | 147 ++++++++++++++++++++++++++++++- 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index b5f26945e90..c68a1a93464 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -3253,3 +3253,12 @@ pub enum PresenceOfCustomerDuringPayment { /// Customer is absent during the payment Absent, } + +impl From for TransactionType { + fn from(connector_type: ConnectorType) -> Self { + match connector_type { + ConnectorType::PayoutProcessor => Self::Payout, + _ => Self::Payment, + } + } +} diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index ad9925a241f..efe6f926121 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -1910,6 +1910,65 @@ impl<'a> MerchantDefaultConfigUpdate<'a> { } Ok(()) } + + async fn retrieve_and_delete_from_default_fallback_routing_algorithm_if_routable_connector_exists( + &self, + ) -> RouterResult<()> { + let mut default_routing_config = routing::helpers::get_merchant_default_config( + self.store, + self.merchant_id.get_string_repr(), + self.transaction_type, + ) + .await?; + + let mut default_routing_config_for_profile = routing::helpers::get_merchant_default_config( + self.store, + self.profile_id.get_string_repr(), + self.transaction_type, + ) + .await?; + + if let Some(routable_connector_val) = self.routable_connector { + let choice = routing_types::RoutableConnectorChoice { + choice_kind: routing_types::RoutableChoiceKind::FullStruct, + connector: *routable_connector_val, + merchant_connector_id: Some(self.merchant_connector_id.clone()), + }; + if default_routing_config.contains(&choice) { + default_routing_config.retain(|mca| { + mca.merchant_connector_id + .as_ref() + .map_or(true, |merchant_connector_id| { + merchant_connector_id != self.merchant_connector_id + }) + }); + routing::helpers::update_merchant_default_config( + self.store, + self.merchant_id.get_string_repr(), + default_routing_config.clone(), + self.transaction_type, + ) + .await?; + } + if default_routing_config_for_profile.contains(&choice.clone()) { + default_routing_config_for_profile.retain(|mca| { + mca.merchant_connector_id + .as_ref() + .map_or(true, |merchant_connector_id| { + merchant_connector_id != self.merchant_connector_id + }) + }); + routing::helpers::update_merchant_default_config( + self.store, + self.profile_id.get_string_repr(), + default_routing_config_for_profile.clone(), + self.transaction_type, + ) + .await?; + } + } + Ok(()) + } } #[cfg(feature = "v2")] struct DefaultFallbackRoutingConfigUpdate<'a> { @@ -1949,6 +2008,40 @@ impl<'a> DefaultFallbackRoutingConfigUpdate<'a> { } Ok(()) } + + async fn retrieve_and_delete_from_default_fallback_routing_algorithm_if_routable_connector_exists( + &self, + ) -> RouterResult<()> { + let profile_wrapper = ProfileWrapper::new(self.business_profile.clone()); + let default_routing_config_for_profile = + &mut profile_wrapper.get_default_fallback_list_of_connector_under_profile()?; + if let Some(routable_connector_val) = self.routable_connector { + let choice = routing_types::RoutableConnectorChoice { + choice_kind: routing_types::RoutableChoiceKind::FullStruct, + connector: *routable_connector_val, + merchant_connector_id: Some(self.merchant_connector_id.clone()), + }; + if default_routing_config_for_profile.contains(&choice.clone()) { + default_routing_config_for_profile.retain(|mca| { + mca.merchant_connector_id + .as_ref() + .map_or(true, |merchant_connector_id| { + merchant_connector_id != self.merchant_connector_id + }) + }); + + profile_wrapper + .update_default_fallback_routing_of_connectors_under_profile( + self.store, + default_routing_config_for_profile, + self.key_manager_state, + &self.key_store, + ) + .await? + } + } + Ok(()) + } } #[cfg(any(feature = "v1", feature = "v2", feature = "olap"))] #[async_trait::async_trait] @@ -3126,7 +3219,7 @@ pub async fn delete_connector( .await .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?; - let _mca = db + let mca = db .find_by_merchant_connector_account_merchant_id_merchant_connector_id( key_manager_state, &merchant_id, @@ -3148,6 +3241,26 @@ pub async fn delete_connector( id: merchant_connector_id.get_string_repr().to_string(), })?; + // delete the mca from the config as well + let merchant_default_config_delete = MerchantDefaultConfigUpdate { + routable_connector: &Some( + common_enums::RoutableConnectors::from_str(&mca.connector_name).map_err(|_| { + errors::ApiErrorResponse::InvalidDataValue { + field_name: "connector_name", + } + })?, + ), + merchant_connector_id: &mca.get_id(), + store: db, + merchant_id: &merchant_id, + profile_id: &mca.profile_id, + transaction_type: &mca.connector_type.into(), + }; + + merchant_default_config_delete + .retrieve_and_delete_from_default_fallback_routing_algorithm_if_routable_connector_exists() + .await?; + let response = api::MerchantConnectorDeleteResponse { merchant_id, merchant_connector_id, @@ -3194,6 +3307,38 @@ pub async fn delete_connector( id: id.clone().get_string_repr().to_string(), })?; + let business_profile = crate::core::utils::validate_and_get_business_profile( + db, + key_manager_state, + &key_store, + Some(&mca.profile_id), + merchant_id, + ) + .await? + .get_required_value("Profile") + .change_context(errors::ApiErrorResponse::ProfileNotFound { + id: mca.profile_id.get_string_repr().to_owned(), + })?; + + let merchant_default_config_delete = DefaultFallbackRoutingConfigUpdate { + routable_connector: &Some( + common_enums::RoutableConnectors::from_str(&mca.connector_name).map_err(|_| { + errors::ApiErrorResponse::InvalidDataValue { + field_name: "connector_name", + } + })?, + ), + merchant_connector_id: &mca.get_id(), + store: db, + business_profile, + key_store, + key_manager_state, + }; + + merchant_default_config_delete + .retrieve_and_delete_from_default_fallback_routing_algorithm_if_routable_connector_exists() + .await?; + let response = api::MerchantConnectorDeleteResponse { merchant_id: merchant_id.clone(), id, From 284b3aec9c68ef24390cec60118848a57bdc135a Mon Sep 17 00:00:00 2001 From: Noa Date: Tue, 24 Sep 2024 05:08:36 +0000 Subject: [PATCH 2/2] refactor: add feature flag for payout --- crates/common_enums/src/enums.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index c68a1a93464..1a0761a5d22 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -3257,6 +3257,7 @@ pub enum PresenceOfCustomerDuringPayment { impl From for TransactionType { fn from(connector_type: ConnectorType) -> Self { match connector_type { + #[cfg(feature = "payouts")] ConnectorType::PayoutProcessor => Self::Payout, _ => Self::Payment, }