Bug: [REFACTOR] Add additional field in MandateResponse



### Feature Description

Add additional field, `payment_method_response` in MandateResponse

### Possible Implementation

Add additional field, `payment_method_response` in MandateResponse

### 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/config/config.example.toml b/config/config.example.toml
index d4e11964192..cf25ef195a2 100644
--- a/config/config.example.toml
+++ b/config/config.example.toml
@@ -131,6 +131,7 @@ host_rs = ""                   # Rust Locker host
 mock_locker = true             # Emulate a locker locally using Postgres
 basilisk_host = ""             # Basilisk host
 locker_signing_key_id = "1"    # Key_id to sign basilisk hs locker
+locker_enabled = true         # Boolean to enable or disable saving cards in locker
 
 [delayed_session_response]
 connectors_with_delayed_session_response = "trustpay,payme" # List of connectors which has delayed session response
diff --git a/config/development.toml b/config/development.toml
index 91269005a0f..b23f68680e6 100644
--- a/config/development.toml
+++ b/config/development.toml
@@ -69,6 +69,8 @@ host = ""
 host_rs = ""
 mock_locker = true
 basilisk_host = ""
+locker_enabled = true
+
 
 [forex_api]
 call_delay = 21600
diff --git a/config/docker_compose.toml b/config/docker_compose.toml
index 450fe106a31..8af1528e177 100644
--- a/config/docker_compose.toml
+++ b/config/docker_compose.toml
@@ -56,6 +56,7 @@ host = ""
 host_rs = ""
 mock_locker = true
 basilisk_host = ""
+locker_enabled = true
 
 [jwekey]
 vault_encryption_key = ""
diff --git a/crates/api_models/src/mandates.rs b/crates/api_models/src/mandates.rs
index 5c0810dc21b..b29f4e0d0c3 100644
--- a/crates/api_models/src/mandates.rs
+++ b/crates/api_models/src/mandates.rs
@@ -36,6 +36,8 @@ pub struct MandateResponse {
     pub payment_method_id: String,
     /// The payment method
     pub payment_method: String,
+    /// The payment method type
+    pub payment_method_type: Option<String>,
     /// The card details for mandate
     pub card: Option<MandateCardDetails>,
     /// Details about the customer’s acceptance
@@ -66,6 +68,15 @@ pub struct MandateCardDetails {
     #[schema(value_type = Option<String>)]
     /// A unique identifier alias to identify a particular card
     pub card_fingerprint: Option<Secret<String>>,
+    /// The first 6 digits of card
+    pub card_isin: Option<String>,
+    /// The bank that issued the card
+    pub card_issuer: Option<String>,
+    /// The network that facilitates payment card transactions
+    #[schema(value_type = Option<CardNetwork>)]
+    pub card_network: Option<api_enums::CardNetwork>,
+    /// The type of the payment card
+    pub card_type: Option<String>,
 }
 
 #[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs
index 3467777da74..984e6dbffff 100644
--- a/crates/api_models/src/payment_methods.rs
+++ b/crates/api_models/src/payment_methods.rs
@@ -109,6 +109,19 @@ pub struct CardDetail {
     /// Card Holder's Nick Name
     #[schema(value_type = Option<String>,example = "John Doe")]
     pub nick_name: Option<masking::Secret<String>>,
+
+    /// Card Issuing Country
+    pub card_issuing_country: Option<String>,
+
+    /// Card's Network
+    #[schema(value_type = Option<CardNetwork>)]
+    pub card_network: Option<api_enums::CardNetwork>,
+
+    /// Issuer Bank for Card
+    pub card_issuer: Option<String>,
+
+    /// Card Type
+    pub card_type: Option<String>,
 }
 
 #[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)]
@@ -177,6 +190,12 @@ pub struct CardDetailsPaymentMethod {
     pub expiry_year: Option<masking::Secret<String>>,
     pub nick_name: Option<masking::Secret<String>>,
     pub card_holder_name: Option<masking::Secret<String>>,
+    pub card_isin: Option<String>,
+    pub card_issuer: Option<String>,
+    pub card_network: Option<api_enums::CardNetwork>,
+    pub card_type: Option<String>,
+    #[serde(default = "saved_in_locker_default")]
+    pub saved_to_locker: bool,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
@@ -227,6 +246,18 @@ pub struct CardDetailFromLocker {
 
     #[schema(value_type=Option<String>)]
     pub nick_name: Option<masking::Secret<String>>,
+
+    #[schema(value_type = Option<CardNetwork>)]
+    pub card_network: Option<api_enums::CardNetwork>,
+
+    pub card_isin: Option<String>,
+    pub card_issuer: Option<String>,
+    pub card_type: Option<String>,
+    pub saved_to_locker: bool,
+}
+
+fn saved_in_locker_default() -> bool {
+    true
 }
 
 impl From<CardDetailsPaymentMethod> for CardDetailFromLocker {
@@ -242,6 +273,11 @@ impl From<CardDetailsPaymentMethod> for CardDetailFromLocker {
             card_holder_name: item.card_holder_name,
             card_fingerprint: None,
             nick_name: item.nick_name,
+            card_isin: item.card_isin,
+            card_issuer: item.card_issuer,
+            card_network: item.card_network,
+            card_type: item.card_type,
+            saved_to_locker: item.saved_to_locker,
         }
     }
 }
@@ -255,6 +291,11 @@ impl From<CardDetailFromLocker> for CardDetailsPaymentMethod {
             expiry_year: item.expiry_year,
             nick_name: item.nick_name,
             card_holder_name: item.card_holder_name,
+            card_isin: item.card_isin,
+            card_issuer: item.card_issuer,
+            card_network: item.card_network,
+            card_type: item.card_type,
+            saved_to_locker: item.saved_to_locker,
         }
     }
 }
