Bug: [FEATURE] Making CVV optional field for payments flow 



### Feature Description

 CVV should be Optional and should only be passed for first time payment else depending upon use cases we don't need to pass the CVV. It gets handeled by the conntector itslef

### Possible Implementation

We need to make the CVV field as optional and need to check for the  flows, that if mandate_id is passed then we don't need to include CVV as this is a recurring payment else in other case we have to pass cvv

### Have you spent some time to check if this feature request has been raised before?

- [X] I checked and didn't find 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/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index 3740c996ed3..a8c69d04e52 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -520,6 +520,7 @@ pub enum PaymentMethodData {
     BankRedirect(BankRedirectData),
     BankDebit(BankDebitData),
     Crypto(CryptoData),
+    MandatePayment,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
@@ -536,6 +537,7 @@ pub enum AdditionalPaymentData {
     PayLater {},
     Crypto {},
     BankDebit {},
+    MandatePayment {},
 }
 
 impl From<&PaymentMethodData> for AdditionalPaymentData {
@@ -561,6 +563,7 @@ impl From<&PaymentMethodData> for AdditionalPaymentData {
             PaymentMethodData::PayLater(_) => Self::PayLater {},
             PaymentMethodData::Crypto(_) => Self::Crypto {},
             PaymentMethodData::BankDebit(_) => Self::BankDebit {},
+            PaymentMethodData::MandatePayment => Self::MandatePayment {},
         }
     }
 }
@@ -790,6 +793,7 @@ pub enum PaymentMethodDataResponse {
     BankRedirect(BankRedirectData),
     Crypto(CryptoData),
     BankDebit(BankDebitData),
+    MandatePayment,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, ToSchema)]
@@ -1331,6 +1335,7 @@ impl From<PaymentMethodData> for PaymentMethodDataResponse {
             }
             PaymentMethodData::Crypto(crpto_data) => Self::Crypto(crpto_data),
             PaymentMethodData::BankDebit(bank_debit_data) => Self::BankDebit(bank_debit_data),
+            PaymentMethodData::MandatePayment => Self::MandatePayment,
         }
     }
 }
diff --git a/crates/router/src/connector/aci/transformers.rs b/crates/router/src/connector/aci/transformers.rs
index 6ecd6974c02..e4eb7a15854 100644
--- a/crates/router/src/connector/aci/transformers.rs
+++ b/crates/router/src/connector/aci/transformers.rs
@@ -184,7 +184,9 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for AciPaymentsRequest {
                     ))?,
                 }
             }
