Bug: Api contract changes to accept `saving_percentage` in the decision engine response



Api contract changes to accept `saving_percentage` in the decision engine response
diff --git a/crates/api_models/src/open_router.rs b/crates/api_models/src/open_router.rs
index af91ece3f12..5d5f8f016c0 100644
--- a/crates/api_models/src/open_router.rs
+++ b/crates/api_models/src/open_router.rs
@@ -67,17 +67,32 @@ pub struct DecidedGateway {
 
 #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
 pub struct DebitRoutingOutput {
-    pub co_badged_card_networks: Vec<common_enums::CardNetwork>,
+    pub co_badged_card_networks_info: Vec<CoBadgedCardNetworksInfo>,
     pub issuer_country: common_enums::CountryAlpha2,
     pub is_regulated: bool,
     pub regulated_name: Option<common_enums::RegulatedName>,
     pub card_type: common_enums::CardType,
 }
 
+#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
+pub struct CoBadgedCardNetworksInfo {
+    pub network: common_enums::CardNetwork,
+    pub saving_percentage: f64,
+}
+
+impl DebitRoutingOutput {
+    pub fn get_co_badged_card_networks(&self) -> Vec<common_enums::CardNetwork> {
+        self.co_badged_card_networks_info
+            .iter()
+            .map(|data| data.network.clone())
+            .collect()
+    }
+}
+
 impl From<&DebitRoutingOutput> for payment_methods::CoBadgedCardData {
     fn from(output: &DebitRoutingOutput) -> Self {
         Self {
-            co_badged_card_networks: output.co_badged_card_networks.clone(),
+            co_badged_card_networks: output.get_co_badged_card_networks(),
             issuer_country_code: output.issuer_country,
             is_regulated: output.is_regulated,
             regulated_name: output.regulated_name.clone(),
@@ -96,7 +111,7 @@ impl TryFrom<(payment_methods::CoBadgedCardData, String)> for DebitRoutingReques
         })?;
 
         Ok(Self {
-            co_badged_card_networks: output.co_badged_card_networks,
+            co_badged_card_networks_info: output.co_badged_card_networks,
             issuer_country: output.issuer_country_code,
             is_regulated: output.is_regulated,
             regulated_name: output.regulated_name,
@@ -114,7 +129,7 @@ pub struct CoBadgedCardRequest {
 
 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
 pub struct DebitRoutingRequestData {
-    pub co_badged_card_networks: Vec<common_enums::CardNetwork>,
+    pub co_badged_card_networks_info: Vec<common_enums::CardNetwork>,
     pub issuer_country: common_enums::CountryAlpha2,
     pub is_regulated: bool,
     pub regulated_name: Option<common_enums::RegulatedName>,
diff --git a/crates/router/src/core/debit_routing.rs b/crates/router/src/core/debit_routing.rs
index c7de440bbf6..ca03f5d2532 100644
--- a/crates/router/src/core/debit_routing.rs
+++ b/crates/router/src/core/debit_routing.rs
@@ -256,8 +256,8 @@ where
             get_debit_routing_output::<F, D>(state, payment_data, acquirer_country).await?;
 
         logger::debug!(
-            "Sorted co-badged networks: {:?}",
-            debit_routing_output.co_badged_card_networks
+            "Sorted co-badged networks info: {:?}",
+            debit_routing_output.co_badged_card_networks_info
         );
 
         let key_store = db
@@ -281,7 +281,7 @@ where
             &profile_id,
             &key_store,
             vec![connector_data.clone()],
-            debit_routing_output.co_badged_card_networks.clone(),
+            debit_routing_output.get_co_badged_card_networks(),
         )
         .await
         .map_err(|error| {
@@ -455,7 +455,7 @@ where
             &profile_id,
             &key_store,
             connector_data_list.clone(),
-            debit_routing_output.co_badged_card_networks.clone(),
+            debit_routing_output.get_co_badged_card_networks(),
         )
         .await
         .map_err(|error| {

<!-- 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 refactors the `DebitRoutingOutput` structure to introduce a new `CoBadgedCardNetworksInfo` type, enhancing the representation of co-badged card networks by including additional metadata such as saving percentages. It also updates related methods and structures to align with this change.

### 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)?
-->
-> Enable debit routing for a profile and configure adyen connector
-> Make a payment
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'x-feature: router-custom' \
--header 'x-tenant-id: hyperswitch' \
--header 'api-key: ' \
--data-raw '{
    "amount": 10000,
    "amount_to_capture": 10000,
    "currency": "USD",
    "confirm": true,
    "capture_method": "automatic",
    "setup_future_usage": "on_session",
    "capture_on": "2022-09-10T10:11:12Z",
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+1",
    "description": "Its my first payment request",
    "authentication_type": "no_three_ds",
    "customer_id": "cu_1750319776",
    "return_url": "http://127.0.0.1:4040",
    "payment_method": "card",
    "payment_method_type": "debit",
    "payment_method_data": {
        "card": {
            "card_number": "4400 0020 0000 0004",
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "joseph Doe",
            "card_cvc": "737"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "PiX",
            "last_name": "ss"
        },
        "email": "raj@gmail.com"
    },
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "PiX"
        }
    },
    "customer_acceptance": {
        "acceptance_type": "offline",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "in sit",
            "user_agent": "amet irure esse"
        }
    },
    "browser_info": {
        "user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/70.0.3538.110 Safari\/537.36",
        "accept_header": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,image\/apng,*\/*;q=0.8",
        "language": "nl-NL",
        "color_depth": 24,
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "125.0.0.1"
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    }
}'
```
```
{
    "payment_id": "pay_7aTZkTRH72iemhbxOqvc",
    "merchant_id": "merchant_1750232289",
    "status": "succeeded",
    "amount": 10000,
    "net_amount": 10000,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 10000,
    "connector": "adyen",
    "client_secret": "pay_7aTZkTRH72iemhbxOqvc_secret_2v6ATAqLFQsKVhms16hF",
    "created": "2025-06-18T07:40:06.149Z",
    "currency": "USD",
    "customer_id": "cu_1750232406",
    "customer": {
        "id": "cu_1750232406",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+1"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "on_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "0004",
            "card_type": null,
            "card_network": "Accel",
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "440000",
            "card_extended_bin": null,
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "joseph Doe",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "PiX",
            "last_name": null
        },
        "phone": null,
        "email": null
    },
    "billing": {
        "address": {
            "city": "San",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "PiX",
            "last_name": "ss"
        },
        "phone": null,
        "email": "raj@gmail.com"
    },
    "order_details": null,
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": "http://127.0.0.1:4040/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "debit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "cu_1750232406",
        "created_at": 1750232406,
        "expires": 1750236006,
        "secret": "epk_1a8a73a55db941eb89b3c5a54b42bc3d"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "JKCHRB6V9DDHL975",
    "frm_message": null,
    "metadata": {
        "udf1": "value1",
        "login_date": "2019-09-10T10:11:12Z",
        "new_customer": "true"
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "pay_7aTZkTRH72iemhbxOqvc_1",
    "payment_link": null,
    "profile_id": "pro_n23wrYOtUyaiFMM71SEq",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_xC22XUKnNCBkg5vHm1W0",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-06-18T07:55:06.149Z",
    "fingerprint": null,
    "browser_info": {
        "language": "nl-NL",
        "time_zone": 0,
        "ip_address": "125.0.0.1",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "color_depth": 24,
        "java_enabled": true,
        "screen_width": 1536,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "screen_height": 723,
        "java_script_enabled": true
    },
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2025-06-18T07:40:07.133Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null,
    "card_discovery": "manual",
    "force_3ds_challenge": false,
    "force_3ds_challenge_trigger": false,
    "issuer_error_code": null,
    "issuer_error_message": null,
    "is_iframe_redirection_enabled": null,
    "whole_connector_response": null
}
```
Once the payment is done the api events should have the `saving_percentage` in the decision engine response
```
{
    "decided_gateway": "ADYEN",
    "gateway_priority_map": null,
    "filter_wise_gateways": null,
    "priority_logic_tag": null,
    "routing_approach": "NONE",
    "gateway_before_evaluation": null,
    "priority_logic_output": null,
    "debit_routing_output": {
        "co_badged_card_networks_info": [
            {
                "network": "ACCEL",
                "saving_percentage": 0.14
            },
            {
                "network": "STAR",
                "saving_percentage": 0.04
            },
            {
                "network": "VISA",
                "saving_percentage": 0.0
            }
        ],
        "issuer_country": "US",
        "is_regulated": true,
        "regulated_name": "GOVERNMENT EXEMPT INTERCHANGE FEE",
        "card_type": "debit"
    },
    "reset_approach": "NO_RESET",
    "routing_dimension": null,
    "routing_dimension_level": null,
    "is_scheduled_outage": false,
    "is_dynamic_mga_enabled": false,
    "gateway_mga_id_map": null
}
```

## 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
