Bug: Make `original_payment_authorized_currency` and `original_payment_authorized_amount` mandatory fields for `Discover` cards and `Cybersource` connector during payment method migration.



Make original_payment_authorized_currency and original_payment_authorized_amount mandatory fields for Discover cards and Cybersource connector during payment method migration.
diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs
index 7799cc24df2..1ca01114dd5 100644
--- a/crates/api_models/src/payment_methods.rs
+++ b/crates/api_models/src/payment_methods.rs
@@ -1428,12 +1428,8 @@ impl From<PaymentMethodRecord> for PaymentMethodMigrate {
             PaymentsMandateReferenceRecord {
                 connector_mandate_id: record.payment_instrument_id.peek().to_string(),
                 payment_method_type: record.payment_method_type,
-                original_payment_authorized_amount: record
-                    .original_transaction_amount
-                    .or(Some(1000)),
-                original_payment_authorized_currency: record
-                    .original_transaction_currency
-                    .or(Some(common_enums::Currency::USD)),
+                original_payment_authorized_amount: record.original_transaction_amount,
+                original_payment_authorized_currency: record.original_transaction_currency,
             },
         );
         Self {
diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs
index 0a3007b572c..5f5e59a89a5 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -278,17 +278,30 @@ pub async fn migrate_payment_method(
     merchant_account: &domain::MerchantAccount,
     key_store: &domain::MerchantKeyStore,
 ) -> errors::RouterResponse<api::PaymentMethodResponse> {
+    let mut req = req;
     let card_details = req.card.as_ref().get_required_value("card")?;
 
     let card_number_validation_result =
         cards::CardNumber::from_str(card_details.card_number.peek());
 
+    let card_bin_details =
+        populate_bin_details_for_masked_card(card_details, &*state.store).await?;
+
+    req.card = Some(api_models::payment_methods::MigrateCardDetail {
+        card_issuing_country: card_bin_details.issuer_country.clone(),
+        card_network: card_bin_details.card_network.clone(),
+        card_issuer: card_bin_details.card_issuer.clone(),
+        card_type: card_bin_details.card_type.clone(),
+        ..card_details.clone()
+    });
+
     if let Some(connector_mandate_details) = &req.connector_mandate_details {
         helpers::validate_merchant_connector_ids_in_connector_mandate_details(
             &state,
             key_store,
             connector_mandate_details,
             merchant_id,
+            card_bin_details.card_network.clone(),
         )
         .await?;
     };
@@ -316,18 +329,130 @@ pub async fn migrate_payment_method(
                 merchant_id.into(),
                 key_store,
                 merchant_account,
+                card_bin_details.clone(),
             )
             .await
         }
     }
 }
 