-            api::PaymentMethodData::Crypto(_) | api::PaymentMethodData::BankDebit(_) => {
+            api::PaymentMethodData::Crypto(_)
+            | api::PaymentMethodData::BankDebit(_)
+            | api::PaymentMethodData::MandatePayment => {
                 Err(errors::ConnectorError::NotSupported {
                     message: format!("{:?}", item.payment_method),
                     connector: "Aci",
diff --git a/crates/router/src/connector/authorizedotnet/transformers.rs b/crates/router/src/connector/authorizedotnet/transformers.rs
index 55500b281ac..0c93ba198fe 100644
--- a/crates/router/src/connector/authorizedotnet/transformers.rs
+++ b/crates/router/src/connector/authorizedotnet/transformers.rs
@@ -129,7 +129,9 @@ fn get_pm_and_subsequent_auth_detail(
             api::PaymentMethodData::BankRedirect(_) => {
                 Ok((PaymentDetails::BankRedirect, None, None))
             }
-            api::PaymentMethodData::Crypto(_) | api::PaymentMethodData::BankDebit(_) => {
+            api::PaymentMethodData::Crypto(_)
+            | api::PaymentMethodData::BankDebit(_)
+            | api::PaymentMethodData::MandatePayment => {
                 Err(errors::ConnectorError::NotSupported {
                     message: format!("{:?}", item.request.payment_method_data),
                     connector: "AuthorizeDotNet",
diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs
index 3ba9ae11ef1..fe46181684f 100644
--- a/crates/router/src/connector/stripe/transformers.rs
+++ b/crates/router/src/connector/stripe/transformers.rs
@@ -1864,11 +1864,14 @@ impl
                     bank_specific_data: bank_data,
                 }))
             }
-            api::PaymentMethodData::Crypto(_) => Err(errors::ConnectorError::NotSupported {
-                message: format!("{pm_type:?}"),
-                connector: "Stripe",
-                payment_experience: api_models::enums::PaymentExperience::RedirectToUrl.to_string(),
-            })?,
+            api::PaymentMethodData::MandatePayment | api::PaymentMethodData::Crypto(_) => {
+                Err(errors::ConnectorError::NotSupported {
+                    message: format!("{pm_type:?}"),
+                    connector: "Stripe",
+                    payment_experience: api_models::enums::PaymentExperience::RedirectToUrl
+                        .to_string(),
+                })?
+            }
         }
     }
 }
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index db71a3cca16..09ea96c77e0 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -722,6 +722,9 @@ where
     let connector = payment_data.payment_attempt.connector.to_owned();
 
     let payment_data_and_tokenization_action = match connector {
+        Some(_) if payment_data.mandate_id.is_some() => {
+            (payment_data, TokenizationAction::SkipConnectorTokenization)
+        }
         Some(connector) if is_operation_confirm(&operation) => {
             let payment_method = &payment_data
                 .payment_attempt
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index 365c804f07f..1f5775c0c0c 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -180,20 +180,25 @@ pub async fn get_token_for_recurring_mandate(
         .locker_id
         .to_owned()
         .get_required_value("locker_id")?;
-    let _ = cards::get_lookup_key_from_locker(state, &token, &payment_method, &locker_id).await?;
-
-    if let Some(payment_method_from_request) = req.payment_method {
-        let pm: storage_enums::PaymentMethod = payment_method_from_request.foreign_into();
-        if pm != payment_method.payment_method {
-            Err(report!(errors::ApiErrorResponse::PreconditionFailed {
-                message: "payment method in request does not match previously provided payment \
-                          method information"
-                    .into()
-            }))?
-        }
-    };
+    if let storage_models::enums::PaymentMethod::Card = payment_method.payment_method {
+        let _ =
+            cards::get_lookup_key_from_locker(state, &token, &payment_method, &locker_id).await?;
+        if let Some(payment_method_from_request) = req.payment_method {
+            let pm: storage_enums::PaymentMethod = payment_method_from_request.foreign_into();
+            if pm != payment_method.payment_method {
+                Err(report!(errors::ApiErrorResponse::PreconditionFailed {
+                    message:
+                        "payment method in request does not match previously provided payment \
+                                  method information"
+                            .into()
+                }))?
+            }
+        };
 
-    Ok((Some(token), Some(payment_method.payment_method)))
+        Ok((Some(token), Some(payment_method.payment_method)))
+    } else {
+        Ok((None, Some(payment_method.payment_method)))
+    }
 }
 
 #[instrument(skip_all)]
diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs
index ba8dcfd4748..2419854b54e 100644
--- a/crates/router/src/core/payments/transformers.rs
+++ b/crates/router/src/core/payments/transformers.rs
@@ -521,10 +521,16 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsAuthoriz
             payment_data.creds_identifier.as_deref(),
         ));
 
+        // payment_method_data is not required during recurring mandate payment, in such case keep default PaymentMethodData as MandatePayment
+        let payment_method_data = payment_data.payment_method_data.or_else(|| {
+            if payment_data.mandate_id.is_some() {
+                Some(api_models::payments::PaymentMethodData::MandatePayment)
+            } else {
+                None
+            }
+        });
         Ok(Self {
-            payment_method_data: payment_data
-                .payment_method_data
-                .get_required_value("payment_method_data")?,
+            payment_method_data: payment_method_data.get_required_value("payment_method_data")?,
             setup_future_usage: payment_data.payment_intent.setup_future_usage,
             mandate_id: payment_data.mandate_id.clone(),
             off_session: payment_data.mandate_id.as_ref().map(|_| true),

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

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

## Description
<!-- Describe your changes in detail -->
For Recurring mandate payments we don't need payment_method_data, currently we are storing all card_details in locker so payment_method_data can be built from card_details in locker for card_payment but in other_payment_methods(google_pay, apple_pay) it won't be possible, so we can ignore the payment_method_data in all recurring mandate payments.

### 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 its an obvious bug or documentation fix
that will have little conversation).
-->
Closes #1011 

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


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