Bug: [BUG] : store connector mandate id in complete auth



### Bug Description

Connector_reference in TransactionResponse of Complete auth call not saved in the DB

### Expected Behavior

Store the connector_reference, when it is sent in Complete auth call.

### Have you spent some time checking if this bug 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/crates/router/src/core/mandate.rs b/crates/router/src/core/mandate.rs
index e564e4a733e..d58eae371e8 100644
--- a/crates/router/src/core/mandate.rs
+++ b/crates/router/src/core/mandate.rs
@@ -1,7 +1,7 @@
 pub mod helpers;
 pub mod utils;
 use api_models::payments;
-use common_utils::{ext_traits::Encode, pii};
+use common_utils::ext_traits::Encode;
 use diesel_models::{enums as storage_enums, Mandate};
 use error_stack::{report, IntoReport, ResultExt};
 use futures::future;
@@ -24,7 +24,7 @@ use crate::{
             ConnectorData, GetToken,
         },
         domain, storage,
-        transformers::ForeignTryFrom,
+        transformers::ForeignFrom,
     },
     utils::OptionExt,
 };
@@ -154,25 +154,46 @@ pub async fn revoke_mandate(
 pub async fn update_connector_mandate_id(
     db: &dyn StorageInterface,
     merchant_account: String,
-    mandate_ids_opt: Option<api_models::payments::MandateIds>,
+    mandate_ids_opt: Option<String>,
+    payment_method_id: Option<String>,
     resp: Result<types::PaymentsResponseData, types::ErrorResponse>,
 ) -> RouterResponse<mandates::MandateResponse> {
-    let connector_mandate_id = Option::foreign_try_from(resp)?;
+    let mandate_details = Option::foreign_from(resp);
+    let connector_mandate_id = mandate_details
+        .clone()
+        .map(|md| {
+            Encode::<types::MandateReference>::encode_to_value(&md)
+                .change_context(errors::ApiErrorResponse::InternalServerError)
+                .map(masking::Secret::new)
+        })
+        .transpose()?;
+
     //Ignore updation if the payment_attempt mandate_id or connector_mandate_id is not present
-    if let Some((mandate_ids, connector_id)) = mandate_ids_opt.zip(connector_mandate_id) {
-        let mandate_id = &mandate_ids.mandate_id;
+    if let Some((mandate_id, connector_id)) = mandate_ids_opt.zip(connector_mandate_id) {
         let mandate = db
-            .find_mandate_by_merchant_id_mandate_id(&merchant_account, mandate_id)
+            .find_mandate_by_merchant_id_mandate_id(&merchant_account, &mandate_id)
             .await
             .change_context(errors::ApiErrorResponse::MandateNotFound)?;
+
+        let update_mandate_details = match payment_method_id {
+            Some(pmd_id) => storage::MandateUpdate::ConnectorMandateIdUpdate {
+                connector_mandate_id: mandate_details
+                    .and_then(|mandate_reference| mandate_reference.connector_mandate_id),
+                connector_mandate_ids: Some(connector_id),
+                payment_method_id: pmd_id,
+                original_payment_id: None,
+            },
+            None => storage::MandateUpdate::ConnectorReferenceUpdate {
+                connector_mandate_ids: Some(connector_id),
+            },
+        };
+
         // only update the connector_mandate_id if existing is none
         if mandate.connector_mandate_id.is_none() {
             db.update_mandate_by_merchant_id_mandate_id(
                 &merchant_account,
-                mandate_id,
-                storage::MandateUpdate::ConnectorReferenceUpdate {
-                    connector_mandate_ids: Some(connector_id),
-                },
+                &mandate_id,
+                update_mandate_details,
             )
             .await
             .change_context(errors::ApiErrorResponse::MandateUpdateFailed)?;
@@ -454,27 +475,16 @@ pub async fn retrieve_mandates_list(
     Ok(services::ApplicationResponse::Json(mandates_list))
 }
 
-impl ForeignTryFrom<Result<types::PaymentsResponseData, types::ErrorResponse>>
-    for Option<pii::SecretSerdeValue>
+impl ForeignFrom<Result<types::PaymentsResponseData, types::ErrorResponse>>
+    for Option<types::MandateReference>
 {
-    type Error = error_stack::Report<errors::ApiErrorResponse>;
-    fn foreign_try_from(
-        resp: Result<types::PaymentsResponseData, types::ErrorResponse>,
-    ) -> errors::RouterResult<Self> {
-        let mandate_details = match resp {
+    fn foreign_from(resp: Result<types::PaymentsResponseData, types::ErrorResponse>) -> Self {
+        match resp {
             Ok(types::PaymentsResponseData::TransactionResponse {
                 mandate_reference, ..
             }) => mandate_reference,
             _ => None,
-        };
-
-        mandate_details
-            .map(|md| {
-                Encode::<types::MandateReference>::encode_to_value(&md)
-                    .change_context(errors::ApiErrorResponse::MandateNotFound)
-                    .map(masking::Secret::new)
-            })
-            .transpose()
+        }
     }
 }
 
diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs
index e5552f0d156..0666c921422 100644
--- a/crates/router/src/core/payments/operations/payment_response.rs
+++ b/crates/router/src/core/payments/operations/payment_response.rs
@@ -819,17 +819,27 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
         .in_current_span(),
     );
 
-    // When connector requires redirection for mandate creation it can update the connector mandate_id during Psync
+    // When connector requires redirection for mandate creation it can update the connector mandate_id during Psync and CompleteAuthorize
     let m_db = state.clone().store;
+    let m_payment_method_id = payment_data.payment_attempt.payment_method_id.clone();
     let m_router_data_merchant_id = router_data.merchant_id.clone();
-    let m_payment_data_mandate_id = payment_data.mandate_id.clone();
+    let m_payment_data_mandate_id =
+        payment_data
+            .payment_attempt
+            .mandate_id
+            .clone()
+            .or(payment_data
+                .mandate_id
+                .clone()
+                .map(|mandate_ids| mandate_ids.mandate_id));
     let m_router_data_response = router_data.response.clone();
     let mandate_update_fut = tokio::spawn(
         async move {
             mandate::update_connector_mandate_id(
                 m_db.as_ref(),
-                m_router_data_merchant_id,
+                m_router_data_merchant_id.clone(),
                 m_payment_data_mandate_id,
+                m_payment_method_id,
                 m_router_data_response,
             )
             .await

## 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 -->
In this PR we store the connector_reference, when it is sent in Complete auth call. 


## Test Case
1. Make a 3ds mandate payment with Cybersource
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key:{{api_key}}' \
--data-raw '{
    "amount": 0,
    "currency": "PLN",
    "confirm": true,
    "business_country": "US",
    "business_label": "default",
    
    "capture_method": "automatic",
    "customer_id": "abc",
    "capture_on": "2022-09-10T10:11:12Z",
    "authentication_type": "three_ds",
    "return_url": "https://hs-payments-test.netlify.app/payments",
    "email": "sdh@xyz.in",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "statement_descriptor_name": "Juspay",
    "statement_descriptor_suffix": "Router",
    "setup_future_usage": "off_session",
    "payment_method": "card",
    "payment_method_type": "credit",
    "payment_type": "setup_mandate",
    "payment_method_data": {
        "card": {
            "card_number": "4622943127013705",
            "card_exp_month": "12",
            "card_exp_year": "2030",
            "card_holder_name": "joseph Doe",
            "card_cvc": "838"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "CA",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "New York",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "browser_info": {
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "language": "nl-NL",
        "color_depth": 24,
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "125.0.0.1"
    },
    "metadata": {
        "order_details": {
            "product_name": "Apple iphone 15",
            "quantity": 1,
            "amount": 3200,
            "account_name": "transaction_processing"
        }
    },
    "mandate_data": {
        "customer_acceptance": {
            "acceptance_type": "offline",
            "accepted_at": "1963-05-03T04:07:52.723Z",
            "online": {
                "ip_address": "13.232.74.226",
                "user_agent": "amet irure esse"
            }
        }
        , "mandate_type": {
            "multi_use": {
                "amount": 700,
                "currency": "USD"
            }
        }
        
    }
}'
```
<img width="1138" alt="Screenshot 2024-02-07 at 3 08 57 PM" src="https://github.com/juspay/hyperswitch/assets/131388445/f25a3624-f6e7-477f-8a1f-28c569a770b9">


mandate id should be stored in the mandate table
<img width="1380" alt="Screenshot 2024-02-07 at 3 09 18 PM" src="https://github.com/juspay/hyperswitch/assets/131388445/60033b46-11db-45e9-ad52-84729862b646">

DB Query
```
SELECT * FROM mandate WHERE mandate.original_payment_id = '{payment_id}';
```

## Flows Impacted
1. Normal payment
2. Setup mandate
3. Recurring mandate (both customer initiated and merchant initiated)
4. Flows where connector mandate reference is updated in the psync call or after redirection complete (Cybersource 3ds)

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