+pub async fn populate_bin_details_for_masked_card(
+    card_details: &api_models::payment_methods::MigrateCardDetail,
+    db: &dyn db::StorageInterface,
+) -> errors::CustomResult<api::CardDetailFromLocker, errors::ApiErrorResponse> {
+    helpers::validate_card_expiry(&card_details.card_exp_month, &card_details.card_exp_year)?;
+    let card_number = card_details.card_number.clone();
+
+    let (card_isin, _last4_digits) = get_card_bin_and_last4_digits_for_masked_card(
+        card_number.peek(),
+    )
+    .change_context(errors::ApiErrorResponse::InvalidRequestData {
+        message: "Invalid card number".to_string(),
+    })?;
+
+    let card_bin_details = if card_details.card_issuer.is_some()
+        && card_details.card_network.is_some()
+        && card_details.card_type.is_some()
+        && card_details.card_issuing_country.is_some()
+    {
+        api_models::payment_methods::CardDetailFromLocker::foreign_try_from((card_details, None))?
+    } else {
+        let card_info = db
+            .get_card_info(&card_isin)
+            .await
+            .map_err(|error| services::logger::error!(card_info_error=?error))
+            .ok()
+            .flatten();
+
+        api_models::payment_methods::CardDetailFromLocker::foreign_try_from((
+            card_details,
+            card_info,
+        ))?
+    };
+    Ok(card_bin_details)
+}
+
+impl
+    ForeignTryFrom<(
+        &api_models::payment_methods::MigrateCardDetail,
+        Option<diesel_models::CardInfo>,
+    )> for api_models::payment_methods::CardDetailFromLocker
+{
+    type Error = error_stack::Report<errors::ApiErrorResponse>;
+    fn foreign_try_from(
+        (card_details, card_info): (
+            &api_models::payment_methods::MigrateCardDetail,
+            Option<diesel_models::CardInfo>,
+        ),
+    ) -> Result<Self, Self::Error> {
+        let (card_isin, last4_digits) =
+            get_card_bin_and_last4_digits_for_masked_card(card_details.card_number.peek())
+                .change_context(errors::ApiErrorResponse::InvalidRequestData {
+                    message: "Invalid card number".to_string(),
+                })?;
+        if let Some(card_bin_info) = card_info {
+            Ok(Self {
+                scheme: card_details
+                    .card_network
+                    .clone()
+                    .or(card_bin_info.card_network.clone())
+                    .map(|card_network| card_network.to_string()),
+                last4_digits: Some(last4_digits.clone()),
+                issuer_country: card_details
+                    .card_issuing_country
+                    .clone()
+                    .or(card_bin_info.card_issuing_country),
+                card_number: None,
+                expiry_month: Some(card_details.card_exp_month.clone()),
+                expiry_year: Some(card_details.card_exp_year.clone()),
+                card_token: None,
+                card_fingerprint: None,
+                card_holder_name: card_details.card_holder_name.clone(),
+                nick_name: card_details.nick_name.clone(),
+                card_isin: Some(card_isin.clone()),
+                card_issuer: card_details
+                    .card_issuer
+                    .clone()
+                    .or(card_bin_info.card_issuer),
+                card_network: card_details
+                    .card_network
+                    .clone()
+                    .or(card_bin_info.card_network),
+                card_type: card_details.card_type.clone().or(card_bin_info.card_type),
+                saved_to_locker: false,
+            })
+        } else {
+            Ok(Self {
+                scheme: card_details
+                    .card_network
+                    .clone()
+                    .map(|card_network| card_network.to_string()),
+                last4_digits: Some(last4_digits.clone()),
+                issuer_country: card_details.card_issuing_country.clone(),
+                card_number: None,
+                expiry_month: Some(card_details.card_exp_month.clone()),
+                expiry_year: Some(card_details.card_exp_year.clone()),
+                card_token: None,
+                card_fingerprint: None,
+                card_holder_name: card_details.card_holder_name.clone(),
+                nick_name: card_details.nick_name.clone(),
+                card_isin: Some(card_isin.clone()),
+                card_issuer: card_details.card_issuer.clone(),
+                card_network: card_details.card_network.clone(),
+                card_type: card_details.card_type.clone(),
+                saved_to_locker: false,
+            })
+        }
+    }
+}
+
 pub async fn skip_locker_call_and_migrate_payment_method(
     state: routes::SessionState,
     req: &api::PaymentMethodMigrate,
     merchant_id: String,
     key_store: &domain::MerchantKeyStore,
     merchant_account: &domain::MerchantAccount,
+    card: api_models::payment_methods::CardDetailFromLocker,
 ) -> errors::RouterResponse<api::PaymentMethodResponse> {
     let db = &*state.store;
     let customer_id = req.customer_id.clone().get_required_value("customer_id")?;
@@ -362,132 +487,15 @@ pub async fn skip_locker_call_and_migrate_payment_method(
         .await
         .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)?;
 
-    let card = if let Some(card_details) = &req.card {
-        helpers::validate_card_expiry(&card_details.card_exp_month, &card_details.card_exp_year)?;
-        let card_number = card_details.card_number.clone();
-
-        let (card_isin, last4_digits) = get_card_bin_and_last4_digits_for_masked_card(
-            card_number.peek(),
-        )
-        .change_context(errors::ApiErrorResponse::InvalidRequestData {
-            message: "Invalid card number".to_string(),
-        })?;
-
-        if card_details.card_issuer.is_some()
-            && card_details.card_network.is_some()
-            && card_details.card_type.is_some()
-            && card_details.card_issuing_country.is_some()
-        {
-            Some(api::CardDetailFromLocker {
-                scheme: card_details
-                    .card_network
-                    .clone()
-                    .or(card_details.card_network.clone())
-                    .map(|card_network| card_network.to_string()),
-                last4_digits: Some(last4_digits.clone()),
-                issuer_country: card_details
-                    .card_issuing_country
-                    .clone()
-                    .or(card_details.card_issuing_country.clone()),
-                card_number: None,
-                expiry_month: Some(card_details.card_exp_month.clone()),
-                expiry_year: Some(card_details.card_exp_year.clone()),
-                card_token: None,
-                card_fingerprint: None,
-                card_holder_name: card_details.card_holder_name.clone(),
-                nick_name: card_details.nick_name.clone(),
-                card_isin: Some(card_isin.clone()),
-                card_issuer: card_details
-                    .card_issuer
-                    .clone()
-                    .or(card_details.card_issuer.clone()),
-                card_network: card_details
-                    .card_network
-                    .clone()
-                    .or(card_details.card_network.clone()),
-                card_type: card_details
-                    .card_type
-                    .clone()
-                    .or(card_details.card_type.clone()),
-                saved_to_locker: false,
-            })
-        } else {
-            Some(
-                db.get_card_info(&card_isin)
-                    .await
-                    .map_err(|error| services::logger::error!(card_info_error=?error))
-                    .ok()
-                    .flatten()
-                    .map(|card_info| {
-                        logger::debug!("Fetching bin details");
-                        api::CardDetailFromLocker {
-                            scheme: card_details
-                                .card_network
-                                .clone()
-                                .or(card_info.card_network.clone())
-                                .map(|card_network| card_network.to_string()),
-                            last4_digits: Some(last4_digits.clone()),
-                            issuer_country: card_details
-                                .card_issuing_country
-                                .clone()
-                                .or(card_info.card_issuing_country),
-                            card_number: None,
-                            expiry_month: Some(card_details.card_exp_month.clone()),
-                            expiry_year: Some(card_details.card_exp_year.clone()),
-                            card_token: None,
-                            card_fingerprint: None,
-                            card_holder_name: card_details.card_holder_name.clone(),
-                            nick_name: card_details.nick_name.clone(),
-                            card_isin: Some(card_isin.clone()),
-                            card_issuer: card_details.card_issuer.clone().or(card_info.card_issuer),
-                            card_network: card_details
-                                .card_network
-                                .clone()
-                                .or(card_info.card_network),
-                            card_type: card_details.card_type.clone().or(card_info.card_type),
-                            saved_to_locker: false,
-                        }
-                    })
-                    .unwrap_or_else(|| {
-                        logger::debug!("Failed to fetch bin details");
-                        api::CardDetailFromLocker {
-                            scheme: card_details
-                                .card_network
-                                .clone()
-                                .map(|card_network| card_network.to_string()),
-                            last4_digits: Some(last4_digits.clone()),
-                            issuer_country: card_details.card_issuing_country.clone(),
-                            card_number: None,
-                            expiry_month: Some(card_details.card_exp_month.clone()),
-                            expiry_year: Some(card_details.card_exp_year.clone()),
-                            card_token: None,
-                            card_fingerprint: None,
-                            card_holder_name: card_details.card_holder_name.clone(),
-                            nick_name: card_details.nick_name.clone(),
-                            card_isin: Some(card_isin.clone()),
-                            card_issuer: card_details.card_issuer.clone(),
-                            card_network: card_details.card_network.clone(),
-                            card_type: card_details.card_type.clone(),
-                            saved_to_locker: false,
-                        }
-                    }),
-            )
-        }
-    } else {
-        None
-    };
-
-    let payment_method_card_details = card
-        .as_ref()
-        .map(|card| PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone())));
+    let payment_method_card_details =
+        PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone()));
 
