Bug: Error for successive config activation




diff --git a/crates/api_models/src/open_router.rs b/crates/api_models/src/open_router.rs
index c2e6bc76c06..94d31a73787 100644
--- a/crates/api_models/src/open_router.rs
+++ b/crates/api_models/src/open_router.rs
@@ -251,7 +251,7 @@ pub struct DecisionEngineConfigSetupRequest {
 #[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct GetDecisionEngineConfigRequest {
     pub merchant_id: String,
-    pub config: DecisionEngineDynamicAlgorithmType,
+    pub algorithm: DecisionEngineDynamicAlgorithmType,
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone)]
diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs
index 6094c9826a1..0078bfcea0b 100644
--- a/crates/router/src/core/routing.rs
+++ b/crates/router/src/core/routing.rs
@@ -28,7 +28,9 @@ use external_services::grpc_client::dynamic_routing::{
     success_rate_client::SuccessBasedDynamicRouting,
 };
 #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
-use helpers::update_decision_engine_dynamic_routing_setup;
+use helpers::{
+    enable_decision_engine_dynamic_routing_setup, update_decision_engine_dynamic_routing_setup,
+};
 use hyperswitch_domain_models::{mandates, payment_address};
 use payment_methods::helpers::StorageErrorExt;
 use rustc_hash::FxHashSet;
