Bug: [REFACTOR] Refactor deactivating and retrieve apis for routing v2



### Feature Description

Refactor deactivating and retrieve apis for routing v2

### Possible Implementation

Refactor deactivating and retrieve apis for routing v2

### Have you spent some time checking if this feature request has been raised before?

- [X] I checked and didn't find a similar issue

### Have you read the Contributing Guidelines?

- [X] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Are you willing to submit a PR?

Yes, I am willing to submit a PR!
diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs
index 265d0451117..aca7bfaebe3 100644
--- a/crates/api_models/src/routing.rs
+++ b/crates/api_models/src/routing.rs
@@ -30,7 +30,16 @@ impl ConnectorSelection {
         }
     }
 }
+#[cfg(all(feature = "v2", feature = "routing_v2"))]
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
+pub struct RoutingConfigRequest {
+    pub name: String,
+    pub description: String,
+    pub algorithm: RoutingAlgorithm,
+    pub profile_id: String,
+}
 
+#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "routing_v2")))]
 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
 pub struct RoutingConfigRequest {
     pub name: Option<String>,
diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs
index 2451156e874..cb7cf344e89 100644
--- a/crates/router/src/core/routing.rs
+++ b/crates/router/src/core/routing.rs
@@ -1,15 +1,12 @@
 pub mod helpers;
 pub mod transformers;
 
+#[cfg(all(feature = "v2", feature = "routing_v2"))]
+use api_models::routing::RoutingConfigRequest;
 use api_models::{
     enums,
-    routing::{
-        self as routing_types, RoutingAlgorithmId, RoutingRetrieveLinkQuery, RoutingRetrieveQuery,
-    },
+    routing::{self as routing_types, 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"))]
@@ -19,11 +16,8 @@ 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,
@@ -36,6 +30,8 @@ use crate::{
     },
     utils::{self, OptionExt, ValueExt},
 };
+#[cfg(all(feature = "v2", feature = "routing_v2"))]
+use crate::{core::errors::RouterResult, db::StorageInterface};
 pub enum TransactionData<'a, F>
 where
     F: Clone,
@@ -51,10 +47,8 @@ struct RoutingAlgorithmUpdate(RoutingAlgorithm);
 #[cfg(all(feature = "v2", feature = "routing_v2"))]
 impl RoutingAlgorithmUpdate {
     pub fn create_new_routing_algorithm(
-        algorithm: routing_types::RoutingAlgorithm,
+        request: &RoutingConfigRequest,
         merchant_id: &common_utils::id_type::MerchantId,
-        name: String,
-        description: String,
         profile_id: String,
         transaction_type: &enums::TransactionType,
     ) -> Self {
@@ -67,10 +61,10 @@ impl RoutingAlgorithmUpdate {
             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),
+            name: request.name.clone(),
+            description: Some(request.description.clone()),
+            kind: request.algorithm.get_kind().foreign_into(),
+            algorithm_data: serde_json::json!(request.algorithm),
             created_at: timestamp,
             modified_at: timestamp,
             algorithm_for: transaction_type.to_owned(),
@@ -150,36 +144,15 @@ pub async fn create_routing_config(
     state: SessionState,
     merchant_account: domain::MerchantAccount,
     key_store: domain::MerchantKeyStore,
-    request: routing_types::RoutingConfigRequest,
+    request: 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(),
+        Some(&request.profile_id),
         merchant_account.get_id(),
     )
     .await?
@@ -205,16 +178,14 @@ pub async fn create_routing_config(
     let algorithm_helper = helpers::RoutingAlgorithmHelpers {
         name_mca_id_set,
         name_set,
-        routing_algorithm: &algorithm,
+        routing_algorithm: &request.algorithm,
     };
 
     algorithm_helper.validate_connectors_in_routing_config()?;
 
     let algo = RoutingAlgorithmUpdate::create_new_routing_algorithm(
-        algorithm,
+        &request,
         merchant_account.get_id(),
-        name,
-        description,
         business_profile.profile_id,
         transaction_type,
     );
@@ -327,11 +298,13 @@ pub async fn link_routing_config(
     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),
@@ -348,6 +321,7 @@ pub async fn link_routing_config(
     .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,
@@ -432,10 +406,41 @@ pub async fn link_routing_config(
     ))
 }
 
+#[cfg(all(feature = "v2", feature = "routing_v2"))]
+pub async fn retrieve_routing_config(
+    state: SessionState,
+    merchant_account: domain::MerchantAccount,
+    algorithm_id: routing_types::RoutingAlgorithmId,
+) -> RouterResponse<routing_types::MerchantRoutingAlgorithm> {
+    metrics::ROUTING_RETRIEVE_CONFIG.add(&metrics::CONTEXT, 1, &[]);
+    let db = state.store.as_ref();
+
+    let routing_algorithm =
+        RoutingAlgorithmUpdate::fetch_routing_algo(merchant_account.get_id(), &algorithm_id.0, db)
+            .await?;
+    // TODO: Move to domain types of Business Profile
+    core_utils::validate_and_get_business_profile(
+        db,
+        Some(&routing_algorithm.0.profile_id),
+        merchant_account.get_id(),
+    )
+    .await?
+    .get_required_value("BusinessProfile")
+    .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?;
+
+    let response = routing_types::MerchantRoutingAlgorithm::foreign_try_from(routing_algorithm.0)
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("unable to parse routing algorithm")?;
+
+    metrics::ROUTING_RETRIEVE_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]);
+    Ok(service_api::ApplicationResponse::Json(response))
+}
+
+#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "routing_v2")))]
 pub async fn retrieve_routing_config(
     state: SessionState,
     merchant_account: domain::MerchantAccount,
-    algorithm_id: RoutingAlgorithmId,
+    algorithm_id: routing_types::RoutingAlgorithmId,
 ) -> RouterResponse<routing_types::MerchantRoutingAlgorithm> {
     metrics::ROUTING_RETRIEVE_CONFIG.add(&metrics::CONTEXT, 1, &[]);
     let db = state.store.as_ref();
@@ -465,6 +470,70 @@ pub async fn retrieve_routing_config(
     Ok(service_api::ApplicationResponse::Json(response))
 }
 
+#[cfg(all(feature = "v2", feature = "routing_v2"))]
+pub async fn unlink_routing_config(
+    state: SessionState,
+    merchant_account: domain::MerchantAccount,
+    profile_id: String,
+    transaction_type: &enums::TransactionType,
+) -> RouterResponse<routing_types::RoutingDictionaryRecord> {
+    metrics::ROUTING_UNLINK_CONFIG.add(&metrics::CONTEXT, 1, &[]);
+    let db = state.store.as_ref();
+
+    let business_profile = core_utils::validate_and_get_business_profile(
+        db,
+        Some(&profile_id),
+        merchant_account.get_id(),
+    )
+    .await?
+    .get_required_value("BusinessProfile")?;
+
+    let routing_algo_ref = routing_types::RoutingAlgorithmRef::parse_routing_algorithm(
+        match transaction_type {
+            enums::TransactionType::Payment => business_profile.routing_algorithm.clone(),
+            #[cfg(feature = "payouts")]
+            enums::TransactionType::Payout => business_profile.payout_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();
+
+    if let Some(algorithm_id) = routing_algo_ref.algorithm_id {
+        let timestamp = common_utils::date_time::now_unix_timestamp();
+        let routing_algorithm: routing_types::RoutingAlgorithmRef =
+            routing_types::RoutingAlgorithmRef {
+                algorithm_id: None,
+                timestamp,
+                config_algo_id: routing_algo_ref.config_algo_id.clone(),
+                surcharge_config_algo_id: routing_algo_ref.surcharge_config_algo_id,
+            };
+        let record = RoutingAlgorithmUpdate::fetch_routing_algo(
+            merchant_account.get_id(),
+            &algorithm_id,
+            db,
+        )
+        .await?;
+        let response = record.0.foreign_into();
+        helpers::update_business_profile_active_algorithm_ref(
+            db,
+            business_profile,
+            routing_algorithm,
+            transaction_type,
+        )
+        .await?;
+
+        metrics::ROUTING_UNLINK_CONFIG_SUCCESS_RESPONSE.add(&metrics::CONTEXT, 1, &[]);
+        Ok(service_api::ApplicationResponse::Json(response))
+    } else {
+        Err(errors::ApiErrorResponse::PreconditionFailed {
+            message: "Algorithm is already inactive".to_string(),
+        })?
+    }
+}
+
+#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "routing_v2")))]
 pub async fn unlink_routing_config(
     state: SessionState,
     merchant_account: domain::MerchantAccount,
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index 708fcbbf406..928289c3e56 100644
--- a/crates/router/src/routes/app.rs
+++ b/crates/router/src/routes/app.rs
@@ -1454,18 +1454,16 @@ impl BusinessProfile {
                             },
                         )),
                     )
-                    .service(
-                        web::resource("/deactivate_routing_algorithm").route(web::post().to(
-                            |state, req, path| {
-                                routing::routing_unlink_config(
-                                    state,
-                                    req,
-                                    path,
-                                    &TransactionType::Payment,
-                                )
-                            },
-                        )),
-                    ),
+                    .service(web::resource("/deactivate_routing_algorithm").route(
+                        web::patch().to(|state, req, path| {
+                            routing::routing_unlink_config(
+                                state,
+                                req,
+                                path,
+                                &TransactionType::Payment,
+                            )
+                        }),
+                    )),
             )
     }
 }
diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs
index b4e180cf718..8e375898377 100644
--- a/crates/router/src/routes/routing.rs
+++ b/crates/router/src/routes/routing.rs
@@ -200,7 +200,41 @@ pub async fn list_routing_configs(
     .await
 }
 
-#[cfg(feature = "olap")]
+#[cfg(all(feature = "olap", feature = "v2", feature = "routing_v2"))]
+#[instrument(skip_all)]
+pub async fn routing_unlink_config(
+    state: web::Data<AppState>,
+    req: HttpRequest,
+    path: web::Path<String>,
+    transaction_type: &enums::TransactionType,
+) -> impl Responder {
+    let flow = Flow::RoutingUnlinkConfig;
+    Box::pin(oss_api::server_wrap(
+        flow,
+        state,
+        &req,
+        path.into_inner(),
+        |state, auth: auth::AuthenticationData, path, _| {
+            routing::unlink_routing_config(state, auth.merchant_account, path, transaction_type)
+        },
+        #[cfg(not(feature = "release"))]
+        auth::auth_type(
+            &auth::ApiKeyAuth,
+            &auth::JWTAuth(Permission::RoutingWrite),
+            req.headers(),
+        ),
+        #[cfg(feature = "release")]
+        &auth::JWTAuth(Permission::RoutingWrite),
+        api_locking::LockAction::NotApplicable,
+    ))
+    .await
+}
+
+#[cfg(all(
+    feature = "olap",
+    any(feature = "v1", feature = "v2"),
+    not(feature = "routing_v2")
+))]
 #[instrument(skip_all)]
 pub async fn routing_unlink_config(
     state: web::Data<AppState>,

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [ ] New feature
- [ ] Enhancement
- [x] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
Refactor api v2 routes for deactivating and retrieving the routing config


### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->


## How did you test it?
 
 - To deactivate the routing config
 ```
 curl --location --request PATCH 'http://localhost:8080/v2/profiles/pro_VirB3AxB3qItFTnLsuA2/deactivate_routing_algorithm' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_CMjrHy1A62kEwdzCDoLWRBta6xBZalgupmamFfdKfJdMjklfCil5S1wqAZ0F4Jw5' \
--data '
'
```

- To retrieve the routing config
```
curl --location 'http://localhost:8080/v2/routing_algorithm/routing_merchant_1722847196_EiushCG51H' \
--header 'api-key: dev_CMjrHy1A62kEwdzCDoLWRBta6xBZalgupmamFfdKfJdMjklfCil5S1wqAZ0F4Jw5'
 ```

## Checklist
<!-- Put an `x` in the boxes that apply -->

- [ ] I formatted the code `cargo +nightly fmt --all`
- [ ] I addressed lints thrown by `cargo clippy`
- [ ] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
