Bug: [REFACTOR] unify locker api function call



Create a single method using which locker api can be called and deserialised to the given type. Also send tenant-id in headers
diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs
index 996224d7bea..e2c2dbb48ce 100644
--- a/crates/router/src/core/admin.rs
+++ b/crates/router/src/core/admin.rs
@@ -4486,7 +4486,7 @@ async fn locker_recipient_create_call(
         ttl: state.conf.locker.ttl_for_storage_in_secs,
     });
 
-    let store_resp = cards::call_to_locker_hs(
+    let store_resp = cards::add_card_to_hs_locker(
         state,
         &payload,
         &cust_id,
diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs
index c22465c3a32..7fc3e9a9559 100644
--- a/crates/router/src/core/errors.rs
+++ b/crates/router/src/core/errors.rs
@@ -124,6 +124,8 @@ pub enum VaultError {
     SaveCardFailed,
     #[error("Failed to fetch card details from card vault")]
     FetchCardFailed,
+    #[error("Failed to delete card in card vault")]
+    DeleteCardFailed,
     #[error("Failed to encode card vault request")]
     RequestEncodingFailed,
     #[error("Failed to deserialize card vault response")]
@@ -146,6 +148,8 @@ pub enum VaultError {
     SavePaymentMethodFailed,
     #[error("Failed to generate fingerprint")]
     GenerateFingerprintFailed,
+    #[error("Failed while calling locker API")]
+    ApiError,
 }
 
 #[derive(Debug, thiserror::Error)]
diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs
index ccd64f066df..376faeb6464 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -28,8 +28,10 @@ use common_utils::{
     consts,
     crypto::{self, Encryptable},
     encryption::Encryption,
-    ext_traits::{AsyncExt, Encode, StringExt, ValueExt},
-    generate_id, id_type, type_name,
+    ext_traits::{AsyncExt, BytesExt, Encode, StringExt, ValueExt},
+    generate_id, id_type,
+    request::Request,
+    type_name,
     types::{
         keymanager::{Identifier, KeyManagerState},
         MinorUnit,
@@ -93,7 +95,7 @@ use crate::{
         storage::{self, enums, PaymentMethodListContext, PaymentTokenData},
         transformers::ForeignTryFrom,
     },
-    utils::{ConnectorResponseExt, OptionExt},
+    utils::OptionExt,
 };
 #[cfg(all(
     any(feature = "v1", feature = "v2"),
@@ -1876,7 +1878,7 @@ pub async fn add_bank_to_locker(
             enc_data,
             ttl: state.conf.locker.ttl_for_storage_in_secs,
         });
-    let store_resp = call_to_locker_hs(
+    let store_resp = add_card_to_hs_locker(
         state,
         &payload,
         customer_id,
@@ -1920,7 +1922,7 @@ pub async fn add_card_to_locker(
                 card_reference,
             )
             .await
-            .inspect_err(|error| {
+            .inspect_err(|_| {
                 metrics::CARD_LOCKER_FAILURES.add(
                     &metrics::CONTEXT,
                     1,
@@ -1929,7 +1931,6 @@ pub async fn add_card_to_locker(
                         router_env::opentelemetry::KeyValue::new("operation", "add"),
                     ],
                 );
-                logger::error!(?error, "Failed to add card in locker");
             })
         },
         &metrics::CARD_ADD_TIME,
@@ -1962,7 +1963,7 @@ pub async fn get_card_from_locker(
             .await
             .change_context(errors::ApiErrorResponse::InternalServerError)
             .attach_printable("Failed while getting card from hyperswitch card vault")
-            .inspect_err(|error| {
+            .inspect_err(|_| {
                 metrics::CARD_LOCKER_FAILURES.add(
                     &metrics::CONTEXT,
                     1,
@@ -1971,7 +1972,6 @@ pub async fn get_card_from_locker(
                         router_env::opentelemetry::KeyValue::new("operation", "get"),
                     ],
                 );
-                logger::error!(?error, "Failed to retrieve card from locker");
             })
         },
         &metrics::CARD_GET_TIME,
@@ -1996,9 +1996,15 @@ pub async fn delete_card_from_locker(
         async move {
             delete_card_from_hs_locker(state, customer_id, merchant_id, card_reference)
                 .await
-                .inspect_err(|error| {
-                    metrics::CARD_LOCKER_FAILURES.add(&metrics::CONTEXT, 1, &[]);
-                    logger::error!(?error, "Failed to delete card from locker");
+                .inspect_err(|_| {
+                    metrics::CARD_LOCKER_FAILURES.add(
+                        &metrics::CONTEXT,
+                        1,
+                        &[
+                            router_env::opentelemetry::KeyValue::new("locker", "rust"),
+                            router_env::opentelemetry::KeyValue::new("operation", "delete"),
+                        ],
+                    );
                 })
         },
         &metrics::CARD_DELETE_TIME,
@@ -2006,6 +2012,8 @@ pub async fn delete_card_from_locker(
         &[],
     )
     .await
+    .change_context(errors::ApiErrorResponse::InternalServerError)
+    .attach_printable("Failed while deleting card from locker")
 }
 
 #[cfg(all(feature = "v2", feature = "customer_v2"))]
@@ -2049,7 +2057,8 @@ pub async fn add_card_hs(
         ttl: state.conf.locker.ttl_for_storage_in_secs,
     });
 
-    let store_card_payload = call_to_locker_hs(state, &payload, customer_id, locker_choice).await?;
+    let store_card_payload =
+        add_card_to_hs_locker(state, &payload, customer_id, locker_choice).await?;
 
     let payment_method_resp = payment_methods::mk_add_card_response_hs(
         card.clone(),
@@ -2111,30 +2120,22 @@ pub async fn get_payment_method_from_hs_locker<'a>(
             merchant_id,
             payment_method_reference,
             locker_choice,
+            state.tenant.name.clone(),
+            state.request_id,
         )
         .await
         .change_context(errors::VaultError::FetchPaymentMethodFailed)
         .attach_printable("Making get payment method request failed")?;
-        let response = services::call_connector_api(state, request, "add_card_to_locker")
-            .await
-            .change_context(errors::VaultError::FetchPaymentMethodFailed)
-            .attach_printable("Failed while executing call_connector_api for get_card");
-        let jwe_body: services::JweBody = response
-            .get_response_inner("JweBody")
-            .change_context(errors::VaultError::FetchPaymentMethodFailed)?;
-        let decrypted_payload = payment_methods::get_decrypted_response_payload(
-            jwekey,
-            jwe_body,
+
+        let get_card_resp = call_locker_api::<payment_methods::RetrieveCardResp>(
+            state,
+            request,
+            "get_pm_from_locker",
             locker_choice,
-            locker.decryption_scheme.clone(),
         )
         .await
-        .change_context(errors::VaultError::FetchPaymentMethodFailed)
-        .attach_printable("Error getting decrypted response payload for get card")?;
-        let get_card_resp: payment_methods::RetrieveCardResp = decrypted_payload
-            .parse_struct("RetrieveCardResp")
-            .change_context(errors::VaultError::FetchPaymentMethodFailed)
-            .attach_printable("Failed to parse struct to RetrieveCardResp")?;
+        .change_context(errors::VaultError::FetchPaymentMethodFailed)?;
+
         let retrieve_card_resp = get_card_resp
             .payload
             .get_required_value("RetrieveCardRespPayload")
@@ -2158,7 +2159,7 @@ pub async fn get_payment_method_from_hs_locker<'a>(
 }
 
 #[instrument(skip_all)]
-pub async fn call_to_locker_hs(
+pub async fn add_card_to_hs_locker(
     state: &routes::SessionState,
     payload: &payment_methods::StoreLockerReq,
     customer_id: &id_type::CustomerId,
@@ -2168,30 +2169,23 @@ pub async fn call_to_locker_hs(
     let jwekey = state.conf.jwekey.get_inner();
     let db = &*state.store;
     let stored_card_response = if !locker.mock_locker {
-        let request =
-            payment_methods::mk_add_locker_request_hs(jwekey, locker, payload, locker_choice)
-                .await?;
-        let response = services::call_connector_api(state, request, "add_card_to_hs_locker")
-            .await
-            .change_context(errors::VaultError::SaveCardFailed);
-
-        let jwe_body: services::JweBody = response
-            .get_response_inner("JweBody")
-            .change_context(errors::VaultError::FetchCardFailed)?;
-
-        let decrypted_payload = payment_methods::get_decrypted_response_payload(
+        let request = payment_methods::mk_add_locker_request_hs(
             jwekey,
-            jwe_body,
+            locker,
+            payload,
+            locker_choice,
+            state.tenant.name.clone(),
+            state.request_id,
+        )
+        .await?;
+        call_locker_api::<payment_methods::StoreCardResp>(
+            state,
+            request,
+            "add_card_to_hs_locker",
             Some(locker_choice),
-            locker.decryption_scheme.clone(),
         )
         .await
-        .change_context(errors::VaultError::SaveCardFailed)
-        .attach_printable("Error getting decrypted response payload")?;
-        let stored_card_resp: payment_methods::StoreCardResp = decrypted_payload
-            .parse_struct("StoreCardResp")
-            .change_context(errors::VaultError::ResponseDeserializationFailed)?;
-        stored_card_resp
+        .change_context(errors::VaultError::SaveCardFailed)?
     } else {
         let card_id = generate_id(consts::ID_LENGTH, "card");
         mock_call_to_locker_hs(db, &card_id, payload, None, None, Some(customer_id)).await?
@@ -2204,6 +2198,61 @@ pub async fn call_to_locker_hs(
     Ok(stored_card)
 }
 
+#[instrument(skip_all)]
+pub async fn call_locker_api<T>(
+    state: &routes::SessionState,
+    request: Request,
+    flow_name: &str,
+    locker_choice: Option<api_enums::LockerChoice>,
+) -> errors::CustomResult<T, errors::VaultError>
+where
+    T: serde::de::DeserializeOwned,
+{
+    let locker = &state.conf.locker;
+    let jwekey = state.conf.jwekey.get_inner();
+    let response_type_name = type_name!(T);
+
+    let response = services::call_connector_api(state, request, flow_name)
+        .await
+        .change_context(errors::VaultError::ApiError)?;
+
+    let is_locker_call_succeeded = response.is_ok();
+
+    let jwe_body = response
+        .unwrap_or_else(|err| err)
+        .response
+        .parse_struct::<services::JweBody>("JweBody")
+        .change_context(errors::VaultError::ResponseDeserializationFailed)
+        .attach_printable("Failed while parsing locker response into JweBody")?;
+
+    let decrypted_payload = payment_methods::get_decrypted_response_payload(
+        jwekey,
+        jwe_body,
+        locker_choice,
+        locker.decryption_scheme.clone(),
+    )
+    .await
+    .change_context(errors::VaultError::ResponseDeserializationFailed)
+    .attach_printable("Failed while decrypting locker payload response")?;
+
+    // Irrespective of locker's response status, payload is JWE + JWS decrypted. But based on locker's status,
+    // if Ok, deserialize the decrypted payload into given type T
+    // if Err, raise an error including locker error message too
+    if is_locker_call_succeeded {
+        let stored_card_resp: Result<T, error_stack::Report<errors::VaultError>> =
+            decrypted_payload
+                .parse_struct(response_type_name)
+                .change_context(errors::VaultError::ResponseDeserializationFailed)
+                .attach_printable_lazy(|| {
+                    format!("Failed while parsing locker response into {response_type_name}")
+                });
+        stored_card_resp
+    } else {
+        Err::<T, error_stack::Report<errors::VaultError>>((errors::VaultError::ApiError).into())
+            .attach_printable_lazy(|| format!("Locker error response: {decrypted_payload:?}"))
+    }
+}
+
 #[cfg(all(
     any(feature = "v1", feature = "v2"),
     not(feature = "payment_methods_v2")
@@ -2322,29 +2371,21 @@ pub async fn get_card_from_hs_locker<'a>(
             merchant_id,
             card_reference,
             Some(locker_choice),
+            state.tenant.name.clone(),
+            state.request_id,
         )
         .await
         .change_context(errors::VaultError::FetchCardFailed)
         .attach_printable("Making get card request failed")?;
-        let response = services::call_connector_api(state, request, "get_card_from_locker")
-            .await
-            .change_context(errors::VaultError::FetchCardFailed)
-            .attach_printable("Failed while executing call_connector_api for get_card");
-        let jwe_body: services::JweBody = response
-            .get_response_inner("JweBody")
-            .change_context(errors::VaultError::FetchCardFailed)?;
-        let decrypted_payload = payment_methods::get_decrypted_response_payload(
-            jwekey,
-            jwe_body,
+        let get_card_resp = call_locker_api::<payment_methods::RetrieveCardResp>(
+            state,
+            request,
+            "get_card_from_locker",
             Some(locker_choice),
-            locker.decryption_scheme.clone(),
         )
         .await
-        .change_context(errors::VaultError::FetchCardFailed)
-        .attach_printable("Error getting decrypted response payload for get card")?;
-        let get_card_resp: payment_methods::RetrieveCardResp = decrypted_payload
-            .parse_struct("RetrieveCardResp")
-            .change_context(errors::VaultError::FetchCardFailed)?;
+        .change_context(errors::VaultError::FetchCardFailed)?;
+
         let retrieve_card_resp = get_card_resp
             .payload
             .get_required_value("RetrieveCardRespPayload")
@@ -2366,7 +2407,7 @@ pub async fn delete_card_from_hs_locker<'a>(
     customer_id: &id_type::CustomerId,
     merchant_id: &id_type::MerchantId,
     card_reference: &'a str,
-) -> errors::RouterResult<payment_methods::DeleteCardResp> {
+) -> errors::CustomResult<payment_methods::DeleteCardResp, errors::VaultError> {
     let locker = &state.conf.locker;
     let jwekey = &state.conf.jwekey.get_inner();
 
@@ -2376,35 +2417,26 @@ pub async fn delete_card_from_hs_locker<'a>(
         customer_id,
         merchant_id,
         card_reference,
+        state.tenant.name.clone(),
+        state.request_id,
     )
     .await
-    .change_context(errors::ApiErrorResponse::InternalServerError)
+    .change_context(errors::VaultError::DeleteCardFailed)
     .attach_printable("Making delete card request failed")?;
 
     if !locker.mock_locker {
-        let response = services::call_connector_api(state, request, "delete_card_from_locker")
-            .await
-            .change_context(errors::ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed while executing call_connector_api for delete card");
-        let jwe_body: services::JweBody = response.get_response_inner("JweBody")?;
-        let decrypted_payload = payment_methods::get_decrypted_response_payload(
-            jwekey,
-            jwe_body,
+        call_locker_api::<payment_methods::DeleteCardResp>(
+            state,
+            request,
+            "delete_card_from_locker",
             Some(api_enums::LockerChoice::HyperswitchCardVault),
-            locker.decryption_scheme.clone(),
         )
         .await
-        .change_context(errors::ApiErrorResponse::InternalServerError)
-        .attach_printable("Error getting decrypted response payload for delete card")?;
-        let delete_card_resp: payment_methods::DeleteCardResp = decrypted_payload
-            .parse_struct("DeleteCardResp")
-            .change_context(errors::ApiErrorResponse::InternalServerError)?;
-        Ok(delete_card_resp)
+        .change_context(errors::VaultError::DeleteCardFailed)
     } else {
         Ok(mock_delete_card_hs(&*state.store, card_reference)
             .await
-            .change_context(errors::ApiErrorResponse::InternalServerError)
-            .attach_printable("card_delete_failure_message")?)
+            .change_context(errors::VaultError::DeleteCardFailed)?)
     }
 }
 
@@ -4871,6 +4903,10 @@ pub async fn list_customer_payment_method(
 
     let mut filtered_saved_payment_methods_ctx = Vec::new();
     for pm in saved_payment_methods.into_iter() {
+        logger::debug!(
+            "Fetching payment method from locker for payment_method_id: {}",
+            pm.id
+        );
         let payment_method = pm.payment_method.get_required_value("payment_method")?;
         let parent_payment_method_token =
             is_payment_associated.then(|| generate_id(consts::ID_LENGTH, "token"));
diff --git a/crates/router/src/core/payment_methods/transformers.rs b/crates/router/src/core/payment_methods/transformers.rs
index f594feb5954..f01ecffbbb3 100644
--- a/crates/router/src/core/payment_methods/transformers.rs
+++ b/crates/router/src/core/payment_methods/transformers.rs
@@ -10,6 +10,7 @@ use common_utils::{
 };
 use error_stack::ResultExt;
 use josekit::jwe;
+use router_env::tracing_actix_web::RequestId;
 use serde::{Deserialize, Serialize};
 
 use crate::{
@@ -301,6 +302,8 @@ pub async fn mk_add_locker_request_hs(
     locker: &settings::Locker,
     payload: &StoreLockerReq,
     locker_choice: api_enums::LockerChoice,
+    tenant_id: String,
+    request_id: Option<RequestId>,
 ) -> CustomResult<services::Request, errors::VaultError> {
     let payload = payload
         .encode_to_vec()
@@ -319,6 +322,13 @@ pub async fn mk_add_locker_request_hs(
     url.push_str("/cards/add");
     let mut request = services::Request::new(services::Method::Post, &url);
     request.add_header(headers::CONTENT_TYPE, "application/json".into());
+    request.add_header(headers::X_TENANT_ID, tenant_id.into());
+    if let Some(req_id) = request_id {
+        request.add_header(
+            headers::X_REQUEST_ID,
+            req_id.as_hyphenated().to_string().into(),
+        );
+    }
     request.set_body(RequestContent::Json(Box::new(jwe_payload)));
     Ok(request)
 }
@@ -425,6 +435,7 @@ pub fn mk_add_card_response_hs(
     todo!()
 }
 
+#[allow(clippy::too_many_arguments)]
 pub async fn mk_get_card_request_hs(
     jwekey: &settings::Jwekey,
     locker: &settings::Locker,
@@ -432,6 +443,8 @@ pub async fn mk_get_card_request_hs(
     merchant_id: &id_type::MerchantId,
     card_reference: &str,
     locker_choice: Option<api_enums::LockerChoice>,
+    tenant_id: String,
+    request_id: Option<RequestId>,
 ) -> CustomResult<services::Request, errors::VaultError> {
     let merchant_customer_id = customer_id.to_owned();
     let card_req_body = CardReqBody {
@@ -458,6 +471,14 @@ pub async fn mk_get_card_request_hs(
     url.push_str("/cards/retrieve");
     let mut request = services::Request::new(services::Method::Post, &url);
     request.add_header(headers::CONTENT_TYPE, "application/json".into());
+    request.add_header(headers::X_TENANT_ID, tenant_id.into());
+    if let Some(req_id) = request_id {
+        request.add_header(
+            headers::X_REQUEST_ID,
+            req_id.as_hyphenated().to_string().into(),
+        );
+    }
+
     request.set_body(RequestContent::Json(Box::new(jwe_payload)));
     Ok(request)
 }
@@ -503,6 +524,8 @@ pub async fn mk_delete_card_request_hs(
     customer_id: &id_type::CustomerId,
     merchant_id: &id_type::MerchantId,
     card_reference: &str,
+    tenant_id: String,
+    request_id: Option<RequestId>,
 ) -> CustomResult<services::Request, errors::VaultError> {
     let merchant_customer_id = customer_id.to_owned();
     let card_req_body = CardReqBody {
@@ -527,6 +550,14 @@ pub async fn mk_delete_card_request_hs(
     url.push_str("/cards/delete");
     let mut request = services::Request::new(services::Method::Post, &url);
     request.add_header(headers::CONTENT_TYPE, "application/json".into());
+    request.add_header(headers::X_TENANT_ID, tenant_id.into());
+    if let Some(req_id) = request_id {
+        request.add_header(
+            headers::X_REQUEST_ID,
+            req_id.as_hyphenated().to_string().into(),
+        );
+    }
+
     request.set_body(RequestContent::Json(Box::new(jwe_payload)));
     Ok(request)
 }
@@ -539,6 +570,8 @@ pub async fn mk_delete_card_request_hs_by_id(
     id: &String,
     merchant_id: &id_type::MerchantId,
     card_reference: &str,
+    tenant_id: String,
+    request_id: Option<RequestId>,
 ) -> CustomResult<services::Request, errors::VaultError> {
     let merchant_customer_id = id.to_owned();
     let card_req_body = CardReqBodyV2 {
@@ -563,6 +596,14 @@ pub async fn mk_delete_card_request_hs_by_id(
     url.push_str("/cards/delete");
     let mut request = services::Request::new(services::Method::Post, &url);
     request.add_header(headers::CONTENT_TYPE, "application/json".into());
+    request.add_header(headers::X_TENANT_ID, tenant_id.into());
+    if let Some(req_id) = request_id {
+        request.add_header(
+            headers::X_REQUEST_ID,
+            req_id.as_hyphenated().to_string().into(),
+        );
+    }
+
     request.set_body(RequestContent::Json(Box::new(jwe_payload)));
     Ok(request)
 }
@@ -641,12 +682,22 @@ pub fn mk_crud_locker_request(
     locker: &settings::Locker,
     path: &str,
     req: api::TokenizePayloadEncrypted,
+    tenant_id: String,
+    request_id: Option<RequestId>,
 ) -> CustomResult<services::Request, errors::VaultError> {
     let mut url = locker.basilisk_host.to_owned();
     url.push_str(path);
     let mut request = services::Request::new(services::Method::Post, &url);
     request.add_default_headers();
     request.add_header(headers::CONTENT_TYPE, "application/json".into());
+    request.add_header(headers::X_TENANT_ID, tenant_id.into());
+    if let Some(req_id) = request_id {
+        request.add_header(
+            headers::X_REQUEST_ID,
+            req_id.as_hyphenated().to_string().into(),
+        );
+    }
+
     request.set_body(RequestContent::Json(Box::new(req)));
     Ok(request)
 }
diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs
index 11cb0c11761..035c5c139a8 100644
--- a/crates/router/src/core/payouts/helpers.rs
+++ b/crates/router/src/core/payouts/helpers.rs
@@ -307,7 +307,7 @@ pub async fn save_payout_data_to_locker(
         };
 
     // Store payout method in locker
-    let stored_resp = cards::call_to_locker_hs(
+    let stored_resp = cards::add_card_to_hs_locker(
         state,
         &locker_req,
         customer_id,
@@ -559,6 +559,7 @@ pub async fn save_payout_data_to_locker(
             card_reference,
         )
         .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
         .attach_printable(
             "Failed to delete PMD from locker as a part of metadata update operation",
         )?;
@@ -566,7 +567,7 @@ pub async fn save_payout_data_to_locker(
         locker_req.update_requestor_card_reference(Some(card_reference.to_string()));
 
         // Store in locker
-        let stored_resp = cards::call_to_locker_hs(
+        let stored_resp = cards::add_card_to_hs_locker(
             state,
             &locker_req,
             customer_id,
diff --git a/crates/router/src/lib.rs b/crates/router/src/lib.rs
index ac452233e0f..caa96826937 100644
--- a/crates/router/src/lib.rs
+++ b/crates/router/src/lib.rs
@@ -83,6 +83,7 @@ pub mod headers {
     pub const BROWSER_NAME: &str = "x-browser-name";
     pub const X_CLIENT_PLATFORM: &str = "x-client-platform";
     pub const X_MERCHANT_DOMAIN: &str = "x-merchant-domain";
+    pub const X_TENANT_ID: &str = "x-tenant-id";
 }
 
 pub mod pii {

## 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 PR performs below changes - 
* Creates a single method using which locker api can be called and deserialised to the given type. 
* Currently, if locker returns an Err, the error response is not JWE+JWS decrypted. Instead its logged directly. This new method calls the api and irrespective of whether locker responds with an OK response or Err response, JWE+JWS decryption happens on the locker response. 
* Sends `x-tenant-id` in the headers to locker

### 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)?
-->
To test, I failed the locker on purpose and received below error report in Hyperswitch which also includes JWE+JWS decrypted error message.

![image](https://github.com/user-attachments/assets/e2c5374d-529d-4184-8353-5b485d4180f8)

Sandbox testing - Basic sanity tests which also involves saving card in locker would suffice 

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