@@ -694,7 +696,15 @@ pub async fn link_routing_config(
                 #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
                 {
                     if state.conf.open_router.dynamic_routing_enabled {
-                        update_decision_engine_dynamic_routing_setup(
+                        let existing_config = helpers::get_decision_engine_active_dynamic_routing_algorithm(
+                        &state,
+                        business_profile.get_id(),
+                        api_models::open_router::DecisionEngineDynamicAlgorithmType::SuccessRate,
+                    )
+                    .await;
+
+                        if let Ok(Some(_config)) = existing_config {
+                            update_decision_engine_dynamic_routing_setup(
                             &state,
                             business_profile.get_id(),
                             routing_algorithm.algorithm_data.clone(),
@@ -706,6 +716,27 @@ pub async fn link_routing_config(
                         .attach_printable(
                             "Failed to update the success rate routing config in Decision Engine",
                         )?;
+                        } else {
+                            let data: routing_types::SuccessBasedRoutingConfig =
+                            routing_algorithm.algorithm_data
+                                .clone()
+                                .parse_value("SuccessBasedRoutingConfig")
+                                .change_context(errors::ApiErrorResponse::InternalServerError)
+                                .attach_printable(
+                                    "unable to deserialize SuccessBasedRoutingConfig from routing algorithm data",
+                                )?;
+
+                            enable_decision_engine_dynamic_routing_setup(
+                            &state,
+                            business_profile.get_id(),
+                            routing_types::DynamicRoutingType::SuccessRateBasedRouting,
+                            &mut dynamic_routing_ref,
+                            Some(routing_types::DynamicRoutingPayload::SuccessBasedRoutingPayload(data)),
+                        )
+                        .await
+                        .change_context(errors::ApiErrorResponse::InternalServerError)
+                        .attach_printable("Unable to setup decision engine dynamic routing")?;
+                        }
                     }
                 }
             } else if routing_algorithm.name == helpers::ELIMINATION_BASED_DYNAMIC_ROUTING_ALGORITHM
@@ -725,18 +756,51 @@ pub async fn link_routing_config(
                 #[cfg(all(feature = "dynamic_routing", feature = "v1"))]
                 {
                     if state.conf.open_router.dynamic_routing_enabled {
-                        update_decision_engine_dynamic_routing_setup(
+                        let existing_config = helpers::get_decision_engine_active_dynamic_routing_algorithm(
                             &state,
                             business_profile.get_id(),
-                            routing_algorithm.algorithm_data.clone(),
-                            routing_types::DynamicRoutingType::EliminationRouting,
-                            &mut dynamic_routing_ref,
+                            api_models::open_router::DecisionEngineDynamicAlgorithmType::Elimination,
                         )
-                        .await
-                        .change_context(errors::ApiErrorResponse::InternalServerError)
-                        .attach_printable(
-                            "Failed to update the elimination routing config in Decision Engine",
-                        )?;
+                        .await;
+
+                        if let Ok(Some(_config)) = existing_config {
+                            update_decision_engine_dynamic_routing_setup(
+                                &state,
+                                business_profile.get_id(),
+                                routing_algorithm.algorithm_data.clone(),
+                                routing_types::DynamicRoutingType::EliminationRouting,
+                                &mut dynamic_routing_ref,
+                            )
+                            .await
+                            .change_context(errors::ApiErrorResponse::InternalServerError)
+                            .attach_printable(
+                                "Failed to update the elimination routing config in Decision Engine",
+                            )?;
+                        } else {
+                            let data: routing_types::EliminationRoutingConfig =
+                                routing_algorithm.algorithm_data
+                                    .clone()
+                                    .parse_value("EliminationRoutingConfig")
+                                    .change_context(errors::ApiErrorResponse::InternalServerError)
+                                    .attach_printable(
+                                        "unable to deserialize EliminationRoutingConfig from routing algorithm data",
+                                    )?;
+
+                            enable_decision_engine_dynamic_routing_setup(
+                                &state,
+                                business_profile.get_id(),
+                                routing_types::DynamicRoutingType::EliminationRouting,
+                                &mut dynamic_routing_ref,
+                                Some(
+                                    routing_types::DynamicRoutingPayload::EliminationRoutingPayload(
+                                        data,
+                                    ),
+                                ),
+                            )
+                            .await
+                            .change_context(errors::ApiErrorResponse::InternalServerError)
+                            .attach_printable("Unable to setup decision engine dynamic routing")?;
+                        }
                     }
                 }
             } else if routing_algorithm.name == helpers::CONTRACT_BASED_DYNAMIC_ROUTING_ALGORITHM {
diff --git a/crates/router/src/core/routing/helpers.rs b/crates/router/src/core/routing/helpers.rs
index 290feb9e306..0b1395ed4ba 100644
--- a/crates/router/src/core/routing/helpers.rs
+++ b/crates/router/src/core/routing/helpers.rs
@@ -2307,19 +2307,6 @@ pub async fn create_specific_dynamic_routing_setup(
         }
     };
 
-    if state.conf.open_router.dynamic_routing_enabled {
-        enable_decision_engine_dynamic_routing_setup(
-            state,
-            business_profile.get_id(),
-            dynamic_routing_type,
-            &mut dynamic_routing_algo_ref,
-            Some(payload),
-        )
-        .await
-        .change_context(errors::ApiErrorResponse::InternalServerError)
-        .attach_printable("Unable to setup decision engine dynamic routing")?;
-    }
-
     let record = db
         .insert_routing_algorithm(algo)
         .await
@@ -2599,7 +2586,7 @@ pub async fn get_decision_engine_active_dynamic_routing_algorithm(
     );
     let request = open_router::GetDecisionEngineConfigRequest {
         merchant_id: profile_id.get_string_repr().to_owned(),
-        config: dynamic_routing_type,
+        algorithm: dynamic_routing_type,
     };
     let response: Option<open_router::DecisionEngineConfigSetupRequest> =
         routing_utils::ConfigApiClient::send_decision_engine_request(

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

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

Taged Issue
https://github.com/juspay/hyperswitch-cloud/issues/10731

### Summary

This PR refactors **Decision Engine dynamic routing setup** handling inside `link_routing_config` and `create_specific_dynamic_routing_setup` to improve reliability when updating dynamic routing configs.

### Key Changes

1. **Added `enable_decision_engine_dynamic_routing_setup` import**

   * Alongside `update_decision_engine_dynamic_routing_setup` in `helpers.rs`.

2. **Enhanced error handling for SuccessRate & Elimination routing configs**

   * Now, we first attempt to update the DE config via `update_decision_engine_dynamic_routing_setup`.
   * If the update fails, we gracefully fallback to **enabling** the config using `enable_decision_engine_dynamic_routing_setup` with parsed payloads:

     * `SuccessBasedRoutingConfig`
     * `EliminationRoutingConfig`

3. **Improved error messages & traceability**

   * Distinct error messages for update vs. enable flow.
   * Clearer attachable printables for debugging.

4. **Removed redundant `enable_decision_engine_dynamic_routing_setup` call** in
   `create_specific_dynamic_routing_setup` to avoid duplicate execution, since setup is now properly handled within `link_routing_config`.

### Why this change?

* Previously, DE config updates could silently fail without retry/fallback.
* This introduces a safer mechanism:

  * Try **update** → fallback to **enable** with correct payload.
* Ensures merchant routing configs remain in sync with Decision Engine even if updates fail.

### Impact

* More reliable DE config synchronization.
* Clearer error logs.
* Slight increase in control-flow complexity inside `link_routing_config`, but safer handling overall.

**Screenshots

<img width="1282" height="897" alt="Screenshot 2025-08-25 at 3 18 05 PM" src="https://github.com/user-attachments/assets/1c96fefe-edd7-40a3-ba0d-84ea48f56bcb" />
<img width="1282" height="777" alt="Screenshot 2025-08-25 at 3 18 47 PM" src="https://github.com/user-attachments/assets/270cb13f-6dd4-41cb-88dc-317004d60a79" />
<img width="1288" height="816" alt="Screenshot 2025-08-25 at 3 19 12 PM" src="https://github.com/user-attachments/assets/781ac691-50dc-466d-a272-d5350fa2fbd1" />
<img width="1299" height="849" alt="Screenshot 2025-08-25 at 3 19 37 PM" src="https://github.com/user-attachments/assets/862be21c-c330-49a7-8bad-34dc91904fec" />


**Curls and Responses

create

```
curl --location 'http://localhost:8080/account/merchant_1756108708/business_profile/pro_hawNVdPoyuXr2njSINGY/dynamic_routing/success_based/create?enable=dynamic_connector_selection' \
--header 'Content-Type: application/json' \
--header 'api-key:*****' \
--data '{
    "decision_engine_configs": {
        "defaultLatencyThreshold": 90,
        "defaultBucketSize": 200,
        "defaultHedgingPercent": 5,
        "subLevelInputConfig": [
            {
                "paymentMethodType": "card",
                "paymentMethod": "credit",
                "bucketSize": 250,
                "hedgingPercent": 1
            }
        ]
    }
}'
```

response

```
{
    "id": "routing_tVG4bP14dqo4TP7UVPV9",
    "profile_id": "pro_hawNVdPoyuXr2njSINGY",
    "name": "Success rate based dynamic routing algorithm",
    "kind": "dynamic",
    "description": "",
    "created_at": 1756115463,
    "modified_at": 1756115463,
    "algorithm_for": "payment",
    "decision_engine_routing_id": null
}
```

activate

```
curl --location 'http://localhost:8080/routing/routing_tVG4bP14dqo4TP7UVPV9/activate' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_oxFyweqWmRlpg3ZXpKnr5nRQp4JJbrB4uDs85G3mWdCN9F0ZOAtSIvAnfNPhqV1q' \
--data '{}'
```

response

```
{
    "id": "routing_tVG4bP14dqo4TP7UVPV9",
    "profile_id": "pro_hawNVdPoyuXr2njSINGY",
    "name": "Success rate based dynamic routing algorithm",
    "kind": "dynamic",
    "description": "",
    "created_at": 1756115463,
    "modified_at": 1756115463,
    "algorithm_for": "payment",
    "decision_engine_routing_id": null
}
```

create(new)

```
curl --location 'http://localhost:8080/account/merchant_1756108708/business_profile/pro_hawNVdPoyuXr2njSINGY/dynamic_routing/success_based/create?enable=dynamic_connector_selection' \
--header 'Content-Type: application/json' \
--header 'api-key:****' \
--data '{
    "decision_engine_configs": {
        "defaultLatencyThreshold": 90,
        "defaultBucketSize": 200,
        "defaultHedgingPercent": 5,
        "subLevelInputConfig": [
            {
                "paymentMethodType": "card",
                "paymentMethod": "credit",
                "bucketSize": 250,
                "hedgingPercent": 1
            }
        ]
    }
}'
```

response

```
{
    "id": "routing_Jhz8tJy37C12jH19m90F",
    "profile_id": "pro_hawNVdPoyuXr2njSINGY",
    "name": "Success rate based dynamic routing algorithm",
    "kind": "dynamic",
    "description": "",
    "created_at": 1756115557,
    "modified_at": 1756115557,
    "algorithm_for": "payment",
    "decision_engine_routing_id": null
}
```

activate(new)
```
curl --location 'http://localhost:8080/routing/routing_Jhz8tJy37C12jH19m90F/activate' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_oxFyweqWmRlpg3ZXpKnr5nRQp4JJbrB4uDs85G3mWdCN9F0ZOAtSIvAnfNPhqV1q' \
--data '{}'
```

response
```
{
    "id": "routing_Jhz8tJy37C12jH19m90F",
    "profile_id": "pro_hawNVdPoyuXr2njSINGY",
    "name": "Success rate based dynamic routing algorithm",
    "kind": "dynamic",
    "description": "",
    "created_at": 1756115557,
    "modified_at": 1756115557,
    "algorithm_for": "payment",
    "decision_engine_routing_id": null
}

```
activate(old)

```
curl --location 'http://localhost:8080/routing/routing_tVG4bP14dqo4TP7UVPV9/activate' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_oxFyweqWmRlpg3ZXpKnr5nRQp4JJbrB4uDs85G3mWdCN9F0ZOAtSIvAnfNPhqV1q' \
--data '{}'
```

response

```
{
    "id": "routing_tVG4bP14dqo4TP7UVPV9",
    "profile_id": "pro_hawNVdPoyuXr2njSINGY",
    "name": "Success rate based dynamic routing algorithm",
    "kind": "dynamic",
    "description": "",
    "created_at": 1756115463,
    "modified_at": 1756115463,
    "algorithm_for": "payment",
    "decision_engine_routing_id": null
}


```