Bug: refactor(payment_methods): update connector_mandate_details for card metadata changes 



Allow update of connector_mandate_details for card in case of metadata changes(in case of expiry changes). First the value is set as inactive and if a successful payment has been made then set it back to active
diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs
index 01a4e086091..e7101742676 100644
--- a/crates/router/src/core/payments/operations/payment_response.rs
+++ b/crates/router/src/core/payments/operations/payment_response.rs
@@ -200,6 +200,7 @@ impl<F: Send + Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsAuthor
             payment_method_billing_address,
             business_profile,
             connector_mandate_reference_id.clone(),
+            merchant_connector_id.clone(),
         ));
 
         let is_connector_mandate = resp.request.customer_acceptance.is_some()
@@ -315,6 +316,7 @@ impl<F: Send + Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsAuthor
                         payment_method_billing_address.as_ref(),
                         &business_profile,
                         connector_mandate_reference_id,
+                        merchant_connector_id.clone(),
                     ))
                     .await;
 
@@ -1099,6 +1101,7 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::SetupMandateRequestDa
             payment_method_billing_address,
             business_profile,
             connector_mandate_reference_id,
+            merchant_connector_id.clone(),
         ))
         .await?;
 
diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs
index 89fb7752d1b..5f8d5fd8798 100644
--- a/crates/router/src/core/payments/tokenization.rs
+++ b/crates/router/src/core/payments/tokenization.rs
@@ -83,6 +83,7 @@ pub async fn save_payment_method<FData>(
     payment_method_billing_address: Option<&hyperswitch_domain_models::address::Address>,
     business_profile: &domain::Profile,
     mut original_connector_mandate_reference_id: Option<ConnectorMandateReferenceId>,
+    merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
 ) -> RouterResult<SavePaymentMethodDataResponse>
 where
     FData: mandate::MandateBehaviour + Clone,
@@ -458,7 +459,41 @@ where
                                 resp.payment_method_id = payment_method_id;
 
                                 let existing_pm = match payment_method {
-                                    Ok(pm) => Ok(pm),
+                                    Ok(pm) => {
+                                        let mandate_details =    pm
+                                        .connector_mandate_details
+                                        .clone()
+                                        .map(|val| {
+                                            val.parse_value::<diesel_models::PaymentsMandateReference>(
+                                                "PaymentsMandateReference",
+                                            )
+                                        })
+                                        .transpose()
+                                        .change_context(errors::ApiErrorResponse::InternalServerError)
+                                        .attach_printable("Failed to deserialize to Payment Mandate Reference ")?;
+                                        if let Some((mandate_details, merchant_connector_id)) =
+                                            mandate_details.zip(merchant_connector_id)
+                                        {
+                                            let connector_mandate_details =
+                                                update_connector_mandate_details_status(
+                                                    merchant_connector_id,
+                                                    mandate_details,
+                                                    ConnectorMandateStatus::Inactive,
+                                                )?;
+                                            payment_methods::cards::update_payment_method_connector_mandate_details(
+                                            state,
+                                            key_store,
+                                            db,
+                                            pm.clone(),
+                                            connector_mandate_details,
+                                            merchant_account.storage_scheme,
+                                        )
+                                        .await
+                                        .change_context(errors::ApiErrorResponse::InternalServerError)
+                                        .attach_printable("Failed to add payment method in db")?;
+                                        }
+                                        Ok(pm)
+                                    }
                                     Err(err) => {
                                         if err.current_context().is_db_not_found() {
                                             payment_methods::cards::create_payment_method(
@@ -1252,3 +1287,37 @@ pub fn update_connector_mandate_details(
 
     Ok(connector_mandate_details)
 }
+
+#[cfg(feature = "v1")]
+pub fn update_connector_mandate_details_status(
+    merchant_connector_id: id_type::MerchantConnectorAccountId,
+    mut payment_mandate_reference: diesel_models::PaymentsMandateReference,
+    status: ConnectorMandateStatus,
+) -> RouterResult<Option<serde_json::Value>> {
+    let mandate_reference = {
+        payment_mandate_reference
+            .entry(merchant_connector_id)
+            .and_modify(|pm| {
+                let update_rec = diesel_models::PaymentsMandateReferenceRecord {
+                    connector_mandate_id: pm.connector_mandate_id.clone(),
+                    payment_method_type: pm.payment_method_type,
+                    original_payment_authorized_amount: pm.original_payment_authorized_amount,
+                    original_payment_authorized_currency: pm.original_payment_authorized_currency,
+                    mandate_metadata: pm.mandate_metadata.clone(),
+                    connector_mandate_status: Some(status),
+                    connector_mandate_request_reference_id: pm
+                        .connector_mandate_request_reference_id
+                        .clone(),
+                };
+                *pm = update_rec
+            });
+        Some(payment_mandate_reference)
+    };
+    let connector_mandate_details = mandate_reference
+        .map(|mandate| mandate.encode_to_value())
+        .transpose()
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Unable to serialize customer acceptance to value")?;
+
+    Ok(connector_mandate_details)
+}

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

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

## Description
Allow update of `connector_mandate_details` for card in case of metadata changes(in case of expiry changes). First the  value is set as inactive and if a successful payment has been made then set it back to active

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

> - Create a MA and a MCA
> - Make a off_Session save card payment
> - Make a off_Session payment again with the same card just and changes expiry 
> - After a successful payment the Connector Mandate Details would be overriden
<img width="1725" alt="Screenshot 2024-12-16 at 4 21 51 PM" src="https://github.com/user-attachments/assets/2c68dc5e-f27c-400d-9b16-3080029ccfb3" />

- Follow the same step for 3threeds
> - Create a MA and a MCA
> - Make a off_Session save card payment
> - Make a off_Session payment again with the same card just and changed expiry 
> -Before a successful redirection ( the connector mandate is inactive)
<img width="1725" alt="Screenshot 2024-12-16 at 4 23 50 PM" src="https://github.com/user-attachments/assets/69c74c67-f596-447e-baac-ea5191b3a7f0" />

> - After a successful redirection ( the connector mandate is active)
<img width="1725" alt="Screenshot 2024-12-16 at 4 24 24 PM" src="https://github.com/user-attachments/assets/b141a8b1-2d91-4f68-b478-928d4f6149f2" />

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

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