-    let payment_method_data_encrypted: Option<Encryptable<Secret<serde_json::Value>>> =
-        payment_method_card_details
-            .async_map(|card_details| create_encrypted_data(&state, key_store, card_details))
+    let payment_method_data_encrypted: Option<Encryptable<Secret<serde_json::Value>>> = Some(
+        create_encrypted_data(&state, key_store, payment_method_card_details)
             .await
-            .transpose()
             .change_context(errors::ApiErrorResponse::InternalServerError)
-            .attach_printable("Unable to encrypt Payment method card details")?;
+            .attach_printable("Unable to encrypt Payment method card details")?,
+    );
 
     let payment_method_metadata: Option<serde_json::Value> =
         req.metadata.as_ref().map(|data| data.peek()).cloned();
@@ -506,10 +514,7 @@ pub async fn skip_locker_call_and_migrate_payment_method(
                 payment_method: req.payment_method,
                 payment_method_type: req.payment_method_type,
                 payment_method_issuer: req.payment_method_issuer.clone(),
-                scheme: req
-                    .card_network
-                    .clone()
-                    .or(card.clone().and_then(|card| card.scheme.clone())),
+                scheme: req.card_network.clone().or(card.scheme.clone()),
                 metadata: payment_method_metadata.map(Secret::new),
                 payment_method_data: payment_method_data_encrypted.map(Into::into),
                 connector_mandate_details: Some(connector_mandate_details),
@@ -554,7 +559,7 @@ pub async fn skip_locker_call_and_migrate_payment_method(
         .map_err(|error| logger::error!(?error, "Failed to set the payment method as default"));
     }
     Ok(services::api::ApplicationResponse::Json(
-        api::PaymentMethodResponse::foreign_from((card, response)),
+        api::PaymentMethodResponse::foreign_from((Some(card), response)),
     ))
 }
 
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index ecf8ff0c40d..aa630ad9835 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -5085,6 +5085,7 @@ pub async fn validate_merchant_connector_ids_in_connector_mandate_details(
     key_store: &domain::MerchantKeyStore,
     connector_mandate_details: &api_models::payment_methods::PaymentsMandateReference,
     merchant_id: &str,
+    card_network: Option<api_enums::CardNetwork>,
 ) -> CustomResult<(), errors::ApiErrorResponse> {
     let db = &*state.store;
     let merchant_connector_account_list = db
@@ -5097,20 +5098,49 @@ pub async fn validate_merchant_connector_ids_in_connector_mandate_details(
         .await
         .to_not_found_response(errors::ApiErrorResponse::InternalServerError)?;
 
-    let merchant_connector_ids: Vec<String> = merchant_connector_account_list
+    let merchant_connector_account_details_hash_map: std::collections::HashMap<
+        String,
+        domain::MerchantConnectorAccount,
+    > = merchant_connector_account_list
         .iter()
-        .map(|merchant_connector_account| merchant_connector_account.merchant_connector_id.clone())
+        .map(|merchant_connector_account| {
+            (
+                merchant_connector_account.merchant_connector_id.clone(),
+                merchant_connector_account.clone(),
+            )
+        })
         .collect();
 
-    for merchant_connector_id in connector_mandate_details.0.keys() {
-        if !merchant_connector_ids.contains(merchant_connector_id) {
-            Err(errors::ApiErrorResponse::InvalidDataValue {
-                field_name: "merchant_connector_id",
-            })
-            .attach_printable_lazy(|| {
-                format!("{merchant_connector_id} invalid merchant connector id in connector_mandate_details")
-            })?
-        }
+    for (migrating_merchant_connector_id, migrating_connector_mandate_details) in
+        connector_mandate_details.0.clone()
+    {
+        match (card_network.clone() ,merchant_connector_account_details_hash_map.get(&migrating_merchant_connector_id)) {
+                        (Some(enums::CardNetwork::Discover),Some(merchant_connector_account_details)) => if let ("cybersource", None) = (
+                          merchant_connector_account_details.connector_name.as_str(),
+                        migrating_connector_mandate_details
+                            .original_payment_authorized_amount
+                            .zip(
+                                migrating_connector_mandate_details
+                                  .original_payment_authorized_currency,
+                             ),
+                      ) {
+                        Err(errors::ApiErrorResponse::MissingRequiredFields {
+                              field_names: vec![
+                                 "original_payment_authorized_currency",
+                                  "original_payment_authorized_amount",
+                          ],
+                         }).attach_printable(format!("Invalid connector_mandate_details provided for connector {migrating_merchant_connector_id}"))?
+                    },
+                    (_, Some(_)) => (),
+                        (_, None) => {
+                            Err(errors::ApiErrorResponse::InvalidDataValue {
+                                field_name: "merchant_connector_id",
+                            })
+                            .attach_printable_lazy(|| {
+                                format!("{migrating_merchant_connector_id} invalid merchant connector id in connector_mandate_details")
+                            })?
+                        },
+                    }
     }
     Ok(())
 }

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

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

## Description
<!-- Describe your changes in detail -->
Make `original_payment_authorized_currency` and `original_payment_authorized_amount` mandatory fields for Discover cards and `Cybersource` connector during payment method migration. 

### 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?
<!--
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 connector account for cybersource
-> Create a customer
```
curl --location 'http://localhost:8080/customers' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_1oC3ReWVy4AaGA8ORA6EMm8JHS5WTlsmBtfRnNp2LLemMxZEJXfZ9hLYsd9wmWtg' \
--data-raw '{
    "customer_id": "cu_1721377355",
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "First customer",
    "address": {
        "line1": "1467",
        "line2": "Harrison Street",
        "line3": "Harrison Street",
        "city": "San Fransico",
        "state": "California",
        "zip": "94122",
        "country": "US",
        "first_name": "John",
        "last_name": "Doe"
    },
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    }
}'
```
```
{
    "customer_id": "cu_1721377384",
    "name": "John Doe",
    "email": "guest@example.com",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "First customer",
    "address": {
        "city": "San Fransico",
        "country": "US",
        "line1": "1467",
        "line2": "Harrison Street",
        "line3": "Harrison Street",
        "zip": "94122",
        "state": "California",
        "first_name": "John",
        "last_name": "Doe"
    },
    "created_at": "2024-07-19T08:23:04.632Z",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    },
    "default_payment_method_id": null
}
```
-> Migrate the payment method without the `original_payment_authorized_amount` and `original_payment_authorized_currency` for `discover` card
```
curl --location 'http://localhost:8080/payment_methods/migrate' \
--header 'api-key: test_admin' \
--header 'Content-Type: application/json' \
--data '{
    "payment_method": "card",
    "merchant_id": "merchant_1721375416",
    "card": {
        "card_number": "6011111111111117",
        "card_exp_month": "10",
        "card_exp_year": "33",
        "nick_name": "Joh"
    },
    "customer_id": "cu_1721375441",
    "connector_mandate_details": {
        "mca_k9zWJaOP2XzQbygmkerU": {
            "connector_mandate_id": "juaghfija"
        }
    }
}
'
```
```
{
    "error": {
        "type": "invalid_request",
        "message": "Missing required params",
        "code": "IR_21",
        "data": [
            "original_payment_authorized_currency",
            "original_payment_authorized_amount"
        ]
    }
}
```
-> With the `original_payment_authorized_amount` and `original_payment_authorized_currency` for `discover` card
```
curl --location 'http://localhost:8080/payment_methods/migrate' \
--header 'api-key: test_admin' \
--header 'Content-Type: application/json' \
--data '{
    "payment_method": "card",
    "merchant_id": "merchant_1721375416",
    "card": {
        "card_number": "601111xxxxxx1117",
        "card_exp_month": "10",
        "card_exp_year": "33",
        "nick_name": "Joh"
    },
    "customer_id": "cu_1721375441",
    "connector_mandate_details": {
        "mca_k9zWJaOP2XzQbygmkerU": {
            "connector_mandate_id": "khaifhq",
            "original_payment_authorized_amount": 6560,
            "original_payment_authorized_currency": "USD"
        }
    }
}
'
```
-> without the `original_payment_authorized_amount` and `original_payment_authorized_currency` for `visa`
```
curl --location 'http://localhost:8080/payment_methods/migrate' \
--header 'api-key: test_admin' \
--header 'Content-Type: application/json' \
--data '{
    "payment_method": "card",
    "merchant_id": "merchant_1721375416",
    "card": {
        "card_number": "424242xxxxxx4242",
        "card_exp_month": "10",
        "card_exp_year": "33",
        "nick_name": "Joh"
    },
    "customer_id": "cu_1721375441",
    "connector_mandate_details": {
        "mca_k9zWJaOP2XzQbygmkerU": {
            "connector_mandate_id": "1BF10FB47729ADD7E063AF598E0A9908"
        }
    }
}
'
```
```
{
    "merchant_id": "merchant_1721375416",
    "customer_id": "cu_1721375441",
    "payment_method_id": "pm_ZwoZZ11YSzX8iGECSUe1",
    "payment_method": "card",
    "payment_method_type": null,
    "card": {
        "scheme": "Visa",
        "issuer_country": "UNITEDKINGDOM",
        "last4_digits": "4242",
        "expiry_month": "10",
        "expiry_year": "33",
        "card_token": null,
        "card_holder_name": null,
        "card_fingerprint": null,
        "nick_name": "Joh",
        "card_network": "Visa",
        "card_isin": "424242",
        "card_issuer": "STRIPE PAYMENTS UK LIMITED",
        "card_type": "CREDIT",
        "saved_to_locker": false
    },
    "recurring_enabled": false,
    "installment_payment_enabled": false,
    "payment_experience": null,
    "metadata": null,
    "created": "2024-07-19T08:28:28.586Z",
    "last_used_at": null,
    "client_secret": null
}
```

-> Make a MIT with the migrated payment method details
```
curl --location 'http://localhost:8080/payment_methods/migrate' \
--header 'api-key: test_admin' \
--header 'Content-Type: application/json' \
--data '{
    "payment_method": "card",
    "merchant_id": "merchant_1721375416",
    "card": {
        "card_number": "424242xxxxxx4242",
        "card_exp_month": "10",
        "card_exp_year": "33",
        "nick_name": "Joh"
    },
    "customer_id": "cu_1721375441",
    "connector_mandate_details": {
        "mca_k9zWJaOP2XzQbygmkerU": {
            "connector_mandate_id": "hiahfi"
        }
    }
}
'
```
```
{
    "merchant_id": "merchant_1721375416",
    "customer_id": "cu_1721375441",
    "payment_method_id": "pm_MQkdTmCFjDcuSoDsaNQY",
    "payment_method": "card",
    "payment_method_type": null,
    "card": {
        "scheme": "Visa",
        "issuer_country": "UNITEDKINGDOM",
        "last4_digits": "4242",
        "expiry_month": "10",
        "expiry_year": "33",
        "card_token": null,
        "card_holder_name": null,
        "card_fingerprint": null,
        "nick_name": "Joh",
        "card_network": "Visa",
        "card_isin": "424242",
        "card_issuer": "STRIPE PAYMENTS UK LIMITED",
        "card_type": "CREDIT",
        "saved_to_locker": false
    },
    "recurring_enabled": false,
    "installment_payment_enabled": false,
    "payment_experience": null,
    "metadata": null,
    "created": "2024-07-19T09:10:00.443Z",
    "last_used_at": null,
    "client_secret": null
}
```
-> Create a payment with confirm false with the above customer id
```
curl --location 'http://localhost:8080/payments' \
--header 'Accept: application/json' \
--header 'api-key: dev_1oC3ReWVy4AaGA8ORA6EMm8JHS5WTlsmBtfRnNp2LLemMxZEJXfZ9hLYsd9wmWtg' \
--header 'Content-Type: application/json' \
--data '{
    "amount": 10000,
    "currency": "USD",
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "confirm": false,
    "setup_future_usage": "off_session",
    "customer_id": "cu_1721375441"
}'
```
```
{
    "payment_id": "pay_j5a3ywnN1phsL3wzUAcm",
    "merchant_id": "merchant_1721375416",
    "status": "requires_payment_method",
    "amount": 10000,
    "net_amount": 10000,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": null,
    "client_secret": "pay_j5a3ywnN1phsL3wzUAcm_secret_5rlnu9oeMJmtgXb3ZBLq",
    "created": "2024-07-19T09:12:34.290Z",
    "currency": "USD",
    "customer_id": "cu_1721375441",
    "customer": {
        "id": "cu_1721375441",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+65"
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": null,
    "payment_method_data": null,
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": null,
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": null,
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "cu_1721375441",
        "created_at": 1721380354,
        "expires": 1721383954,
        "secret": "epk_8e71524230c54b8c93aad028cefbee53"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": null,
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_Xr0FZLrIrMhCcomCOWSh",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": null,
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-07-19T09:27:34.290Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-07-19T09:12:34.317Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null
}
```
-> List payment methods
```
curl --location 'http://localhost:8080/customers/payment_methods?client_secret=pay_j5a3ywnN1phsL3wzUAcm_secret_5rlnu9oeMJmtgXb3ZBLq' \
--header 'Accept: application/json' \
--header 'api-key: '
```
```
{
    "customer_payment_methods": [
        {
            "payment_token": "token_pNplvKAPorPIvbXwefUW",
            "payment_method_id": "pm_MQkdTmCFjDcuSoDsaNQY",
            "customer_id": "cu_1721375441",
            "payment_method": "card",
            "payment_method_type": null,
            "payment_method_issuer": null,
            "payment_method_issuer_code": null,
            "recurring_enabled": true,
            "installment_payment_enabled": false,
            "payment_experience": [
                "redirect_to_url"
            ],
            "card": {
                "scheme": "Visa",
                "issuer_country": "UNITEDKINGDOM",
                "last4_digits": "4242",
                "expiry_month": "10",
                "expiry_year": "33",
                "card_token": null,
                "card_holder_name": null,
                "card_fingerprint": null,
                "nick_name": "Joh",
                "card_network": "Visa",
                "card_isin": "424242",
                "card_issuer": "STRIPE PAYMENTS UK LIMITED",
                "card_type": "CREDIT",
                "saved_to_locker": false
            },
            "metadata": null,
            "created": "2024-07-19T09:10:00.443Z",
            "bank": null,
            "surcharge_details": null,
            "requires_cvv": false,
            "last_used_at": "2024-07-19T09:10:00.443Z",
            "default_payment_method_set": false,
            "billing": null
        }
    "is_guest_customer": false
    ]
}
```
-> Confirm the payment 
```
curl --location 'http://localhost:8080/payments/pay_j5a3ywnN1phsL3wzUAcm/confirm' \
--header 'api-key: pk_dev_032d2d2b7ccf4013b41cfcb815a331c4' \
--header 'Content-Type: application/json' \
--data '{
    "payment_token": "token_pNplvKAPorPIvbXwefUW",
    "client_secret": "pay_j5a3ywnN1phsL3wzUAcm_secret_5rlnu9oeMJmtgXb3ZBLq",
    "payment_method": "card",
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "PiX",
            "last_name": "ss"
        }
    }
}'
```
```
{
    "payment_id": "pay_j5a3ywnN1phsL3wzUAcm",
    "merchant_id": "merchant_1721375416",
    "status": "succeeded",
    "amount": 10000,
    "net_amount": 10000,
    "amount_capturable": 0,
    "amount_received": 10000,
    "connector": "cybersource",
    "client_secret": "pay_j5a3ywnN1phsL3wzUAcm_secret_5rlnu9oeMJmtgXb3ZBLq",
    "created": "2024-07-19T09:12:34.290Z",
    "currency": "USD",
    "customer_id": "cu_1721375441",
    "customer": {
        "id": "cu_1721375441",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+65"
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": null,
    "payment_method_data": null,
    "payment_token": "token_pNplvKAPorPIvbXwefUW",
    "shipping": null,
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "PiX",
            "last_name": "ss"
        },
        "phone": null,
        "email": null
    },
    "order_details": null,
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": null,
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": null,
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": false,
    "connector_transaction_id": "7213805477216373003954",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "pay_j5a3ywnN1phsL3wzUAcm_1",
    "payment_link": null,
    "profile_id": "pro_Xr0FZLrIrMhCcomCOWSh",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_k9zWJaOP2XzQbygmkerU",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-07-19T09:27:34.290Z",
    "fingerprint": null,
    "browser_info": {
        "language": null,
        "time_zone": null,
        "ip_address": "::1",
        "user_agent": null,
        "color_depth": null,
        "java_enabled": null,
        "screen_width": null,
        "accept_header": null,
        "screen_height": null,
        "java_script_enabled": null
    },
    "payment_method_id": "pm_MQkdTmCFjDcuSoDsaNQY",
    "payment_method_status": "active",
    "updated": "2024-07-19T09:15:48.395Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null
}
```
-> Connector request
```
 raw_connector_request: Object {"processingInformation": Object {"actionList": Null, "actionTokenTypes": Null, "authorizationOptions": Object {"initiator": Null, "merchantIntitiatedTransaction": Object {"reason": Null, "previousTransactionId": Null, "originalAuthorizedAmount": Null}}, "commerceIndicator": String("internet"), "capture": Bool(true), "captureOptions": Null, "paymentSolution": Null}, "paymentInformation": Object {"paymentInstrument": Object {"id": String("*** alloc::string::String ***")}}, "orderInformation": Object {"amountDetails": Object {"totalAmount": String("100.00"), "currency": String("USD")}, "billTo": Object {"firstName": String("*** alloc::string::String ***"), "lastName": String("*** alloc::string::String ***"), "address1": String("*** alloc::string::String ***"), "locality": String("San Fransico"), "administrativeArea": String("*** alloc::string::String ***"), "postalCode": String("*** alloc::string::String ***"), "country": String("US"), "email": String("*****@example.com")}}, "clientReferenceInformation": Object {"code": String("pay_j5a3ywnN1phsL3wzUAcm_1")}}
```
-> Payment with migrated discover card
```
curl --location 'http://localhost:8080/payment_methods/migrate' \
--header 'api-key: test_admin' \
--header 'Content-Type: application/json' \
--data '{
    "payment_method": "card",
    "merchant_id": "merchant_1721375416",
    "card": {
        "card_number": "601111xxxxxx1117",
        "card_exp_month": "10",
        "card_exp_year": "33",
        "nick_name": "Joh"
    },
    "customer_id": "cu_1721380681",
    "connector_mandate_details": {
        "mca_k9zWJaOP2XzQbygmkerU": {
            "connector_mandate_id": "1BF10FB47729ADD7E063AF598E0A9908",
            "original_payment_authorized_amount": 6560,
            "original_payment_authorized_currency": "USD"
        }
    }
}
'
```
```
{
    "merchant_id": "merchant_1721375416",
    "customer_id": "cu_1721380681",
    "payment_method_id": "pm_9cRR2r6E8cL69tpJnaNj",
    "payment_method": "card",
    "payment_method_type": null,
    "card": {
        "scheme": "Discover",
        "issuer_country": null,
        "last4_digits": "1117",
        "expiry_month": "10",
        "expiry_year": "33",
        "card_token": null,
        "card_holder_name": null,
        "card_fingerprint": null,
        "nick_name": "Joh",
        "card_network": "Discover",
        "card_isin": "601111",
        "card_issuer": null,
        "card_type": "CREDIT",
        "saved_to_locker": false
    },
    "recurring_enabled": false,
    "installment_payment_enabled": false,
    "payment_experience": null,
    "metadata": null,
    "created": "2024-07-19T09:18:06.867Z",
    "last_used_at": null,
    "client_secret": null
}
```
```
curl --location 'http://localhost:8080/payments' \
--header 'Accept: application/json' \
--header 'api-key: dev_1oC3ReWVy4AaGA8ORA6EMm8JHS5WTlsmBtfRnNp2LLemMxZEJXfZ9hLYsd9wmWtg' \
--header 'Content-Type: application/json' \
--data '{
    "amount": 10000,
    "currency": "USD",
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "confirm": false,
    "setup_future_usage": "off_session",
    "customer_id": "cu_1721380681"
}'
```
```
{
    "payment_id": "pay_Lk545qXsXo4LdMgMLoDJ",
    "merchant_id": "merchant_1721375416",
    "status": "requires_payment_method",
    "amount": 10000,
    "net_amount": 10000,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": null,
    "client_secret": "pay_Lk545qXsXo4LdMgMLoDJ_secret_kIFzEWppjSudovmGPpSb",
    "created": "2024-07-19T09:18:15.484Z",
    "currency": "USD",
    "customer_id": "cu_1721380681",
    "customer": {
        "id": "cu_1721380681",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+65"
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": null,
    "payment_method_data": null,
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": null,
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": null,
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "cu_1721380681",
        "created_at": 1721380695,
        "expires": 1721384295,
        "secret": "epk_cdb56ad452eb4c11b1d7d8256683a3dc"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": null,
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_Xr0FZLrIrMhCcomCOWSh",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": null,
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-07-19T09:33:15.484Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-07-19T09:18:15.505Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null
}
```
```
curl --location 'http://localhost:8080/customers/payment_methods?client_secret=pay_Lk545qXsXo4LdMgMLoDJ_secret_kIFzEWppjSudovmGPpSb' \
--header 'Accept: application/json' \
--header 'api-key: pk_dev_032d2d2b7ccf4013b41cfcb815a331c4'
```
```
{
    "customer_payment_methods": [
        {
            "payment_token": "token_GgtGSli2dsvjLKdDCdN1",
            "payment_method_id": "pm_9cRR2r6E8cL69tpJnaNj",
            "customer_id": "cu_1721380681",
            "payment_method": "card",
            "payment_method_type": null,
            "payment_method_issuer": null,
            "payment_method_issuer_code": null,
            "recurring_enabled": true,
            "installment_payment_enabled": false,
            "payment_experience": [
                "redirect_to_url"
            ],
            "card": {
                "scheme": "Discover",
                "issuer_country": null,
                "last4_digits": "1117",
                "expiry_month": "10",
                "expiry_year": "33",
                "card_token": null,
                "card_holder_name": null,
                "card_fingerprint": null,
                "nick_name": "Joh",
                "card_network": "Discover",
                "card_isin": "601111",
                "card_issuer": null,
                "card_type": "CREDIT",
                "saved_to_locker": false
            },
            "metadata": null,
            "created": "2024-07-19T09:18:06.867Z",
            "bank": null,
            "surcharge_details": null,
            "requires_cvv": false,
            "last_used_at": "2024-07-19T09:18:06.867Z",
            "default_payment_method_set": true,
            "billing": null
        }
    ],
    "is_guest_customer": false
}
```
```
curl --location 'http://localhost:8080/payments/pay_Lk545qXsXo4LdMgMLoDJ/confirm' \
--header 'api-key: pk_dev_032d2d2b7ccf4013b41cfcb815a331c4' \
--header 'Content-Type: application/json' \
--data '{
    "payment_token": "token_GgtGSli2dsvjLKdDCdN1",
    "client_secret": "pay_Lk545qXsXo4LdMgMLoDJ_secret_kIFzEWppjSudovmGPpSb",
    "payment_method": "card",
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "PiX",
            "last_name": "ss"
        }
    }
}'
```
```
{
    "payment_id": "pay_Lk545qXsXo4LdMgMLoDJ",
    "merchant_id": "merchant_1721375416",
    "status": "succeeded",
    "amount": 10000,
    "net_amount": 10000,
    "amount_capturable": 0,
    "amount_received": 10000,
    "connector": "cybersource",
    "client_secret": "pay_Lk545qXsXo4LdMgMLoDJ_secret_kIFzEWppjSudovmGPpSb",
    "created": "2024-07-19T09:18:15.484Z",
    "currency": "USD",
    "customer_id": "cu_1721380681",
    "customer": {
        "id": "cu_1721380681",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+65"
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": null,
    "payment_method_data": null,
    "payment_token": "token_GgtGSli2dsvjLKdDCdN1",
    "shipping": null,
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "PiX",
            "last_name": "ss"
        },
        "phone": null,
        "email": null
    },
    "order_details": null,
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": null,
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": null,
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": false,
    "connector_transaction_id": "7213807255186401603954",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "pay_Lk545qXsXo4LdMgMLoDJ_1",
    "payment_link": null,
    "profile_id": "pro_Xr0FZLrIrMhCcomCOWSh",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_k9zWJaOP2XzQbygmkerU",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-07-19T09:33:15.484Z",
    "fingerprint": null,
    "browser_info": {
        "language": null,
        "time_zone": null,
        "ip_address": "::1",
        "user_agent": null,
        "color_depth": null,
        "java_enabled": null,
        "screen_width": null,
        "accept_header": null,
        "screen_height": null,
        "java_script_enabled": null
    },
    "payment_method_id": "pm_9cRR2r6E8cL69tpJnaNj",
    "payment_method_status": "active",
    "updated": "2024-07-19T09:18:46.232Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null
}
```
```
raw_connector_request: Object {"processingInformation": Object {"actionList": Null, "actionTokenTypes": Null, "authorizationOptions": Object {"initiator": Null, "merchantIntitiatedTransaction": Object {"reason": Null, "previousTransactionId": Null, "originalAuthorizedAmount": String("65.60")}}, "commerceIndicator": String("internet"), "capture": Bool(true), "captureOptions": Null, "paymentSolution": Null}, "paymentInformation": Object {"paymentInstrument": Object {"id": String("*** alloc::string::String ***")}}, "orderInformation": Object {"amountDetails": Object {"totalAmount": String("100.00"), "currency": String("USD")}, "billTo": Object {"firstName": String("*** alloc::string::String ***"), "lastName": String("*** alloc::string::String ***"), "address1": String("*** alloc::string::String ***"), "locality": String("San Fransico"), "administrativeArea": String("*** alloc::string::String ***"), "postalCode": String("*** alloc::string::String ***"), "country": String("US"), "email": String("*****@example.com")}}, "clientReferenceInformation": Object {"code": String("pay_Lk545qXsXo4LdMgMLoDJ_1")}}
```

-> Migrate the discover card for stripe without the `original_payment_authorized_amount` and `original_payment_authorized_currency` 
```
curl --location 'http://localhost:8080/payment_methods/migrate' \
--header 'api-key: test_admin' \
--header 'Content-Type: application/json' \
--data '{
    "payment_method": "card",
    "merchant_id": "merchant_1721375416",
    "card": {
        "card_number": "601111xxxxxx1117",
        "card_exp_month": "10",
        "card_exp_year": "33",
        "nick_name": "Joh"
    },
    "customer_id": "cu_1721380681",
    "connector_mandate_details": {
        "mca_tuuwWnqTVvyk5DOS8tO7": {
            "connector_mandate_id": "aaaaa"
        }
    }
}
'
```
```
{
    "merchant_id": "merchant_1721375416",
    "customer_id": "cu_1721380681",
    "payment_method_id": "pm_1sfzvLMBw0SVAdKRZcA2",
    "payment_method": "card",
    "payment_method_type": null,
    "card": {
        "scheme": "Discover",
        "issuer_country": null,
        "last4_digits": "1117",
        "expiry_month": "10",
        "expiry_year": "33",
        "card_token": null,
        "card_holder_name": null,
        "card_fingerprint": null,
        "nick_name": "Joh",
        "card_network": "Discover",
        "card_isin": "601111",
        "card_issuer": null,
        "card_type": "CREDIT",
        "saved_to_locker": false
    },
    "recurring_enabled": false,
    "installment_payment_enabled": false,
    "payment_experience": null,
    "metadata": null,
    "created": "2024-07-19T09:22:42.387Z",
    "last_used_at": null,
    "client_secret": null
}
```

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