Bug: [BUG] Retrieve Payment Id Throwing 4xx 



### Bug Description

For MIT transaction, using non MIT payment method Ids, throwing 400. When retreive this payment, it is throwing 422. 

### Expected Behavior

https://api-reference.hyperswitch.io/api-reference/payments/payments--retrieve

### Actual Behavior

{
    "error": {
        "type": "invalid_request",
        "message": "no customer id provided for the payment",
        "code": "IR_23"
    }
}

### Steps To Reproduce

Provide an unambiguous set of steps to reproduce this bug. Include code or configuration to reproduce, if relevant.
1. Disable recurring from Adyen dashboard
2. Create a recurring payment in Adyen via hyperswitch
3. Hyperswitch sends a successful transaction and payment method id
4. Use the payment_method_id, to do MIT transaction. It fails, genuine fails
5. Try to retrieve the payment. It fails. this is the problem


### Context For The Bug

_No response_

### Environment

Are you using hyperswitch hosted version? Yes
If yes, please provide the value of the `x-request-id` response header to help us debug your issue.
`x-request-id : 01909742-36b7-7e91-9e62-6f684418fb1c`


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

None
diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index 97fc20d9444..d63ac8a030f 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -518,6 +518,139 @@ pub struct PaymentsRequest {
     pub merchant_order_reference_id: Option<String>,
 }
 