diff --git a/crates/router/src/configs/defaults.rs b/crates/router/src/configs/defaults.rs
index 42839bf3513..e4a470d0da3 100644
--- a/crates/router/src/configs/defaults.rs
+++ b/crates/router/src/configs/defaults.rs
@@ -54,6 +54,8 @@ impl Default for super::settings::Locker {
             mock_locker: true,
             basilisk_host: "localhost".into(),
             locker_signing_key_id: "1".into(),
+            //true or false
+            locker_enabled: true,
         }
     }
 }
diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs
index 3d93c2f188b..bcf26d63ae8 100644
--- a/crates/router/src/configs/settings.rs
+++ b/crates/router/src/configs/settings.rs
@@ -490,6 +490,7 @@ pub struct Locker {
     pub mock_locker: bool,
     pub basilisk_host: String,
     pub locker_signing_key_id: String,
+    pub locker_enabled: bool,
 }
 
 #[derive(Debug, Deserialize, Clone)]
diff --git a/crates/router/src/core/locker_migration.rs b/crates/router/src/core/locker_migration.rs
index e3e308a8a01..4bd2555792a 100644
--- a/crates/router/src/core/locker_migration.rs
+++ b/crates/router/src/core/locker_migration.rs
@@ -101,6 +101,10 @@ pub async fn call_to_locker(
             card_exp_year: card.card_exp_year,
             card_holder_name: card.name_on_card,
             nick_name: card.nick_name.map(masking::Secret::new),
+            card_issuing_country: None,
+            card_network: None,
+            card_issuer: None,
+            card_type: None,
         };
 
         let pm_create = api::PaymentMethodCreate {
diff --git a/crates/router/src/core/mandate.rs b/crates/router/src/core/mandate.rs
index aabd846660c..b6837d14f82 100644
--- a/crates/router/src/core/mandate.rs
+++ b/crates/router/src/core/mandate.rs
@@ -33,6 +33,7 @@ use crate::{
 pub async fn get_mandate(
     state: AppState,
     merchant_account: domain::MerchantAccount,
+    key_store: domain::MerchantKeyStore,
     req: mandates::MandateId,
 ) -> RouterResponse<mandates::MandateResponse> {
     let mandate = state
@@ -42,7 +43,7 @@ pub async fn get_mandate(
         .await
         .to_not_found_response(errors::ApiErrorResponse::MandateNotFound)?;
     Ok(services::ApplicationResponse::Json(
-        mandates::MandateResponse::from_db_mandate(&state, mandate).await?,
+        mandates::MandateResponse::from_db_mandate(&state, key_store, mandate).await?,
     ))
 }
 
@@ -202,6 +203,7 @@ pub async fn update_connector_mandate_id(
 pub async fn get_customer_mandates(
     state: AppState,
     merchant_account: domain::MerchantAccount,
+    key_store: domain::MerchantKeyStore,
     req: customers::CustomerId,
 ) -> RouterResponse<Vec<mandates::MandateResponse>> {
     let mandates = state
@@ -221,7 +223,10 @@ pub async fn get_customer_mandates(
     } else {
         let mut response_vec = Vec::with_capacity(mandates.len());
         for mandate in mandates {
-            response_vec.push(mandates::MandateResponse::from_db_mandate(&state, mandate).await?);
+            response_vec.push(
+                mandates::MandateResponse::from_db_mandate(&state, key_store.clone(), mandate)
+                    .await?,
+            );
         }
         Ok(services::ApplicationResponse::Json(response_vec))
     }
@@ -383,6 +388,7 @@ where
 pub async fn retrieve_mandates_list(
     state: AppState,
     merchant_account: domain::MerchantAccount,
+    key_store: domain::MerchantKeyStore,
     constraints: api_models::mandates::MandateListConstraints,
 ) -> RouterResponse<Vec<api_models::mandates::MandateResponse>> {
     let mandates = state
@@ -392,11 +398,9 @@ pub async fn retrieve_mandates_list(
         .await
         .change_context(errors::ApiErrorResponse::InternalServerError)
         .attach_printable("Unable to retrieve mandates")?;
-    let mandates_list = future::try_join_all(
-        mandates
-            .into_iter()
-            .map(|mandate| mandates::MandateResponse::from_db_mandate(&state, mandate)),
-    )
+    let mandates_list = future::try_join_all(mandates.into_iter().map(|mandate| {
+        mandates::MandateResponse::from_db_mandate(&state, key_store.clone(), mandate)
+    }))
     .await?;
     Ok(services::ApplicationResponse::Json(mandates_list))
 }
diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs
index 51f54353635..1a8bbcc8ef7 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -558,6 +558,7 @@ pub async fn add_card_hs(
         req,
         &merchant_account.merchant_id,
     );
+
     Ok((
         payment_method_resp,
         store_card_payload.duplicate.unwrap_or(false),
@@ -2508,11 +2509,19 @@ pub async fn list_customer_payment_method(
         let parent_payment_method_token = generate_id(consts::ID_LENGTH, "token");
 
         let (card, pmd, hyperswitch_token_data) = match pm.payment_method {
-            enums::PaymentMethod::Card => (
-                Some(get_card_details(&pm, key, state).await?),
-                None,
-                PaymentTokenData::permanent_card(pm.payment_method_id.clone()),
-            ),
+            enums::PaymentMethod::Card => {
+                let card_details = get_card_details_with_locker_fallback(&pm, key, state).await?;
+
+                if card_details.is_some() {
+                    (
+                        card_details,
+                        None,
+                        PaymentTokenData::permanent_card(pm.payment_method_id.clone()),
+                    )
+                } else {
+                    continue;
+                }
+            }
 
             #[cfg(feature = "payouts")]
             enums::PaymentMethod::BankTransfer => {
@@ -2571,6 +2580,7 @@ pub async fn list_customer_payment_method(
         };
 
         //Need validation for enabled payment method ,querying MCA
+
         let pma = api::CustomerPaymentMethod {
             payment_token: parent_payment_method_token.to_owned(),
             customer_id: pm.customer_id,
@@ -2700,7 +2710,38 @@ pub async fn list_customer_payment_method(
     Ok(services::ApplicationResponse::Json(response))
 }
 
-async fn get_card_details(
+pub async fn get_card_details_with_locker_fallback(
+    pm: &payment_method::PaymentMethod,
+    key: &[u8],
+    state: &routes::AppState,
+) -> errors::RouterResult<Option<api::CardDetailFromLocker>> {
+    let card_decrypted =
+        decrypt::<serde_json::Value, masking::WithType>(pm.payment_method_data.clone(), key)
+            .await
+            .change_context(errors::StorageError::DecryptionError)
+            .attach_printable("unable to decrypt card details")
+            .ok()
+            .flatten()
+            .map(|x| x.into_inner().expose())
+            .and_then(|v| serde_json::from_value::<PaymentMethodsData>(v).ok())
+            .and_then(|pmd| match pmd {
+                PaymentMethodsData::Card(crd) => Some(api::CardDetailFromLocker::from(crd)),
+                _ => None,
+            });
+
+    Ok(if let Some(mut crd) = card_decrypted {
+        if crd.saved_to_locker {
+            crd.scheme = pm.scheme.clone();
+            Some(crd)
+        } else {
+            None
+        }
+    } else {
+        Some(get_card_details_from_locker(state, pm).await?)
+    })
+}
+
+pub async fn get_card_details_without_locker_fallback(
     pm: &payment_method::PaymentMethod,
     key: &[u8],
     state: &routes::AppState,
@@ -2971,25 +3012,32 @@ impl TempLockerCardSupport {
 pub async fn retrieve_payment_method(
     state: routes::AppState,
     pm: api::PaymentMethodId,
+    key_store: domain::MerchantKeyStore,
 ) -> errors::RouterResponse<api::PaymentMethodResponse> {
     let db = state.store.as_ref();
     let pm = db
         .find_payment_method(&pm.payment_method_id)
         .await
         .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
+
+    let key = key_store.key.peek();
     let card = if pm.payment_method == enums::PaymentMethod::Card {
-        let card = get_card_from_locker(
-            &state,
-            &pm.customer_id,
-            &pm.merchant_id,
-            &pm.payment_method_id,
-        )
-        .await
-        .change_context(errors::ApiErrorResponse::InternalServerError)
-        .attach_printable("Error getting card from card vault")?;
-        let card_detail = payment_methods::get_card_detail(&pm, card)
+        let card_detail = if state.conf.locker.locker_enabled {
+            let card = get_card_from_locker(
+                &state,
+                &pm.customer_id,
+                &pm.merchant_id,
+                &pm.payment_method_id,
+            )
+            .await
             .change_context(errors::ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed while getting card details from locker")?;
+            .attach_printable("Error getting card from card vault")?;
+            payment_methods::get_card_detail(&pm, card)
+                .change_context(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("Failed while getting card details from locker")?
+        } else {
+            get_card_details_without_locker_fallback(&pm, key, &state).await?
+        };
         Some(card_detail)
     } else {
         None
diff --git a/crates/router/src/core/payment_methods/transformers.rs b/crates/router/src/core/payment_methods/transformers.rs
index da4f03b49c1..304091e42ac 100644
--- a/crates/router/src/core/payment_methods/transformers.rs
+++ b/crates/router/src/core/payment_methods/transformers.rs
@@ -352,18 +352,26 @@ pub fn mk_add_card_response_hs(
     req: api::PaymentMethodCreate,
     merchant_id: &str,
 ) -> api::PaymentMethodResponse {
-    let mut card_number = card.card_number.peek().to_owned();
+    let card_number = card.card_number.clone();
+    let last4_digits = card_number.clone().get_last4();
+    let card_isin = card_number.get_card_isin();
+
     let card = api::CardDetailFromLocker {
         scheme: None,
-        last4_digits: Some(card_number.split_off(card_number.len() - 4)),
-        issuer_country: None, // [#256] bin mapping
-        card_number: Some(card.card_number),
-        expiry_month: Some(card.card_exp_month),
-        expiry_year: Some(card.card_exp_year),
-        card_token: None,       // [#256]
-        card_fingerprint: None, // fingerprint not send by basilisk-hs need to have this feature in case we need it in future
-        card_holder_name: card.card_holder_name,
-        nick_name: card.nick_name,
+        last4_digits: Some(last4_digits),
+        issuer_country: None,
+        card_number: Some(card.card_number.clone()),
+        expiry_month: Some(card.card_exp_month.clone()),
+        expiry_year: Some(card.card_exp_year.clone()),
+        card_token: None,
+        card_fingerprint: None,
+        card_holder_name: card.card_holder_name.clone(),
+        nick_name: card.nick_name.clone(),
+        card_isin: Some(card_isin),
+        card_issuer: card.card_issuer,
+        card_network: card.card_network,
+        card_type: card.card_type,
+        saved_to_locker: true,
     };
     api::PaymentMethodResponse {
         merchant_id: merchant_id.to_owned(),
@@ -399,6 +407,11 @@ pub fn mk_add_card_response(
         card_fingerprint: Some(response.card_fingerprint),
         card_holder_name: card.card_holder_name,
         nick_name: card.nick_name,
+        card_isin: None,
+        card_issuer: None,
+        card_network: None,
+        card_type: None,
+        saved_to_locker: true,
     };
     api::PaymentMethodResponse {
         merchant_id: merchant_id.to_owned(),
@@ -597,6 +610,8 @@ pub fn get_card_detail(
 ) -> CustomResult<api::CardDetailFromLocker, errors::VaultError> {
     let card_number = response.card_number;
     let mut last4_digits = card_number.peek().to_owned();
+    //fetch form card bin
+
     let card_detail = api::CardDetailFromLocker {
         scheme: pm.scheme.to_owned(),
         issuer_country: pm.issuer_country.clone(),
@@ -608,6 +623,11 @@ pub fn get_card_detail(
         card_fingerprint: None,
         card_holder_name: response.name_on_card,
         nick_name: response.nick_name.map(masking::Secret::new),
+        card_isin: None,
+        card_issuer: None,
+        card_network: None,
+        card_type: None,
+        saved_to_locker: true,
     };
     Ok(card_detail)
 }
diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs
index 07af15a336d..15c79f4b9d9 100644
--- a/crates/router/src/core/payments/flows/authorize_flow.rs
+++ b/crates/router/src/core/payments/flows/authorize_flow.rs
@@ -92,7 +92,9 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu
 
             metrics::PAYMENT_COUNT.add(&metrics::CONTEXT, 1, &[]); // Metrics
 
-            if resp.request.setup_mandate_details.clone().is_some() {
+            let is_mandate = resp.request.setup_mandate_details.is_some();
+
+            if is_mandate {
                 let payment_method_id = Box::pin(tokenization::save_payment_method(
                     state,
                     connector,
diff --git a/crates/router/src/core/payments/flows/setup_mandate_flow.rs b/crates/router/src/core/payments/flows/setup_mandate_flow.rs
index 0c03c8ce123..d6343ed871b 100644
--- a/crates/router/src/core/payments/flows/setup_mandate_flow.rs
+++ b/crates/router/src/core/payments/flows/setup_mandate_flow.rs
@@ -208,6 +208,7 @@ impl types::SetupMandateRouterData {
                 .to_setup_mandate_failed_response()?;
 
                 let payment_method_type = self.request.payment_method_type;
+
                 let pm_id = Box::pin(tokenization::save_payment_method(
                     state,
                     connector,
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index 92dc1bf5f4b..e3a3ccdc02c 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -509,16 +509,23 @@ pub async fn get_token_for_recurring_mandate(
     };
 
     if let diesel_models::enums::PaymentMethod::Card = payment_method.payment_method {
-        let _ =
-            cards::get_lookup_key_from_locker(state, &token, &payment_method, merchant_key_store)
-                .await?;
+        if state.conf.locker.locker_enabled {
+            let _ = cards::get_lookup_key_from_locker(
+                state,
+                &token,
+                &payment_method,
+                merchant_key_store,
+            )
+            .await?;
+        }
+
         if let Some(payment_method_from_request) = req.payment_method {
             let pm: storage_enums::PaymentMethod = payment_method_from_request;
             if pm != payment_method.payment_method {
                 Err(report!(errors::ApiErrorResponse::PreconditionFailed {
                     message:
                         "payment method in request does not match previously provided payment \
-                                  method information"
+                        method information"
                             .into()
                 }))?
             }
@@ -971,7 +978,6 @@ pub fn payment_intent_status_fsm(
         None => storage_enums::IntentStatus::RequiresPaymentMethod,
     }
 }
-
 pub async fn add_domain_task_to_pt<Op>(
     operation: &Op,
     state: &AppState,
@@ -1034,6 +1040,10 @@ pub(crate) async fn get_payment_method_create_request(
                         card_exp_year: card.card_exp_year.clone(),
                         card_holder_name: card.card_holder_name.clone(),
                         nick_name: card.nick_name.clone(),
+                        card_issuing_country: card.card_issuing_country.clone(),
+                        card_network: card.card_network.clone(),
+                        card_issuer: card.card_issuer.clone(),
+                        card_type: card.card_type.clone(),
                     };
                     let customer_id = customer.customer_id.clone();
                     let payment_method_request = api::PaymentMethodCreate {
@@ -3343,21 +3353,23 @@ pub async fn get_additional_payment_data(
                             },
                         ))
                     });
-                card_info.unwrap_or(api_models::payments::AdditionalPaymentData::Card(Box::new(
-                    api_models::payments::AdditionalCardInfo {
-                        card_issuer: None,
-                        card_network: None,
-                        bank_code: None,
-                        card_type: None,
-                        card_issuing_country: None,
-                        last4,
-                        card_isin,
-                        card_extended_bin,
-                        card_exp_month: Some(card_data.card_exp_month.clone()),
-                        card_exp_year: Some(card_data.card_exp_year.clone()),
-                        card_holder_name: card_data.card_holder_name.clone(),
-                    },
-                )))
+                card_info.unwrap_or_else(|| {
+                    api_models::payments::AdditionalPaymentData::Card(Box::new(
+                        api_models::payments::AdditionalCardInfo {
+                            card_issuer: None,
+                            card_network: None,
+                            bank_code: None,
+                            card_type: None,
+                            card_issuing_country: None,
+                            last4,
+                            card_isin,
+                            card_extended_bin,
+                            card_exp_month: Some(card_data.card_exp_month.clone()),
+                            card_exp_year: Some(card_data.card_exp_year.clone()),
+                            card_holder_name: card_data.card_holder_name.clone(),
+                        },
+                    ))
+                })
             }
         }
         api_models::payments::PaymentMethodData::BankRedirect(bank_redirect_data) => {
diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs
index f884cb79e7e..15d88c94660 100644
--- a/crates/router/src/core/payments/tokenization.rs
+++ b/crates/router/src/core/payments/tokenization.rs
@@ -14,7 +14,7 @@ use crate::{
     services,
     types::{
         self,
-        api::{self, CardDetailsPaymentMethod, PaymentMethodCreateExt},
+        api::{self, CardDetailFromLocker, CardDetailsPaymentMethod, PaymentMethodCreateExt},
         domain,
         storage::enums as storage_enums,
     },
@@ -74,12 +74,21 @@ where
                 .await?;
                 let merchant_id = &merchant_account.merchant_id;
 
-                let locker_response = save_in_locker(
-                    state,
-                    merchant_account,
-                    payment_method_create_request.to_owned(),
-                )
-                .await?;
+                let locker_response = if !state.conf.locker.locker_enabled {
+                    skip_saving_card_in_locker(
+                        merchant_account,
+                        payment_method_create_request.to_owned(),
+                    )
+                    .await?
+                } else {
+                    save_in_locker(
+                        state,
+                        merchant_account,
+                        payment_method_create_request.to_owned(),
+                    )
+                    .await?
+                };
+
                 let is_duplicate = locker_response.1;
 
                 let pm_card_details = locker_response.0.card.as_ref().map(|card| {
@@ -168,6 +177,85 @@ where
     }
 }
 
+async fn skip_saving_card_in_locker(
+    merchant_account: &domain::MerchantAccount,
+    payment_method_request: api::PaymentMethodCreate,
+) -> RouterResult<(api_models::payment_methods::PaymentMethodResponse, bool)> {
+    let merchant_id = &merchant_account.merchant_id;
+    let customer_id = payment_method_request
+        .clone()
+        .customer_id
+        .clone()
+        .get_required_value("customer_id")?;
+    let payment_method_id = common_utils::generate_id(crate::consts::ID_LENGTH, "pm");
+
+    let last4_digits = payment_method_request
+        .card
+        .clone()
+        .map(|c| c.card_number.get_last4());
+
+    let card_isin = payment_method_request
+        .card
+        .clone()
+        .map(|c: api_models::payment_methods::CardDetail| c.card_number.get_card_isin());
+
+    match payment_method_request.card.clone() {
+        Some(card) => {
+            let card_detail = CardDetailFromLocker {
+                scheme: None,
+                issuer_country: card.card_issuing_country.clone(),
+                last4_digits: last4_digits.clone(),
+                card_number: None,
+                expiry_month: Some(card.card_exp_month.clone()),
+                expiry_year: Some(card.card_exp_year),
+                card_token: None,
+                card_holder_name: card.card_holder_name.clone(),
+                card_fingerprint: None,
+                nick_name: None,
+                card_isin: card_isin.clone(),
+                card_issuer: card.card_issuer.clone(),
+                card_network: card.card_network.clone(),
+                card_type: card.card_type.clone(),
+                saved_to_locker: false,
+            };
+            let pm_resp = api::PaymentMethodResponse {
+                merchant_id: merchant_id.to_string(),
+                customer_id: Some(customer_id),
+                payment_method_id,
+                payment_method: payment_method_request.payment_method,
+                payment_method_type: payment_method_request.payment_method_type,
+                card: Some(card_detail),
+                recurring_enabled: false,
+                installment_payment_enabled: false,
+                payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]),
+                metadata: None,
+                created: Some(common_utils::date_time::now()),
+                bank_transfer: None,
+            };
+
+            Ok((pm_resp, false))
+        }
+        None => {
+            let pm_id = common_utils::generate_id(crate::consts::ID_LENGTH, "pm");
+            let payment_method_response = api::PaymentMethodResponse {
+                merchant_id: merchant_id.to_string(),
+                customer_id: Some(customer_id),
+                payment_method_id: pm_id,
+                payment_method: payment_method_request.payment_method,
+                payment_method_type: payment_method_request.payment_method_type,
+                card: None,
+                metadata: None,
+                created: Some(common_utils::date_time::now()),
+                recurring_enabled: false,
+                installment_payment_enabled: false,
+                payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]),
+                bank_transfer: None,
+            };
+            Ok((payment_method_response, false))
+        }
+    }
+}
+
 pub async fn save_in_locker(
     state: &AppState,
     merchant_account: &domain::MerchantAccount,
diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs
index 56e3a6faf53..1ab24023bdb 100644
--- a/crates/router/src/core/payouts/helpers.rs
+++ b/crates/router/src/core/payouts/helpers.rs
@@ -1,6 +1,6 @@
 use common_utils::{
     errors::CustomResult,
-    ext_traits::{StringExt, ValueExt},
+    ext_traits::{AsyncExt, StringExt, ValueExt},
 };
 use diesel_models::encryption::Encryption;
 use error_stack::{IntoReport, ResultExt};
@@ -19,6 +19,7 @@ use crate::{
     },
     db::StorageInterface,
     routes::AppState,
+    services,
     types::{
         api::{self, enums as api_enums},
         domain::{
@@ -184,6 +185,10 @@ pub async fn save_payout_data_to_locker(
                 card_exp_month: card.expiry_month.to_owned(),
                 card_exp_year: card.expiry_year.to_owned(),
                 nick_name: None,
+                card_issuing_country: None,
+                card_network: None,
+                card_issuer: None,
+                card_type: None,
             };
             let payload = StoreLockerReq::LockerCard(StoreCardReq {
                 merchant_id: &merchant_account.merchant_id,
@@ -267,20 +272,65 @@ pub async fn save_payout_data_to_locker(
     .change_context(errors::ApiErrorResponse::InternalServerError)
     .attach_printable("Error updating payouts in saved payout method")?;
 
-    let pm_data = api::payment_methods::PaymentMethodsData::Card(
-        api::payment_methods::CardDetailsPaymentMethod {
-            last4_digits: card_details
-                .as_ref()
-                .map(|c| c.card_number.clone().get_last4()),
-            issuer_country: None,
-            expiry_month: card_details.as_ref().map(|c| c.card_exp_month.clone()),
-            expiry_year: card_details.as_ref().map(|c| c.card_exp_year.clone()),
-            nick_name: card_details.as_ref().and_then(|c| c.nick_name.clone()),
-            card_holder_name: card_details
-                .as_ref()
-                .and_then(|c| c.card_holder_name.clone()),
-        },
-    );
+    // fetch card info from db
+    let card_isin = card_details
+        .as_ref()
+        .map(|c| c.card_number.clone().get_card_isin());
+
+    let pm_data = card_isin
+        .clone()
+        .async_and_then(|card_isin| async move {
+            db.get_card_info(&card_isin)
+                .await
+                .map_err(|error| services::logger::warn!(card_info_error=?error))
+                .ok()
+        })
+        .await
+        .flatten()
+        .map(|card_info| {
+            api::payment_methods::PaymentMethodsData::Card(
+                api::payment_methods::CardDetailsPaymentMethod {
+                    last4_digits: card_details
+                        .as_ref()
+                        .map(|c| c.card_number.clone().get_last4()),
+                    issuer_country: card_info.card_issuing_country,
+                    expiry_month: card_details.as_ref().map(|c| c.card_exp_month.clone()),
+                    expiry_year: card_details.as_ref().map(|c| c.card_exp_year.clone()),
+                    nick_name: card_details.as_ref().and_then(|c| c.nick_name.clone()),
+                    card_holder_name: card_details
+                        .as_ref()
+                        .and_then(|c| c.card_holder_name.clone()),
+
+                    card_isin: card_isin.clone(),
+                    card_issuer: card_info.card_issuer,
+                    card_network: card_info.card_network,
+                    card_type: card_info.card_type,
+                    saved_to_locker: true,
+                },
+            )
+        })
+        .unwrap_or_else(|| {
+            api::payment_methods::PaymentMethodsData::Card(
+                api::payment_methods::CardDetailsPaymentMethod {
+                    last4_digits: card_details
+                        .as_ref()
+                        .map(|c| c.card_number.clone().get_last4()),
+                    issuer_country: None,
+                    expiry_month: card_details.as_ref().map(|c| c.card_exp_month.clone()),
+                    expiry_year: card_details.as_ref().map(|c| c.card_exp_year.clone()),
+                    nick_name: card_details.as_ref().and_then(|c| c.nick_name.clone()),
+                    card_holder_name: card_details
+                        .as_ref()
+                        .and_then(|c| c.card_holder_name.clone()),
+
+                    card_isin: card_isin.clone(),
+                    card_issuer: None,
+                    card_network: None,
+                    card_type: None,
+                    saved_to_locker: true,
+                },
+            )
+        });
 
     let card_details_encrypted =
         cards::create_encrypted_payment_method_data(key_store, Some(pm_data)).await;
diff --git a/crates/router/src/core/webhooks.rs b/crates/router/src/core/webhooks.rs
index 4354a3ee195..f291d1cd2e8 100644
--- a/crates/router/src/core/webhooks.rs
+++ b/crates/router/src/core/webhooks.rs
@@ -421,6 +421,7 @@ pub async fn mandates_incoming_webhook_flow<W: types::OutgoingWebhookType>(
     state: AppState,
     merchant_account: domain::MerchantAccount,
     business_profile: diesel_models::business_profile::BusinessProfile,
+    key_store: domain::MerchantKeyStore,
     webhook_details: api::IncomingWebhookDetails,
     source_verified: bool,
     event_type: api_models::webhooks::IncomingWebhookEvent,
@@ -464,8 +465,12 @@ pub async fn mandates_incoming_webhook_flow<W: types::OutgoingWebhookType>(
             .await
             .to_not_found_response(errors::ApiErrorResponse::MandateNotFound)?;
         let mandates_response = Box::new(
-            api::mandates::MandateResponse::from_db_mandate(&state, updated_mandate.clone())
-                .await?,
+            api::mandates::MandateResponse::from_db_mandate(
+                &state,
+                key_store,
+                updated_mandate.clone(),
+            )
+            .await?,
         );
         let event_type: Option<enums::EventType> = updated_mandate.mandate_status.foreign_into();
         if let Some(outgoing_event_type) = event_type {
@@ -1237,6 +1242,7 @@ pub async fn webhooks_core<W: types::OutgoingWebhookType, Ctx: PaymentMethodRetr
                 state.clone(),
                 merchant_account,
                 business_profile,
+                key_store,
                 webhook_details,
                 source_verified,
                 event_type,
diff --git a/crates/router/src/routes/customers.rs b/crates/router/src/routes/customers.rs
index 2592d8837d5..e7a0804500c 100644
--- a/crates/router/src/routes/customers.rs
+++ b/crates/router/src/routes/customers.rs
@@ -226,7 +226,12 @@ pub async fn get_customer_mandates(
         &req,
         customer_id,
         |state, auth, req| {
-            crate::core::mandate::get_customer_mandates(state, auth.merchant_account, req)
+            crate::core::mandate::get_customer_mandates(
+                state,
+                auth.merchant_account,
+                auth.key_store,
+                req,
+            )
         },
         auth::auth_type(
             &auth::ApiKeyAuth,
diff --git a/crates/router/src/routes/mandates.rs b/crates/router/src/routes/mandates.rs
index ecc89a10fa2..468d202b94c 100644
--- a/crates/router/src/routes/mandates.rs
+++ b/crates/router/src/routes/mandates.rs
@@ -41,7 +41,7 @@ pub async fn get_mandate(
         state,
         &req,
         mandate_id,
-        |state, auth, req| mandate::get_mandate(state, auth.merchant_account, req),
+        |state, auth, req| mandate::get_mandate(state, auth.merchant_account, auth.key_store, req),
         &auth::ApiKeyAuth,
         api_locking::LockAction::NotApplicable,
     )
@@ -123,7 +123,9 @@ pub async fn retrieve_mandates_list(
         state,
         &req,
         payload,
-        |state, auth, req| mandate::retrieve_mandates_list(state, auth.merchant_account, req),
+        |state, auth, req| {
+            mandate::retrieve_mandates_list(state, auth.merchant_account, auth.key_store, req)
+        },
         auth::auth_type(
             &auth::ApiKeyAuth,
             &auth::JWTAuth(Permission::MandateRead),
diff --git a/crates/router/src/routes/payment_methods.rs b/crates/router/src/routes/payment_methods.rs
index a6eeeabd687..6ef5de886be 100644
--- a/crates/router/src/routes/payment_methods.rs
+++ b/crates/router/src/routes/payment_methods.rs
@@ -242,7 +242,7 @@ pub async fn payment_method_retrieve_api(
         state,
         &req,
         payload,
-        |state, _auth, pm| cards::retrieve_payment_method(state, pm),
+        |state, auth, pm| cards::retrieve_payment_method(state, pm, auth.key_store),
         &auth::ApiKeyAuth,
         api_locking::LockAction::NotApplicable,
     ))
diff --git a/crates/router/src/types/api/mandates.rs b/crates/router/src/types/api/mandates.rs
index 8d6b9a15e3a..f6b2d7bba93 100644
--- a/crates/router/src/types/api/mandates.rs
+++ b/crates/router/src/types/api/mandates.rs
@@ -1,6 +1,7 @@
 use api_models::mandates;
 pub use api_models::mandates::{MandateId, MandateResponse, MandateRevokedResponse};
 use error_stack::ResultExt;
+use masking::PeekInterface;
 use serde::{Deserialize, Serialize};
 
 use crate::{
@@ -11,7 +12,7 @@ use crate::{
     newtype,
     routes::AppState,
     types::{
-        api,
+        api, domain,
         storage::{self, enums as storage_enums},
     },
 };
@@ -23,12 +24,20 @@ newtype!(
 
 #[async_trait::async_trait]
 pub(crate) trait MandateResponseExt: Sized {
-    async fn from_db_mandate(state: &AppState, mandate: storage::Mandate) -> RouterResult<Self>;
+    async fn from_db_mandate(
+        state: &AppState,
+        key_store: domain::MerchantKeyStore,
+        mandate: storage::Mandate,
+    ) -> RouterResult<Self>;
 }
 
 #[async_trait::async_trait]
 impl MandateResponseExt for MandateResponse {
-    async fn from_db_mandate(state: &AppState, mandate: storage::Mandate) -> RouterResult<Self> {
+    async fn from_db_mandate(
+        state: &AppState,
+        key_store: domain::MerchantKeyStore,
+        mandate: storage::Mandate,
+    ) -> RouterResult<Self> {
         let db = &*state.store;
         let payment_method = db
             .find_payment_method(&mandate.payment_method_id)
@@ -36,21 +45,35 @@ impl MandateResponseExt for MandateResponse {
             .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
 
         let card = if payment_method.payment_method == storage_enums::PaymentMethod::Card {
-            let card = payment_methods::cards::get_card_from_locker(
-                state,
-                &payment_method.customer_id,
-                &payment_method.merchant_id,
-                &payment_method.payment_method_id,
-            )
-            .await?;
-            let card_detail = payment_methods::transformers::get_card_detail(&payment_method, card)
-                .change_context(errors::ApiErrorResponse::InternalServerError)
-                .attach_printable("Failed while getting card details")?;
-            Some(MandateCardDetails::from(card_detail).into_inner())
+            // if locker is disabled , decrypt the payment method data
+            let card_details = if state.conf.locker.locker_enabled {
+                let card = payment_methods::cards::get_card_from_locker(
+                    state,
+                    &payment_method.customer_id,
+                    &payment_method.merchant_id,
+                    &payment_method.payment_method_id,
+                )
+                .await?;
+
+                payment_methods::transformers::get_card_detail(&payment_method, card)
+                    .change_context(errors::ApiErrorResponse::InternalServerError)
+                    .attach_printable("Failed while getting card details")?
+            } else {
+                payment_methods::cards::get_card_details_without_locker_fallback(
+                    &payment_method,
+                    key_store.key.get_inner().peek(),
+                    state,
+                )
+                .await?
+            };
+
+            Some(MandateCardDetails::from(card_details).into_inner())
         } else {
             None
         };
-
+        let payment_method_type = payment_method
+            .payment_method_type
+            .map(|pmt| pmt.to_string());
         Ok(Self {
             mandate_id: mandate.mandate_id,
             customer_acceptance: Some(api::payments::CustomerAcceptance {
@@ -68,6 +91,7 @@ impl MandateResponseExt for MandateResponse {
             card,
             status: mandate.mandate_status,
             payment_method: payment_method.payment_method.to_string(),
+            payment_method_type,
             payment_method_id: mandate.payment_method_id,
         })
     }
@@ -84,6 +108,10 @@ impl From<api::payment_methods::CardDetailFromLocker> for MandateCardDetails {
             scheme: card_details_from_locker.scheme,
             issuer_country: card_details_from_locker.issuer_country,
             card_fingerprint: card_details_from_locker.card_fingerprint,
+            card_isin: card_details_from_locker.card_isin,
+            card_issuer: card_details_from_locker.card_issuer,
+            card_network: card_details_from_locker.card_network,
+            card_type: card_details_from_locker.card_type,
         }
         .into()
     }
diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml
index 358a591a667..268ebd1d3ac 100644
--- a/loadtest/config/development.toml
+++ b/loadtest/config/development.toml
@@ -33,6 +33,7 @@ host = ""
 host_rs = ""
 mock_locker = true
 basilisk_host = ""
+locker_enabled = true
 
 [forex_api]
 call_delay = 21600
diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json
index b2f5d3ea52c..02df6324a06 100644
--- a/openapi/openapi_spec.json
+++ b/openapi/openapi_spec.json
@@ -4421,11 +4421,37 @@
             "description": "Card Holder's Nick Name",
             "example": "John Doe",
             "nullable": true
+          },
+          "card_issuing_country": {
+            "type": "string",
+            "description": "Card Issuing Country",
+            "nullable": true
+          },
+          "card_network": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/CardNetwork"
+              }
+            ],
+            "nullable": true
+          },
+          "card_issuer": {
+            "type": "string",
+            "description": "Issuer Bank for Card",
+            "nullable": true
+          },
+          "card_type": {
+            "type": "string",
+            "description": "Card Type",
+            "nullable": true
           }
         }
       },
       "CardDetailFromLocker": {
         "type": "object",
+        "required": [
+          "saved_to_locker"
+        ],
         "properties": {
           "scheme": {
             "type": "string",
@@ -4462,6 +4488,29 @@
           "nick_name": {
             "type": "string",
             "nullable": true
+          },
+          "card_network": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/CardNetwork"
+              }
+            ],
+            "nullable": true
+          },
+          "card_isin": {
+            "type": "string",
+            "nullable": true
+          },
+          "card_issuer": {
+            "type": "string",
+            "nullable": true
+          },
+          "card_type": {
+            "type": "string",
+            "nullable": true
+          },
+          "saved_to_locker": {
+            "type": "boolean"
           }
         }
       },
@@ -6884,6 +6933,29 @@
             "type": "string",
             "description": "A unique identifier alias to identify a particular card",
             "nullable": true
+          },
+          "card_isin": {
+            "type": "string",
+            "description": "The first 6 digits of card",
+            "nullable": true
+          },
+          "card_issuer": {
+            "type": "string",
+            "description": "The bank that issued the card",
+            "nullable": true
+          },
+          "card_network": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/CardNetwork"
+              }
+            ],
+            "nullable": true
+          },
+          "card_type": {
+            "type": "string",
+            "description": "The type of the payment card",
+            "nullable": true
           }
         }
       },
@@ -6932,6 +7004,11 @@
             "type": "string",
             "description": "The payment method"
           },
+          "payment_method_type": {
+            "type": "string",
+            "description": "The payment method type",
+            "nullable": true
+          },
           "card": {
             "allOf": [
               {

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

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

## Description
Add locker config to enable or disable locker , so that if the locker is enabled we can store the card_details in the locker else if the config is disabled we don't 

Also this PR involvesaddition in the `MandateResponse`.

### 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).
-->
This Feature provides an option for the merchant whether or not to save the card at hyperswitch . Saving the card at hyperswitch is not necessary if the mandate is created at the processor level.

## How did you test it?

- Create an MA & MCA

- Disable the `locker_enabled` config

> Create  a Mandate payment , the details will not be stored in Locker and payment will be successful 
> List PaymentMethods for a Customer won't have any details as the card was never stored
> List the Mandates would have mandate details


![Screenshot 2024-01-16 at 4 38 43 PM](https://github.com/juspay/hyperswitch/assets/55580080/c9d5d11b-b31f-4a58-a324-f92c376a7c26)

![Screenshot 2024-01-16 at 4 38 59 PM](https://github.com/juspay/hyperswitch/assets/55580080/32645dfa-c962-43a2-9e7f-ca1056415560)

![Screenshot 2024-01-16 at 4 39 10 PM](https://github.com/juspay/hyperswitch/assets/55580080/f413bd94-b74c-4a1b-bf22-fbc335a05e56)

![Screenshot 2024-01-16 at 4 39 26 PM](https://github.com/juspay/hyperswitch/assets/55580080/2745fabd-bc81-4d2b-ab53-d6829fa53d13)

![Screenshot 2024-01-16 at 4 39 38 PM](https://github.com/juspay/hyperswitch/assets/55580080/25221f1c-7932-4295-9a6e-083355513c15)

- Enable the `locker_enabled` config

> Create  a Mandate payment , the details will be stored in Locker and payment will be successful 
> List PaymentMethods for a Customer would have details of the card that was stored
> List the Mandates


![Screenshot 2024-01-16 at 4 33 56 PM](https://github.com/juspay/hyperswitch/assets/55580080/174a1933-9112-4088-893c-12c4e84b3148)

![Screenshot 2024-01-16 at 4 34 57 PM](https://github.com/juspay/hyperswitch/assets/55580080/2a5f46e7-86b0-470e-89a6-3a8f0a225c3b)

![Screenshot 2024-01-16 at 4 35 18 PM](https://github.com/juspay/hyperswitch/assets/55580080/66a1df1f-0f8a-418e-a122-570508eb97a9)

![Screenshot 2024-01-16 at 4 35 33 PM](https://github.com/juspay/hyperswitch/assets/55580080/8c5fe598-9cad-498f-88eb-ef9ca0c3018b)

![Screenshot 2024-01-16 at 4 35 51 PM](https://github.com/juspay/hyperswitch/assets/55580080/8d05dbcb-ef2d-4c2a-b326-56393ed5b16e)

![Screenshot 2024-01-16 at 4 36 32 PM](https://github.com/juspay/hyperswitch/assets/55580080/0e3e9272-27b5-44de-9c3a-4e1e942faee9)

-When we do a list mandates we have an additional field `payment_method_type`

![Screenshot 2024-01-18 at 4 27 53 PM](https://github.com/juspay/hyperswitch/assets/55580080/7b2455e7-889b-4e01-979d-56353ce60f49)




## 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
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
