Bug: refactor(dynamic_routing): add support for shuffle on tie flag to success_based routing




diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json
index bb4db422556..9724050266d 100644
--- a/api-reference-v2/openapi_spec.json
+++ b/api-reference-v2/openapi_spec.json
@@ -9482,6 +9482,7 @@
           "customer_id",
           "payment_method_type",
           "payment_method_subtype",
+          "recurring_enabled",
           "created",
           "requires_cvv",
           "last_used_at",
@@ -9513,9 +9514,8 @@
           },
           "recurring_enabled": {
             "type": "boolean",
-            "description": "Indicates whether the payment method supports recurring payments. Optional.",
-            "example": true,
-            "nullable": true
+            "description": "Indicates whether the payment method is eligible for recurring payments",
+            "example": true
           },
           "payment_method_data": {
             "allOf": [
@@ -17142,7 +17142,6 @@
           "customer_id",
           "payment_method_type",
           "payment_method_subtype",
-          "recurring_enabled",
           "created",
           "requires_cvv",
           "is_default",
@@ -17169,8 +17168,9 @@
           },
           "recurring_enabled": {
             "type": "boolean",
-            "description": "Indicates whether the payment method is eligible for recurring payments",
-            "example": true
+            "description": "Indicates whether the payment method supports recurring payments. Optional.",
+            "example": true,
+            "nullable": true
           },
           "payment_method_data": {
             "allOf": [
@@ -23804,6 +23804,10 @@
             "type": "number",
             "format": "double",
             "nullable": true
+          },
+          "shuffle_on_tie_during_exploitation": {
+            "type": "boolean",
+            "nullable": true
           }
         }
       },
diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs
index ed1915764cb..aea14c23fe8 100644
--- a/crates/api_models/src/routing.rs
+++ b/crates/api_models/src/routing.rs
@@ -1016,6 +1016,7 @@ impl Default for SuccessBasedRoutingConfig {
                 }),
                 specificity_level: SuccessRateSpecificityLevel::default(),
                 exploration_percent: Some(20.0),
+                shuffle_on_tie_during_exploitation: Some(false),
             }),
             decision_engine_configs: None,
         }
@@ -1044,6 +1045,7 @@ pub struct SuccessBasedRoutingConfigBody {
     #[serde(default)]
     pub specificity_level: SuccessRateSpecificityLevel,
     pub exploration_percent: Option<f64>,
+    pub shuffle_on_tie_during_exploitation: Option<bool>,
 }
 
 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, ToSchema)]
@@ -1173,6 +1175,9 @@ impl SuccessBasedRoutingConfigBody {
         if let Some(exploration_percent) = new.exploration_percent {
             self.exploration_percent = Some(exploration_percent);
         }
+        if let Some(shuffle_on_tie_during_exploitation) = new.shuffle_on_tie_during_exploitation {
+            self.shuffle_on_tie_during_exploitation = Some(shuffle_on_tie_during_exploitation);
+        }
     }
 }
 
diff --git a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs
index b63f435327e..00f3e1f159a 100644
--- a/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs
+++ b/crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs
@@ -291,6 +291,7 @@ impl ForeignTryFrom<SuccessBasedRoutingConfigBody> for CalSuccessRateConfig {
                 SuccessRateSpecificityLevel::Global => Some(ProtoSpecificityLevel::Global.into()),
             },
             exploration_percent: config.exploration_percent,
+            shuffle_on_tie_during_exploitation: config.shuffle_on_tie_during_exploitation,
         })
     }
 }
diff --git a/proto/success_rate.proto b/proto/success_rate.proto
index efdd439cac9..cdcde99fa87 100644
--- a/proto/success_rate.proto
+++ b/proto/success_rate.proto
@@ -24,6 +24,7 @@ message CalSuccessRateConfig {
     double default_success_rate = 2;
     optional SuccessRateSpecificityLevel specificity_level = 3;
     optional double exploration_percent = 4;
+    optional bool shuffle_on_tie_during_exploitation = 5;
 }
 
 enum SuccessRateSpecificityLevel {
@@ -78,13 +79,13 @@ message UpdateSuccessRateWindowResponse {
    UpdationStatus status = 1;
 }
 
- // API-3 types
+// API-3 types
 message InvalidateWindowsRequest {
     string id = 1;
 }
 
 message InvalidateWindowsResponse {
-    enum InvalidationStatus {
+   enum InvalidationStatus {
       WINDOW_INVALIDATION_SUCCEEDED = 0;
       WINDOW_INVALIDATION_FAILED = 1;
    }

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

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

## Description
<!-- Describe your changes in detail -->
This pull request introduces a new feature to the routing configuration: the ability to shuffle results on a tie during exploitation. This feature is implemented across multiple files, including API specifications, Rust models, and protocol buffer definitions. Below is a summary of the most important changes grouped by theme.

### Feature Addition: Shuffle on Tie During Exploitation

* **API Specification Update**: Added `shuffle_on_tie_during_exploitation` to the routing configuration in `api-reference/hyperswitch_intelligent_router_open_api_spec.yml`. This parameter enhances routing behavior during exploitation when multiple options have equal success rates.
* **Rust Model Updates**:
  - Updated the `SuccessBasedRoutingConfig` default implementation in `crates/api_models/src/routing.rs` to include `shuffle_on_tie_during_exploitation` with a default value of `false`.
  - Added `shuffle_on_tie_during_exploitation` as an optional field in the `SuccessBasedRoutingConfigBody` struct to allow API clients to configure this behavior.
  - Modified the `update_from` method in `SuccessBasedRoutingConfigBody` to handle updates to the `shuffle_on_tie_during_exploitation` field.
* **Protocol Buffer Update**: Added `shuffle_on_tie_during_exploitation` as an optional field in the `CalSuccessRateConfig` message definition in `proto/success_rate.proto`. This ensures compatibility with external services using gRPC.
* **gRPC Client Update**: Incorporated the new `shuffle_on_tie_during_exploitation` field into the `ForeignTryFrom` implementation for `CalSuccessRateConfig` in `crates/external_services/src/grpc_client/dynamic_routing/success_rate_client.rs`.

### 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?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
1. Create merchant_account, api_key. 
2. Toggle SR for the default profile_created above

```
curl --location --request POST 'http://localhost:8080/account/merchant_1748681084/business_profile/pro_3gHXWoq1Xh3AKi6tNZV1/dynamic_routing/success_based/toggle?enable=dynamic_connector_selection' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: xyz'
```

Check the `routing_algorithm` table for `shuffle_on_tie_during_exploitation` field in `algorithm_data` column. By default it will be set to `false`

3. If you want to update it, hit below curl and activate that algorithm_id for profile.

```
curl --location --request PATCH 'http://localhost:8080/account/merchant_1749040696/business_profile/pro_IFPbNQgBfzPAsqXUSAll/dynamic_routing/success_based/config/routing_Vl1hWGUqg203J5WqeCtK' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: xyz' \
--data '{
  "config": {   
    "shuffle_on_tie_during_exploitation": true
  }
}
'
```

Check the `routing_algorithm` table for `shuffle_on_tie_during_exploitation` field in `algorithm_data` column for the newly created algorithm above after updating. It should be set to `true`

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

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


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced a new optional configuration parameter to control shuffle behavior during exploitation ties in success-based routing.
  - Enhanced payment method information by indicating eligibility for recurring payments and added filtering options for payment methods.
- **Documentation**
  - Updated API documentation and example requests to reflect the new configuration option and payment method changes.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->