+/// Checks if the inner values of two options are equal
+/// Returns true if values are not equal, returns false in other cases
+fn are_optional_values_invalid<T: PartialEq>(
+    first_option: Option<&T>,
+    second_option: Option<&T>,
+) -> bool {
+    match (first_option, second_option) {
+        (Some(first_option), Some(second_option)) => first_option != second_option,
+        _ => false,
+    }
+}
+
+impl PaymentsRequest {
+    /// Get the customer id
+    ///
+    /// First check the id for `customer.id`
+    /// If not present, check for `customer_id` at the root level
+    pub fn get_customer_id(&self) -> Option<&id_type::CustomerId> {
+        self.customer_id
+            .as_ref()
+            .or(self.customer.as_ref().map(|customer| &customer.id))
+    }
+
+    /// Checks if the customer details are passed in both places
+    /// If they are passed in both places, check for both the values to be equal
+    /// Or else, return the field which has inconsistent data
+    pub fn validate_customer_details_in_request(&self) -> Option<Vec<&str>> {
+        if let Some(CustomerDetails {
+            id,
+            name,
+            email,
+            phone,
+            phone_country_code,
+        }) = self.customer.as_ref()
+        {
+            let invalid_fields = [
+                are_optional_values_invalid(self.customer_id.as_ref(), Some(id))
+                    .then_some("customer_id and customer.id"),
+                are_optional_values_invalid(self.email.as_ref(), email.as_ref())
+                    .then_some("email and customer.email"),
+                are_optional_values_invalid(self.name.as_ref(), name.as_ref())
+                    .then_some("name and customer.name"),
+                are_optional_values_invalid(self.phone.as_ref(), phone.as_ref())
+                    .then_some("phone and customer.phone"),
+                are_optional_values_invalid(
+                    self.phone_country_code.as_ref(),
+                    phone_country_code.as_ref(),
+                )
+                .then_some("phone_country_code and customer.phone_country_code"),
+            ]
+            .into_iter()
+            .flatten()
+            .collect::<Vec<_>>();
+
+            if invalid_fields.is_empty() {
+                None
+            } else {
+                Some(invalid_fields)
+            }
+        } else {
+            None
+        }
+    }
+}
+
+#[cfg(test)]
+mod payments_request_test {
+    use common_utils::generate_customer_id_of_default_length;
+
+    use super::*;
+
+    #[test]
+    fn test_valid_case_where_customer_details_are_passed_only_once() {
+        let customer_id = generate_customer_id_of_default_length();
+        let payments_request = PaymentsRequest {
+            customer_id: Some(customer_id),
+            ..Default::default()
+        };
+
+        assert!(payments_request
+            .validate_customer_details_in_request()
+            .is_none());
+    }
+
+    #[test]
+    fn test_valid_case_where_customer_id_is_passed_in_both_places() {
+        let customer_id = generate_customer_id_of_default_length();
+
+        let customer_object = CustomerDetails {
+            id: customer_id.clone(),
+            name: None,
+            email: None,
+            phone: None,
+            phone_country_code: None,
+        };
+
+        let payments_request = PaymentsRequest {
+            customer_id: Some(customer_id),
+            customer: Some(customer_object),
+            ..Default::default()
+        };
+
+        assert!(payments_request
+            .validate_customer_details_in_request()
+            .is_none());
+    }
+
+    #[test]
+    fn test_invalid_case_where_customer_id_is_passed_in_both_places() {
+        let customer_id = generate_customer_id_of_default_length();
+        let another_customer_id = generate_customer_id_of_default_length();
+
+        let customer_object = CustomerDetails {
+            id: customer_id.clone(),
+            name: None,
+            email: None,
+            phone: None,
+            phone_country_code: None,
+        };
+
+        let payments_request = PaymentsRequest {
+            customer_id: Some(another_customer_id),
+            customer: Some(customer_object),
+            ..Default::default()
+        };
+
+        assert_eq!(
+            payments_request.validate_customer_details_in_request(),
+            Some(vec!["customer_id and customer.id"])
+        );
+    }
+}
+
 /// Fee information to be charged on the payment being collected
 #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
 #[serde(rename_all = "snake_case")]
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index c19480f1d56..a19db991bf3 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -451,7 +451,7 @@ pub async fn get_token_pm_type_mandate_details(
     merchant_account: &domain::MerchantAccount,
     merchant_key_store: &domain::MerchantKeyStore,
     payment_method_id: Option<String>,
-    customer_id: &Option<id_type::CustomerId>,
+    payment_intent_customer_id: Option<&id_type::CustomerId>,
 ) -> RouterResult<MandateGenericData> {
     let mandate_data = request.mandate_data.clone().map(MandateData::foreign_from);
     let (
@@ -505,14 +505,15 @@ pub async fn get_token_pm_type_mandate_details(
                             .to_not_found_response(
                                 errors::ApiErrorResponse::PaymentMethodNotFound,
                             )?;
-                        let customer_id = get_customer_id_from_payment_request(request)
+                        let customer_id = request
+                            .get_customer_id()
                             .get_required_value("customer_id")?;
 
                         verify_mandate_details_for_recurring_payments(
                             &payment_method_info.merchant_id,
                             &merchant_account.merchant_id,
                             &payment_method_info.customer_id,
-                            &customer_id,
+                            customer_id,
                         )?;
 
                         (
@@ -552,10 +553,9 @@ pub async fn get_token_pm_type_mandate_details(
                         || request.payment_method_type
                             == Some(api_models::enums::PaymentMethodType::GooglePay)
                     {
-                        let payment_request_customer_id =
-                            get_customer_id_from_payment_request(request);
+                        let payment_request_customer_id = request.get_customer_id();
                         if let Some(customer_id) =
-                            &payment_request_customer_id.or(customer_id.clone())
+                            payment_request_customer_id.or(payment_intent_customer_id)
                         {
                             let customer_saved_pm_option = match state
                                 .store
@@ -711,10 +711,10 @@ pub async fn get_token_for_recurring_mandate(
         .map(|pi| pi.amount.get_amount_as_i64());
     let original_payment_authorized_currency =
         original_payment_intent.clone().and_then(|pi| pi.currency);
-    let customer = get_customer_id_from_payment_request(req).get_required_value("customer_id")?;
+    let customer = req.get_customer_id().get_required_value("customer_id")?;
 
     let payment_method_id = {
-        if mandate.customer_id != customer {
+        if &mandate.customer_id != customer {
             Err(report!(errors::ApiErrorResponse::PreconditionFailed {
                 message: "customer_id must match mandate customer_id".into()
             }))?
@@ -1453,25 +1453,6 @@ pub async fn get_customer_from_details<F: Clone>(
     }
 }
 
-// Checks if the inner values of two options are not equal and throws appropriate error
-fn validate_options_for_inequality<T: PartialEq>(
-    first_option: Option<&T>,
-    second_option: Option<&T>,
-    field_name: &str,
-) -> Result<(), errors::ApiErrorResponse> {
-    fp_utils::when(
-        first_option
-            .zip(second_option)
-            .map(|(value1, value2)| value1 != value2)
-            .unwrap_or(false),
-        || {
-            Err(errors::ApiErrorResponse::PreconditionFailed {
-                message: format!("The field name `{field_name}` sent in both places is ambiguous"),
-            })
-        },
-    )
-}
-
 pub fn validate_max_amount(
     amount: api_models::payments::Amount,
 ) -> CustomResult<(), errors::ApiErrorResponse> {
@@ -1490,44 +1471,21 @@ pub fn validate_max_amount(
     }
 }
 
-// Checks if the customer details are passed in both places
-// If so, raise an error
-pub fn validate_customer_details_in_request(
+/// Check whether the customer information that is sent in the root of payments request
+/// and in the customer object are same, if the values mismatch return an error
+pub fn validate_customer_information(
     request: &api_models::payments::PaymentsRequest,
-) -> Result<(), errors::ApiErrorResponse> {
-    if let Some(customer_details) = request.customer.as_ref() {
-        validate_options_for_inequality(
-            request.customer_id.as_ref(),
-            Some(&customer_details.id),
-            "customer_id",
-        )?;
-
-        validate_options_for_inequality(
-            request.email.as_ref(),
-            customer_details.email.as_ref(),
-            "email",
-        )?;
-
-        validate_options_for_inequality(
-            request.name.as_ref(),
-            customer_details.name.as_ref(),
-            "name",
-        )?;
-
-        validate_options_for_inequality(
-            request.phone.as_ref(),
-            customer_details.phone.as_ref(),
-            "phone",
-        )?;
-
-        validate_options_for_inequality(
-            request.phone_country_code.as_ref(),
-            customer_details.phone_country_code.as_ref(),
-            "phone_country_code",
-        )?;
+) -> RouterResult<()> {
+    if let Some(mismatched_fields) = request.validate_customer_details_in_request() {
+        let mismatched_fields = mismatched_fields.join(", ");
+        Err(errors::ApiErrorResponse::PreconditionFailed {
+            message: format!(
+                "The field names `{mismatched_fields}` sent in both places is ambiguous"
+            ),
+        })?
+    } else {
+        Ok(())
     }
-
-    Ok(())
 }
 
 /// Get the customer details from customer field if present
@@ -1536,12 +1494,7 @@ pub fn validate_customer_details_in_request(
 pub fn get_customer_details_from_request(
     request: &api_models::payments::PaymentsRequest,
 ) -> CustomerDetails {
-    let customer_id = request
-        .customer
-        .as_ref()
-        .map(|customer_details| &customer_details.id)
-        .or(request.customer_id.as_ref())
-        .map(ToOwned::to_owned);
+    let customer_id = request.get_customer_id().map(ToOwned::to_owned);
 
     let customer_name = request
         .customer
@@ -1576,16 +1529,6 @@ pub fn get_customer_details_from_request(
     }
 }
 
-fn get_customer_id_from_payment_request(
-    request: &api_models::payments::PaymentsRequest,
-) -> Option<id_type::CustomerId> {
-    request
-        .customer
-        .as_ref()
-        .map(|customer| customer.id.clone())
-        .or(request.customer_id.clone())
-}
-
 pub async fn get_connector_default(
     _state: &SessionState,
     request_connector: Option<serde_json::Value>,
@@ -4079,8 +4022,8 @@ pub fn validate_customer_access(
     auth_flow: services::AuthFlow,
     request: &api::PaymentsRequest,
 ) -> Result<(), errors::ApiErrorResponse> {
-    if auth_flow == services::AuthFlow::Client && request.customer_id.is_some() {
-        let is_same_customer = request.customer_id == payment_intent.customer_id;
+    if auth_flow == services::AuthFlow::Client && request.get_customer_id().is_some() {
+        let is_same_customer = request.get_customer_id() == payment_intent.customer_id.as_ref();
         if !is_same_customer {
             Err(errors::ApiErrorResponse::GenericUnauthorized {
                 message: "Unauthorised access to update customer".to_string(),
diff --git a/crates/router/src/core/payments/operations/payment_complete_authorize.rs b/crates/router/src/core/payments/operations/payment_complete_authorize.rs
index 060acf51549..9c48df1dd53 100644
--- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs
+++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs
@@ -126,7 +126,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Co
             merchant_account,
             key_store,
             payment_attempt.payment_method_id.clone(),
-            &payment_intent.customer_id,
+            payment_intent.customer_id.as_ref(),
         )
         .await?;
         let customer_acceptance: Option<CustomerAcceptance> = request
@@ -188,12 +188,15 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Co
         currency = payment_attempt.currency.get_required_value("currency")?;
         amount = payment_attempt.get_total_amount().into();
 
+        let customer_id = payment_intent
+            .customer_id
+            .as_ref()
+            .or(request.get_customer_id())
+            .cloned();
+
         helpers::validate_customer_id_mandatory_cases(
             request.setup_future_usage.is_some(),
-            payment_intent
-                .customer_id
-                .as_ref()
-                .or(request.customer_id.as_ref()),
+            customer_id.as_ref(),
         )?;
 
         let shipping_address = helpers::create_or_update_address_for_payment_by_request(
@@ -337,7 +340,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Co
         };
 
         let customer_details = Some(CustomerDetails {
-            customer_id: request.customer_id.clone(),
+            customer_id,
             name: request.name.clone(),
             email: request.email.clone(),
             phone: request.phone.clone(),
diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs
index 9fe28c38106..771ee137474 100644
--- a/crates/router/src/core/payments/operations/payment_confirm.rs
+++ b/crates/router/src/core/payments/operations/payment_confirm.rs
@@ -508,7 +508,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
                     &m_merchant_account,
                     &m_key_store,
                     None,
-                    &payment_intent_customer_id,
+                    payment_intent_customer_id.as_ref(),
                 )
                 .await
             }
@@ -1353,7 +1353,8 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentConfir
         BoxedOperation<'b, F, api::PaymentsRequest>,
         operations::ValidateResult<'a>,
     )> {
-        helpers::validate_customer_details_in_request(request)?;
+        helpers::validate_customer_information(request)?;
+
         if let Some(amount) = request.amount {
             helpers::validate_max_amount(amount)?;
         }
diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs
index 4204972411a..4e0bbec9f17 100644
--- a/crates/router/src/core/payments/operations/payment_create.rs
+++ b/crates/router/src/core/payments/operations/payment_create.rs
@@ -136,7 +136,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
             merchant_account,
             merchant_key_store,
             None,
-            &request.customer_id,
+            None,
         )
         .await?;
 
@@ -684,7 +684,8 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentCreate
         BoxedOperation<'b, F, api::PaymentsRequest>,
         operations::ValidateResult<'a>,
     )> {
-        helpers::validate_customer_details_in_request(request)?;
+        helpers::validate_customer_information(request)?;
+
         if let Some(amount) = request.amount {
             helpers::validate_max_amount(amount)?;
         }
@@ -749,11 +750,7 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentCreate
 
             helpers::validate_customer_id_mandatory_cases(
                 request.setup_future_usage.is_some(),
-                request
-                    .customer
-                    .as_ref()
-                    .map(|customer| &customer.id)
-                    .or(request.customer_id.as_ref()),
+                request.get_customer_id(),
             )?;
         }
 
@@ -1066,7 +1063,7 @@ impl PaymentCreate {
             .await;
 
         // Derivation of directly supplied Customer data in our Payment Create Request
-        let raw_customer_details = if request.customer_id.is_none()
+        let raw_customer_details = if request.get_customer_id().is_none()
             && (request.name.is_some()
                 || request.email.is_some()
                 || request.phone.is_some()
@@ -1115,7 +1112,7 @@ impl PaymentCreate {
             ),
             order_details,
             amount_captured: None,
-            customer_id: None,
+            customer_id: request.get_customer_id().cloned(),
             connector_id: None,
             allowed_payment_method_types,
             connector_metadata,
@@ -1149,10 +1146,10 @@ impl PaymentCreate {
         state: &SessionState,
         merchant_account: &domain::MerchantAccount,
     ) -> Option<ephemeral_key::EphemeralKey> {
-        match request.customer_id.clone() {
+        match request.get_customer_id() {
             Some(customer_id) => helpers::make_ephemeral_key(
                 state.clone(),
-                customer_id,
+                customer_id.clone(),
                 merchant_account.merchant_id.clone(),
             )
             .await
diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs
index 0bccd409cac..8af5a86d7c3 100644
--- a/crates/router/src/core/payments/operations/payment_update.rs
+++ b/crates/router/src/core/payments/operations/payment_update.rs
@@ -151,7 +151,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
             merchant_account,
             key_store,
             None,
-            &payment_intent.customer_id,
+            payment_intent.customer_id.as_ref(),
         )
         .await?;
         helpers::validate_amount_to_capture_and_capture_method(Some(&payment_attempt), request)?;
@@ -807,7 +807,8 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentUpdate
         BoxedOperation<'b, F, api::PaymentsRequest>,
         operations::ValidateResult<'a>,
     )> {
-        helpers::validate_customer_details_in_request(request)?;
+        helpers::validate_customer_information(request)?;
+
         if let Some(amount) = request.amount {
             helpers::validate_max_amount(amount)?;
         }

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

- [x] Bugfix

## Description
<!-- Describe your changes in detail -->
In case we receive a 4xx when creating the payment before calling the connector, we do not save the `customer_id` in payment intent. This PR fixes it

This PR also includes changes to ensure that `customer_id` is always taken from both the places in the PaymentsRequest. The root `customer_id` and `customer.id` field.


<!--
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)?
-->
- Create a merchant account
```bash
curl --location 'http://localhost:8080/accounts' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: test_admin' \
--data '{
    "merchant_id": "merchant_1720593206"
}'
```

- Create an api key
```bash
curl --location 'http://localhost:8080/api_keys/merchant_1720593134' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: test_admin' \
--data '{
  "name": "API Key 1",
  "description": null,
  "expiration": "2038-01-19T03:14:08.000Z"
}'
```

- Create a payment
```bash
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_RMV9h1z6QVqWHW9B7LBRl6peSokwQ7go96pfAjehuGZDGiwlenKAbgtyqUlXny9J' \
--data '{
    "amount": 0,
    "payment_id": "pay_1720593248",
    "customer_id": "cus_123",
    "currency": "USD",
    "confirm": true,
    "payment_type": "setup_mandate",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "card_number": "4111111111111111",
            "card_exp_month": "10",
            "card_exp_year": "25",
            "card_holder_name": "joseph Doe",
            "card_cvc": "123"
        }
    }
}'
```
Fails with the error message
```json
{
    "error": {
        "type": "invalid_request",
        "message": "No eligible connector was found for the current payment method configuration",
        "code": "HE_04"
    }
}
```

- Check in the database whether `customer_id` is updated
<img width="1014" alt="image" src="https://github.com/juspay/hyperswitch/assets/48803246/a83fce74-2aa9-4670-b074-d1ea77bb3e14">


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