    /// This is an unique label you can generate and pass in order to identify this connector account on your Hyperswitch dashboard and reports, If not passed then if will take `connector_name`_`profile_name`. Eg: if your profile label is `default`, connector label can be `stripe_default`
    #[schema(example = "stripe_US_travel")]
    pub connector_label: Option<String>,

    /// Identifier for the profile, if not provided default will be chosen from merchant account
    #[schema(max_length = 64, value_type = String)]
    pub profile_id: id_type::ProfileId,

    /// An object containing the required details/credentials for a Connector account.
    #[schema(value_type = Option<MerchantConnectorDetails>,example = json!({ "auth_type": "HeaderKey","api_key": "Basic MyVerySecretApiKey" }))]
    pub connector_account_details: Option<pii::SecretSerdeValue>,

    /// An object containing the details about the payment methods that need to be enabled under this merchant connector account
    #[schema(value_type = PaymentMethodsEnabled)]
    pub payment_methods_enabled: Option<Vec<common_types::payment_methods::PaymentMethodsEnabled>>,

    /// Webhook details of this merchant connector
    #[schema(example = json!({
        "connector_webhook_details": {
            "merchant_secret": "1234567890987654321"
        }
    }))]
    pub connector_webhook_details: Option<MerchantConnectorWebhookDetails>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>,max_length = 255,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,

    /// A boolean value to indicate if the connector is disabled. By default, its value is false.
    #[schema(default = false, example = false)]
    pub disabled: Option<bool>,

    /// Contains the frm configs for the merchant connector
    #[schema(example = json!(consts::FRM_CONFIGS_EG))]
    pub frm_configs: Option<Vec<FrmConfigs>>,

    /// pm_auth_config will relate MCA records to their respective chosen auth services, based on payment_method and pmt
    #[schema(value_type = Option<Object>)]
    pub pm_auth_config: Option<pii::SecretSerdeValue>,

    #[schema(value_type = Option<ConnectorStatus>, example = "inactive")]
    // By default the ConnectorStatus is Active
    pub status: Option<api_enums::ConnectorStatus>,

    /// In case the merchant needs to store any additional sensitive data
    #[schema(value_type = Option<AdditionalMerchantData>)]
    pub additional_merchant_data: Option<AdditionalMerchantData>,

    /// The connector_wallets_details is used to store wallet details such as certificates and wallet credentials
    #[schema(value_type = Option<ConnectorWalletDetails>)]
    pub connector_wallets_details: Option<ConnectorWalletDetails>,

    /// Additional data that might be required by hyperswitch, to enable some specific features.
    #[schema(value_type = Option<MerchantConnectorAccountFeatureMetadata>)]
    pub feature_metadata: Option<MerchantConnectorAccountFeatureMetadata>,
}

#[cfg(feature = "v2")]
impl MerchantConnectorCreate {
    pub fn get_transaction_type(&self) -> api_enums::TransactionType {
        match self.connector_type {
            #[cfg(feature = "payouts")]
            api_enums::ConnectorType::PayoutProcessor => api_enums::TransactionType::Payout,
            _ => api_enums::TransactionType::Payment,
        }
    }

    pub fn get_frm_config_as_secret(&self) -> Option<Vec<Secret<serde_json::Value>>> {
        match self.frm_configs.as_ref() {
            Some(frm_value) => {
                let configs_for_frm_value: Vec<Secret<serde_json::Value>> = frm_value
                    .iter()
                    .map(|config| config.encode_to_value().map(Secret::new))
                    .collect::<Result<Vec<_>, _>>()
                    .ok()?;
                Some(configs_for_frm_value)
            }
            None => None,
        }
    }

    pub fn get_connector_label(&self, profile_name: String) -> String {
        match self.connector_label.clone() {
            Some(connector_label) => connector_label,
            None => format!("{}_{}", self.connector_name, profile_name),
        }
    }
}

#[cfg(feature = "v1")]
/// Create a new Merchant Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc."
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MerchantConnectorCreate {
    /// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
    #[schema(value_type = ConnectorType, example = "payment_processor")]
    pub connector_type: api_enums::ConnectorType,
    /// Name of the Connector
    #[schema(value_type = Connector, example = "stripe")]
    pub connector_name: api_enums::Connector,
    /// This is an unique label you can generate and pass in order to identify this connector account on your Hyperswitch dashboard and reports. Eg: if your profile label is `default`, connector label can be `stripe_default`
    #[schema(example = "stripe_US_travel")]
    pub connector_label: Option<String>,

    /// Identifier for the profile, if not provided default will be chosen from merchant account
    #[schema(max_length = 64, value_type = Option<String>)]
    pub profile_id: Option<id_type::ProfileId>,

    /// An object containing the required details/credentials for a Connector account.
    #[schema(value_type = Option<MerchantConnectorDetails>,example = json!({ "auth_type": "HeaderKey","api_key": "Basic MyVerySecretApiKey" }))]
    pub connector_account_details: Option<pii::SecretSerdeValue>,

    /// An object containing the details about the payment methods that need to be enabled under this merchant connector account
    #[schema(example = json!([
        {
            "payment_method": "wallet",
            "payment_method_types": [
                "upi_collect",
                "upi_intent"
            ],
            "payment_method_issuers": [
                "labore magna ipsum",
                "aute"
            ],
            "payment_schemes": [
                "Discover",
                "Discover"
            ],
            "accepted_currencies": {
                "type": "enable_only",
                "list": ["USD", "EUR"]
            },
            "accepted_countries": {
                "type": "disable_only",
                "list": ["FR", "DE","IN"]
            },
            "minimum_amount": 1,
            "maximum_amount": 68607706,
            "recurring_enabled": true,
            "installment_payment_enabled": true
        }
    ]))]
    pub payment_methods_enabled: Option<Vec<PaymentMethodsEnabled>>,

    /// Webhook details of this merchant connector
    #[schema(example = json!({
        "connector_webhook_details": {
            "merchant_secret": "1234567890987654321"
        }
    }))]
    pub connector_webhook_details: Option<MerchantConnectorWebhookDetails>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>,max_length = 255,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,

    /// A boolean value to indicate if the connector is in Test mode. By default, its value is false.
    #[schema(default = false, example = false)]
    pub test_mode: Option<bool>,

    /// A boolean value to indicate if the connector is disabled. By default, its value is false.
    #[schema(default = false, example = false)]
    pub disabled: Option<bool>,

    /// Contains the frm configs for the merchant connector
    #[schema(example = json!(consts::FRM_CONFIGS_EG))]
    pub frm_configs: Option<Vec<FrmConfigs>>,

    /// The business country to which the connector account is attached. To be deprecated soon. Use the 'profile_id' instead
    #[schema(value_type = Option<CountryAlpha2>, example = "US")]
    pub business_country: Option<api_enums::CountryAlpha2>,

    /// The business label to which the connector account is attached. To be deprecated soon. Use the 'profile_id' instead
    pub business_label: Option<String>,

    /// The business sublabel to which the connector account is attached. To be deprecated soon. Use the 'profile_id' instead
    #[schema(example = "chase")]
    pub business_sub_label: Option<String>,

    /// Unique ID of the connector
    #[schema(example = "mca_5apGeP94tMts6rg3U3kR", value_type = Option<String>)]
    pub merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,

    #[schema(value_type = Option<Object>)]
    pub pm_auth_config: Option<pii::SecretSerdeValue>,

    #[schema(value_type = Option<ConnectorStatus>, example = "inactive")]
    pub status: Option<api_enums::ConnectorStatus>,

    /// In case the merchant needs to store any additional sensitive data
    #[schema(value_type = Option<AdditionalMerchantData>)]
    pub additional_merchant_data: Option<AdditionalMerchantData>,

    /// The connector_wallets_details is used to store wallet details such as certificates and wallet credentials
    #[schema(value_type = Option<ConnectorWalletDetails>)]
    pub connector_wallets_details: Option<ConnectorWalletDetails>,
}

#[cfg(feature = "v1")]
impl MerchantConnectorCreate {
    pub fn get_transaction_type(&self) -> api_enums::TransactionType {
        match self.connector_type {
            #[cfg(feature = "payouts")]
            api_enums::ConnectorType::PayoutProcessor => api_enums::TransactionType::Payout,
            _ => api_enums::TransactionType::Payment,
        }
    }

    pub fn get_frm_config_as_secret(&self) -> Option<Vec<Secret<serde_json::Value>>> {
        match self.frm_configs.as_ref() {
            Some(frm_value) => {
                let configs_for_frm_value: Vec<Secret<serde_json::Value>> = frm_value
                    .iter()
                    .map(|config| config.encode_to_value().map(Secret::new))
                    .collect::<Result<Vec<_>, _>>()
                    .ok()?;
                Some(configs_for_frm_value)
            }
            None => None,
        }
    }
}

#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum AdditionalMerchantData {
    OpenBankingRecipientData(MerchantRecipientData),
}

#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
/// Feature metadata for merchant connector account
pub struct MerchantConnectorAccountFeatureMetadata {
    /// Revenue recovery metadata for merchant connector account
    pub revenue_recovery: Option<RevenueRecoveryMetadata>,
}

#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
/// Revenue recovery metadata for merchant connector account
pub struct RevenueRecoveryMetadata {
    /// The maximum number of retries allowed for an invoice. This limit is set by the merchant for each `billing connector`. Once this limit is reached, no further retries will be attempted.
    #[schema(value_type = u16, example = "15")]
    pub max_retry_count: u16,
    /// Maximum number of `billing connector` retries before revenue recovery can start executing retries.
    #[schema(value_type = u16, example = "10")]
    pub billing_connector_retry_threshold: u16,
    /// Billing account reference id is payment gateway id at billing connector end.
    /// Merchants need to provide a mapping between these merchant connector account and the corresponding account reference IDs for each `billing connector`.
    #[schema(value_type = u16, example = r#"{ "mca_vDSg5z6AxnisHq5dbJ6g": "stripe_123", "mca_vDSg5z6AumisHqh4x5m1": "adyen_123" }"#)]
    pub billing_account_reference: HashMap<id_type::MerchantConnectorAccountId, String>,
}

#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum MerchantAccountData {
    /// IBAN-based account for international transfers
    Iban {
        /// International Bank Account Number (up to 34 characters)
        #[schema(value_type = String)]
        iban: Secret<String>,

        /// Account holder name
        name: String,
        #[schema(value_type = Option<String>)]
        #[serde(skip_serializing_if = "Option::is_none")]
        connector_recipient_id: Option<Secret<String>>,
    },
    /// UK BACS payment system
    Bacs {
        /// 8-digit UK account number
        #[schema(value_type = String)]
        account_number: Secret<String>,

        /// 6-digit UK sort code
        #[schema(value_type = String, example = "123456")]
        sort_code: Secret<String>,

        /// Account holder name
        name: String,

        #[schema(value_type = Option<String>)]
        #[serde(skip_serializing_if = "Option::is_none")]
        connector_recipient_id: Option<Secret<String>>,
    },
    /// UK Faster Payments (instant transfers)
    FasterPayments {
        /// 8-digit UK account number
        #[schema(value_type = String)]
        account_number: Secret<String>,
        /// 6-digit UK sort code
        #[schema(value_type = String)]
        sort_code: Secret<String>,

        /// Account holder name
        name: String,

        #[schema(value_type = Option<String>)]
        #[serde(skip_serializing_if = "Option::is_none")]
        connector_recipient_id: Option<Secret<String>>,
    },

    /// SEPA payments (Euro zone)
    Sepa {
        /// IBAN for SEPA transfers
        #[schema(value_type = String, example = "FR1420041010050500013M02606")]
        iban: Secret<String>,
        /// Account holder name
        name: String,
        #[schema(value_type = Option<String>)]
        #[serde(skip_serializing_if = "Option::is_none")]
        connector_recipient_id: Option<Secret<String>>,
    },

    /// SEPA Instant payments (10-second transfers)
    SepaInstant {
        /// IBAN for instant SEPA transfers
        #[schema(value_type = String, example = "DE89370400440532013000")]
        iban: Secret<String>,

        /// Account holder name
        name: String,

        #[schema(value_type = Option<String>)]
        #[serde(skip_serializing_if = "Option::is_none")]
        connector_recipient_id: Option<Secret<String>>,
    },

    /// Polish Elixir payment system
    Elixir {
        /// Polish account number (26 digits)
        #[schema(value_type = String, example = "12345678901234567890123456")]
        account_number: Secret<String>,

        /// Polish IBAN (28 chars)
        #[schema(value_type = String, example = "PL27114020040000300201355387")]
        iban: Secret<String>,

        /// Account holder name
        name: String,

        #[schema(value_type = Option<String>)]
        #[serde(skip_serializing_if = "Option::is_none")]
        connector_recipient_id: Option<Secret<String>>,
    },

    /// Swedish Bankgiro system
    Bankgiro {
        /// Bankgiro number (7-8 digits)
        #[schema(value_type = String, example = "5402-9656")]
        number: Secret<String>,

        /// Account holder name
        #[schema(example = "Erik Andersson")]
        name: String,

        #[schema(value_type = Option<String>)]
        #[serde(skip_serializing_if = "Option::is_none")]
        connector_recipient_id: Option<Secret<String>>,
    },

    /// Swedish Plusgiro system
    Plusgiro {
        /// Plusgiro number (2-8 digits)
        #[schema(value_type = String, example = "4789-2")]
        number: Secret<String>,

        /// Account holder name
        #[schema(example = "Anna Larsson")]
        name: String,

        #[schema(value_type = Option<String>)]
        #[serde(skip_serializing_if = "Option::is_none")]
        connector_recipient_id: Option<Secret<String>>,
    },
}

#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum MerchantRecipientData {
    #[schema(value_type= Option<String>)]
    ConnectorRecipientId(Secret<String>),
    #[schema(value_type= Option<String>)]
    WalletId(Secret<String>),
    AccountData(MerchantAccountData),
}

// Different patterns of authentication.
#[derive(Default, Debug, Clone, serde::Deserialize, serde::Serialize)]
#[serde(tag = "auth_type")]
pub enum ConnectorAuthType {
    TemporaryAuth,
    HeaderKey {
        api_key: Secret<String>,
    },
    BodyKey {
        api_key: Secret<String>,
        key1: Secret<String>,
    },
    SignatureKey {
        api_key: Secret<String>,
        key1: Secret<String>,
        api_secret: Secret<String>,
    },
    MultiAuthKey {
        api_key: Secret<String>,
        key1: Secret<String>,
        api_secret: Secret<String>,
        key2: Secret<String>,
    },
    CurrencyAuthKey {
        auth_key_map: HashMap<common_enums::Currency, pii::SecretSerdeValue>,
    },
    CertificateAuth {
        // certificate should be base64 encoded
        certificate: Secret<String>,
        // private_key should be base64 encoded
        private_key: Secret<String>,
    },
    #[default]
    NoKey,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MerchantConnectorWebhookDetails {
    #[schema(value_type = String, example = "12345678900987654321")]
    pub merchant_secret: Secret<String>,
    #[schema(value_type = String, example = "12345678900987654321")]
    pub additional_secret: Option<Secret<String>>,
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, ToSchema)]
pub struct MerchantConnectorInfo {
    pub connector_label: String,
    #[schema(value_type = String)]
    pub merchant_connector_id: id_type::MerchantConnectorAccountId,
}

impl MerchantConnectorInfo {
    pub fn new(
        connector_label: String,
        merchant_connector_id: id_type::MerchantConnectorAccountId,
    ) -> Self {
        Self {
            connector_label,
            merchant_connector_id,
        }
    }
}

/// Response of creating a new Merchant Connector for the merchant account."
#[cfg(feature = "v2")]
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MerchantConnectorResponse {
    /// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
    #[schema(value_type = ConnectorType, example = "payment_processor")]
    pub connector_type: api_enums::ConnectorType,

    /// Name of the Connector
    #[schema(value_type = Connector, example = "stripe")]
    pub connector_name: common_enums::connector_enums::Connector,

    /// A unique label to identify the connector account created under a profile
    #[schema(example = "stripe_US_travel")]
    pub connector_label: Option<String>,

    /// Unique ID of the merchant connector account
    #[schema(example = "mca_5apGeP94tMts6rg3U3kR", value_type = String)]
    pub id: id_type::MerchantConnectorAccountId,

    /// Identifier for the profile, if not provided default will be chosen from merchant account
    #[schema(max_length = 64, value_type = String)]
    pub profile_id: id_type::ProfileId,

    /// An object containing the required details/credentials for a Connector account.
    #[schema(value_type = Option<MerchantConnectorDetails>,example = json!({ "auth_type": "HeaderKey","api_key": "Basic MyVerySecretApiKey" }))]
    pub connector_account_details: pii::SecretSerdeValue,

    /// An object containing the details about the payment methods that need to be enabled under this merchant connector account
    #[schema(value_type = Vec<PaymentMethodsEnabled>)]
    pub payment_methods_enabled: Option<Vec<common_types::payment_methods::PaymentMethodsEnabled>>,

    /// Webhook details of this merchant connector
    #[schema(example = json!({
        "connector_webhook_details": {
            "merchant_secret": "1234567890987654321"
        }
    }))]
    pub connector_webhook_details: Option<MerchantConnectorWebhookDetails>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>,max_length = 255,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,

    /// A boolean value to indicate if the connector is disabled. By default, its value is false.
    #[schema(default = false, example = false)]
    pub disabled: Option<bool>,

    /// Contains the frm configs for the merchant connector
    #[schema(example = json!(consts::FRM_CONFIGS_EG))]
    pub frm_configs: Option<Vec<FrmConfigs>>,

    /// identifier for the verified domains of a particular connector account
    pub applepay_verified_domains: Option<Vec<String>>,

    /// pm_auth_config will relate MCA records to their respective chosen auth services, based on payment_method and pmt
    #[schema(value_type = Option<Object>)]
    pub pm_auth_config: Option<pii::SecretSerdeValue>,

    #[schema(value_type = ConnectorStatus, example = "inactive")]
    pub status: api_enums::ConnectorStatus,

    #[schema(value_type = Option<AdditionalMerchantData>)]
    pub additional_merchant_data: Option<AdditionalMerchantData>,

    /// The connector_wallets_details is used to store wallet details such as certificates and wallet credentials
    #[schema(value_type = Option<ConnectorWalletDetails>)]
    pub connector_wallets_details: Option<ConnectorWalletDetails>,

    /// Additional data that might be required by hyperswitch, to enable some specific features.
    #[schema(value_type = Option<MerchantConnectorAccountFeatureMetadata>)]
    pub feature_metadata: Option<MerchantConnectorAccountFeatureMetadata>,
}

#[cfg(feature = "v2")]
impl MerchantConnectorResponse {
    pub fn to_merchant_connector_info(&self, connector_label: &String) -> MerchantConnectorInfo {
        MerchantConnectorInfo {
            connector_label: connector_label.to_string(),
            merchant_connector_id: self.id.clone(),
        }
    }
}

/// Response of creating a new Merchant Connector for the merchant account."
#[cfg(feature = "v1")]
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MerchantConnectorResponse {
    /// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
    #[schema(value_type = ConnectorType, example = "payment_processor")]
    pub connector_type: api_enums::ConnectorType,
    /// Name of the Connector
    #[schema(value_type = Connector, example = "stripe")]
    pub connector_name: String,

    /// A unique label to identify the connector account created under a profile
    #[schema(example = "stripe_US_travel")]
    pub connector_label: Option<String>,

    /// Unique ID of the merchant connector account
    #[schema(example = "mca_5apGeP94tMts6rg3U3kR", value_type = String)]
    pub merchant_connector_id: id_type::MerchantConnectorAccountId,

    /// Identifier for the profile, if not provided default will be chosen from merchant account
    #[schema(max_length = 64, value_type = String)]
    pub profile_id: id_type::ProfileId,

    /// An object containing the required details/credentials for a Connector account.
    #[schema(value_type = Option<MerchantConnectorDetails>,example = json!({ "auth_type": "HeaderKey","api_key": "Basic MyVerySecretApiKey" }))]
    pub connector_account_details: pii::SecretSerdeValue,

    /// An object containing the details about the payment methods that need to be enabled under this merchant connector account
    #[schema(example = json!([
        {
            "payment_method": "wallet",
            "payment_method_types": [
                "upi_collect",
                "upi_intent"
            ],
            "payment_method_issuers": [
                "labore magna ipsum",
                "aute"
            ],
            "payment_schemes": [
                "Discover",
                "Discover"
            ],
            "accepted_currencies": {
                "type": "enable_only",
                "list": ["USD", "EUR"]
            },
            "accepted_countries": {
                "type": "disable_only",
                "list": ["FR", "DE","IN"]
            },
            "minimum_amount": 1,
            "maximum_amount": 68607706,
            "recurring_enabled": true,
            "installment_payment_enabled": true
        }
    ]))]
    pub payment_methods_enabled: Option<Vec<PaymentMethodsEnabled>>,

    /// Webhook details of this merchant connector
    #[schema(example = json!({
        "connector_webhook_details": {
            "merchant_secret": "1234567890987654321"
        }
    }))]
    pub connector_webhook_details: Option<MerchantConnectorWebhookDetails>,

    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>,max_length = 255,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,

    /// A boolean value to indicate if the connector is in Test mode. By default, its value is false.
    #[schema(default = false, example = false)]
    pub test_mode: Option<bool>,

    /// A boolean value to indicate if the connector is disabled. By default, its value is false.
    #[schema(default = false, example = false)]
    pub disabled: Option<bool>,

    /// Contains the frm configs for the merchant connector
    #[schema(example = json!(consts::FRM_CONFIGS_EG))]
    pub frm_configs: Option<Vec<FrmConfigs>>,

    /// The business country to which the connector account is attached. To be deprecated soon. Use the 'profile_id' instead
    #[schema(value_type = Option<CountryAlpha2>, example = "US")]
    pub business_country: Option<api_enums::CountryAlpha2>,

    ///The business label to which the connector account is attached. To be deprecated soon. Use the 'profile_id' instead
    #[schema(example = "travel")]
    pub business_label: Option<String>,

    /// The business sublabel to which the connector account is attached. To be deprecated soon. Use the 'profile_id' instead
    #[schema(example = "chase")]
    pub business_sub_label: Option<String>,

    /// identifier for the verified domains of a particular connector account
    pub applepay_verified_domains: Option<Vec<String>>,

    #[schema(value_type = Option<Object>)]
    pub pm_auth_config: Option<pii::SecretSerdeValue>,

    #[schema(value_type = ConnectorStatus, example = "inactive")]
    pub status: api_enums::ConnectorStatus,

    #[schema(value_type = Option<AdditionalMerchantData>)]
    pub additional_merchant_data: Option<AdditionalMerchantData>,

    /// The connector_wallets_details is used to store wallet details such as certificates and wallet credentials
    #[schema(value_type = Option<ConnectorWalletDetails>)]
    pub connector_wallets_details: Option<ConnectorWalletDetails>,
}

#[cfg(feature = "v1")]
impl MerchantConnectorResponse {
    pub fn to_merchant_connector_info(&self, connector_label: &String) -> MerchantConnectorInfo {
        MerchantConnectorInfo {
            connector_label: connector_label.to_string(),
            merchant_connector_id: self.merchant_connector_id.clone(),
        }
    }
}

#[cfg(feature = "v1")]
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MerchantConnectorListResponse {
    /// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
    #[schema(value_type = ConnectorType, example = "payment_processor")]
    pub connector_type: api_enums::ConnectorType,
    /// Name of the Connector
    #[schema(value_type = Connector, example = "stripe")]
    pub connector_name: String,

    /// A unique label to identify the connector account created under a profile
    #[schema(example = "stripe_US_travel")]
    pub connector_label: Option<String>,

    /// Unique ID of the merchant connector account
    #[schema(example = "mca_5apGeP94tMts6rg3U3kR", value_type = String)]
    pub merchant_connector_id: id_type::MerchantConnectorAccountId,

    /// Identifier for the profile, if not provided default will be chosen from merchant account
    #[schema(max_length = 64, value_type = String)]
    pub profile_id: id_type::ProfileId,

    /// An object containing the details about the payment methods that need to be enabled under this merchant connector account
    #[schema(example = json!([
        {
            "payment_method": "wallet",
            "payment_method_types": [
                "upi_collect",
                "upi_intent"
            ],
            "payment_method_issuers": [
                "labore magna ipsum",
                "aute"
            ],
            "payment_schemes": [
                "Discover",
                "Discover"
            ],
            "accepted_currencies": {
                "type": "enable_only",
                "list": ["USD", "EUR"]
            },
            "accepted_countries": {
                "type": "disable_only",
                "list": ["FR", "DE","IN"]
            },
            "minimum_amount": 1,
            "maximum_amount": 68607706,
            "recurring_enabled": true,
            "installment_payment_enabled": true
        }
    ]))]
    pub payment_methods_enabled: Option<Vec<PaymentMethodsEnabled>>,

    /// A boolean value to indicate if the connector is in Test mode. By default, its value is false.
    #[schema(default = false, example = false)]
    pub test_mode: Option<bool>,

    /// A boolean value to indicate if the connector is disabled. By default, its value is false.
    #[schema(default = false, example = false)]
    pub disabled: Option<bool>,

    /// Contains the frm configs for the merchant connector
    #[schema(example = json!(consts::FRM_CONFIGS_EG))]
    pub frm_configs: Option<Vec<FrmConfigs>>,

    /// The business country to which the connector account is attached. To be deprecated soon. Use the 'profile_id' instead
    #[schema(value_type = Option<CountryAlpha2>, example = "US")]
    pub business_country: Option<api_enums::CountryAlpha2>,

    ///The business label to which the connector account is attached. To be deprecated soon. Use the 'profile_id' instead
    #[schema(example = "travel")]
    pub business_label: Option<String>,

    /// The business sublabel to which the connector account is attached. To be deprecated soon. Use the 'profile_id' instead
    #[schema(example = "chase")]
    pub business_sub_label: Option<String>,

    /// identifier for the verified domains of a particular connector account
    pub applepay_verified_domains: Option<Vec<String>>,

    #[schema(value_type = Option<Object>)]
    pub pm_auth_config: Option<pii::SecretSerdeValue>,

    #[schema(value_type = ConnectorStatus, example = "inactive")]
    pub status: api_enums::ConnectorStatus,
}

#[cfg(feature = "v1")]
impl MerchantConnectorListResponse {
    pub fn to_merchant_connector_info(&self, connector_label: &String) -> MerchantConnectorInfo {
        MerchantConnectorInfo {
            connector_label: connector_label.to_string(),
            merchant_connector_id: self.merchant_connector_id.clone(),
        }
    }
    pub fn get_connector_name(&self) -> String {
        self.connector_name.clone()
    }
}

#[cfg(feature = "v2")]
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MerchantConnectorListResponse {
    /// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
    #[schema(value_type = ConnectorType, example = "payment_processor")]
    pub connector_type: api_enums::ConnectorType,

    /// Name of the Connector
    #[schema(value_type = Connector, example = "stripe")]
    pub connector_name: common_enums::connector_enums::Connector,

    /// A unique label to identify the connector account created under a profile
    #[schema(example = "stripe_US_travel")]
    pub connector_label: Option<String>,

    /// Unique ID of the merchant connector account
    #[schema(example = "mca_5apGeP94tMts6rg3U3kR", value_type = String)]
    pub id: id_type::MerchantConnectorAccountId,

    /// Identifier for the profile, if not provided default will be chosen from merchant account
    #[schema(max_length = 64, value_type = String)]
    pub profile_id: id_type::ProfileId,

    /// An object containing the details about the payment methods that need to be enabled under this merchant connector account
    #[schema(value_type = Vec<PaymentMethodsEnabled>)]
    pub payment_methods_enabled: Option<Vec<common_types::payment_methods::PaymentMethodsEnabled>>,

    /// A boolean value to indicate if the connector is disabled. By default, its value is false.
    #[schema(default = false, example = false)]
    pub disabled: Option<bool>,

    /// Contains the frm configs for the merchant connector
    #[schema(example = json!(consts::FRM_CONFIGS_EG))]
    pub frm_configs: Option<Vec<FrmConfigs>>,

    /// identifier for the verified domains of a particular connector account
    pub applepay_verified_domains: Option<Vec<String>>,

    #[schema(value_type = Option<Object>)]
    pub pm_auth_config: Option<pii::SecretSerdeValue>,

    #[schema(value_type = ConnectorStatus, example = "inactive")]
    pub status: api_enums::ConnectorStatus,
}

#[cfg(feature = "v2")]
impl MerchantConnectorListResponse {
    pub fn to_merchant_connector_info(&self, connector_label: &String) -> MerchantConnectorInfo {
        MerchantConnectorInfo {
            connector_label: connector_label.to_string(),
            merchant_connector_id: self.id.clone(),
        }
    }
    pub fn get_connector_name(&self) -> common_enums::connector_enums::Connector {
        self.connector_name
    }
}

/// Create a new Merchant Connector for the merchant account. The connector could be a payment processor / facilitator / acquirer or specialized services like Fraud / Accounting etc."
#[cfg(feature = "v1")]
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(deny_unknown_fields)]
pub struct MerchantConnectorUpdate {
    /// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
    #[schema(value_type = ConnectorType, example = "payment_processor")]
    pub connector_type: api_enums::ConnectorType,

    /// This is an unique label you can generate and pass in order to identify this connector account on your Hyperswitch dashboard and reports. Eg: if your profile label is `default`, connector label can be `stripe_default`
    #[schema(example = "stripe_US_travel")]
    pub connector_label: Option<String>,

    /// An object containing the required details/credentials for a Connector account.
    #[schema(value_type = Option<MerchantConnectorDetails>,example = json!({ "auth_type": "HeaderKey","api_key": "Basic MyVerySecretApiKey" }))]
    pub connector_account_details: Option<pii::SecretSerdeValue>,

    /// An object containing the details about the payment methods that need to be enabled under this merchant connector account
    #[schema(example = json!([
        {
            "payment_method": "wallet",
            "payment_method_types": [
                "upi_collect",
                "upi_intent"
            ],
            "payment_method_issuers": [
                "labore magna ipsum",
                "aute"
            ],
            "payment_schemes": [
                "Discover",
                "Discover"
            ],
            "accepted_currencies": {
                "type": "enable_only",
                "list": ["USD", "EUR"]
            },
            "accepted_countries": {
                "type": "disable_only",
                "list": ["FR", "DE","IN"]
            },
            "minimum_amount": 1,
            "maximum_amount": 68607706,
            "recurring_enabled": true,
            "installment_payment_enabled": true
        }
    ]))]
    pub payment_methods_enabled: Option<Vec<PaymentMethodsEnabled>>,

    /// Webhook details of this merchant connector
    #[schema(example = json!({
        "connector_webhook_details": {


// Function: get_or_create_customer_details
// File: crates/router/src/core/payouts/helpers.rs
// Module: router

pub fn get_or_create_customer_details(
    state: &SessionState,
    customer_details: &CustomerDetails,
    merchant_context: &domain::MerchantContext,
) -> RouterResult<Option<domain::Customer>>


// File: crates/router/src/core/verification.rs
// Module: router
// Public functions: 2

pub mod utils;
use api_models::verifications::{self, ApplepayMerchantResponse};
use common_utils::{errors::CustomResult, request::RequestContent};
use error_stack::ResultExt;
use masking::ExposeInterface;

use crate::{core::errors, headers, logger, routes::SessionState, services};

const APPLEPAY_INTERNAL_MERCHANT_NAME: &str = "Applepay_merchant";

pub async fn verify_merchant_creds_for_applepay(
    state: SessionState,
    body: verifications::ApplepayMerchantVerificationRequest,
    merchant_id: common_utils::id_type::MerchantId,
    profile_id: Option<common_utils::id_type::ProfileId>,
) -> CustomResult<services::ApplicationResponse<ApplepayMerchantResponse>, errors::ApiErrorResponse>
{
    let applepay_merchant_configs = state.conf.applepay_merchant_configs.get_inner();

    let applepay_internal_merchant_identifier = applepay_merchant_configs
        .common_merchant_identifier
        .clone()
        .expose();
    let cert_data = applepay_merchant_configs.merchant_cert.clone();
    let key_data = applepay_merchant_configs.merchant_cert_key.clone();
    let applepay_endpoint = &applepay_merchant_configs.applepay_endpoint;

    let request_body = verifications::ApplepayMerchantVerificationConfigs {
        domain_names: body.domain_names.clone(),
        encrypt_to: applepay_internal_merchant_identifier.clone(),
        partner_internal_merchant_identifier: applepay_internal_merchant_identifier,
        partner_merchant_name: APPLEPAY_INTERNAL_MERCHANT_NAME.to_string(),
    };

    let apple_pay_merch_verification_req = services::RequestBuilder::new()
        .method(services::Method::Post)
        .url(applepay_endpoint)
        .attach_default_headers()
        .headers(vec![(
            headers::CONTENT_TYPE.to_string(),
            "application/json".to_string().into(),
        )])
        .set_body(RequestContent::Json(Box::new(request_body)))
        .add_certificate(Some(cert_data))
        .add_certificate_key(Some(key_data))
        .build();

    let response = services::call_connector_api(
        &state,
        apple_pay_merch_verification_req,
        "verify_merchant_creds_for_applepay",
    )
    .await;
    utils::log_applepay_verification_response_if_error(&response);

    let applepay_response =
        response.change_context(errors::ApiErrorResponse::InternalServerError)?;

    // Error is already logged
    match applepay_response {
        Ok(_) => {
            utils::check_existence_and_add_domain_to_db(
                &state,
                merchant_id,
                profile_id,
                body.merchant_connector_account_id.clone(),
                body.domain_names.clone(),
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)?;
            Ok(services::api::ApplicationResponse::Json(
                ApplepayMerchantResponse {
                    status_message: "Applepay verification Completed".to_string(),
                },
            ))
        }
        Err(error) => {
            logger::error!(?error);
            Err(errors::ApiErrorResponse::InvalidRequestData {
                message: "Applepay verification Failed".to_string(),
            }
            .into())
        }
    }
}

pub async fn get_verified_apple_domains_with_mid_mca_id(
    state: SessionState,
    merchant_id: common_utils::id_type::MerchantId,
    merchant_connector_id: common_utils::id_type::MerchantConnectorAccountId,
) -> CustomResult<
    services::ApplicationResponse<verifications::ApplepayVerifiedDomainsResponse>,
    errors::ApiErrorResponse,
> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let key_store = db
        .get_merchant_key_store_by_merchant_id(
            key_manager_state,
            &merchant_id,
            &db.get_master_key().to_vec().into(),
        )
        .await
        .change_context(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    #[cfg(feature = "v1")]
    let verified_domains = db
        .find_by_merchant_connector_account_merchant_id_merchant_connector_id(
            key_manager_state,
            &merchant_id,
            &merchant_connector_id,
            &key_store,
        )
        .await
        .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?
        .applepay_verified_domains
        .unwrap_or_default();

    #[cfg(feature = "v2")]
    let verified_domains = db
        .find_merchant_connector_account_by_id(
            key_manager_state,
            &merchant_connector_id,
            &key_store,
        )
        .await
        .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?
        .applepay_verified_domains
        .unwrap_or_default();

    Ok(services::api::ApplicationResponse::Json(
        verifications::ApplepayVerifiedDomainsResponse { verified_domains },
    ))
}


// File: crates/pm_auth/src/connector.rs
// Module: pm_auth

pub mod plaid;

pub use self::plaid::Plaid;


// Struct: UasAuthenticationRequestData
// File: crates/hyperswitch_domain_models/src/router_request_types/unified_authentication_service.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct UasAuthenticationRequestData


// Implementation: impl api::PaymentCapture for for Stripe
// File: crates/hyperswitch_connectors/src/connectors/stripe.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentCapture for for Stripe


// Implementation: impl api::RefundSync for for Checkbook
// File: crates/hyperswitch_connectors/src/connectors/checkbook.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::RefundSync for for Checkbook


// Function: new
// File: crates/router/src/core/payments/types.rs
// Module: router

pub fn new(payment_attempt_id: String) -> Self


// Implementation: impl api::RefundSync for for Bluecode
// File: crates/hyperswitch_connectors/src/connectors/bluecode.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::RefundSync for for Bluecode


// Implementation: impl NewUserMerchant
// File: crates/router/src/types/domain/user.rs
// Module: router
// Methods: 9 total (4 public)

impl NewUserMerchant


// Function: from_storage
// File: crates/router/src/services/kafka/fraud_check_event.rs
// Module: router

pub fn from_storage(check: &'a FraudCheck) -> Self


// File: crates/router/tests/connectors/tokenio.rs
// Module: router

use hyperswitch_domain_models::payment_method_data::{Card, PaymentMethodData};
use masking::Secret;
use router::types::{self, api, storage::enums};
use test_utils::connector_auth;

use crate::utils::{self, ConnectorActions};

#[derive(Clone, Copy)]
struct TokenioTest;
impl ConnectorActions for TokenioTest {}
impl utils::Connector for TokenioTest {
    fn get_data(&self) -> api::ConnectorData {
        use router::connector::Tokenio;
        utils::construct_connector_data_old(
            Box::new(Tokenio::new()),
            types::Connector::Plaid,
            api::GetToken::Connector,
            None,
        )
    }

    fn get_auth_token(&self) -> types::ConnectorAuthType {
        utils::to_connector_auth_type(
            connector_auth::ConnectorAuthentication::new()
                .tokenio
                .expect("Missing connector authentication configuration")
                .into(),
        )
    }

    fn get_name(&self) -> String {
        "tokenio".to_string()
    }
}

static CONNECTOR: TokenioTest = TokenioTest {};

fn get_default_payment_info() -> Option<utils::PaymentInfo> {
    None
}

fn payment_method_details() -> Option<types::PaymentsAuthorizeData> {
    None
}

// Cards Positive Tests
// Creates a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_only_authorize_payment() {
    let response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized);
}

// Captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info())
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Partially captures a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(
            payment_method_details(),
            Some(types::PaymentsCaptureData {
                amount_to_capture: 50,
                ..utils::PaymentCaptureType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_authorized_payment() {
    let authorize_response = CONNECTOR
        .authorize_payment(payment_method_details(), get_default_payment_info())
        .await
        .expect("Authorize payment response");
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Authorized,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("PSync response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
}

// Voids a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_void_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_void_payment(
            payment_method_details(),
            Some(types::PaymentsCancelData {
                connector_transaction_id: String::from(""),
                cancellation_reason: Some("requested_by_customer".to_string()),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .expect("Void payment response");
    assert_eq!(response.status, enums::AttemptStatus::Voided);
}

// Refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Synchronizes a refund using the manual capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_manually_captured_refund() {
    let refund_response = CONNECTOR
        .capture_payment_and_refund(
            payment_method_details(),
            None,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_make_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_auto_captured_payment() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Charged,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                capture_method: Some(enums::CaptureMethod::Automatic),
                ..Default::default()
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(response.status, enums::AttemptStatus::Charged,);
}

// Refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_auto_captured_payment() {
    let response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_partially_refund_succeeded_payment() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        refund_response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_refund_succeeded_payment_multiple_times() {
    CONNECTOR
        .make_payment_and_multiple_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await;
}

// Synchronizes a refund using the automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_sync_refund() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Cards Negative scenarios
// Creates a payment with incorrect CVC.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_cvc() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_cvc: Secret::new("12345".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's security code is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry month.
#[actix_web::test]
async fn should_fail_payment_for_invalid_exp_month() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_exp_month: Secret::new("20".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration month is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry year.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_expiry_year() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: PaymentMethodData::Card(Card {
                    card_exp_year: Secret::new("2000".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration year is invalid.".to_string(),
    );
}

// Voids a payment using automatic capture flow (Non 3DS).
#[actix_web::test]
async fn should_fail_void_payment_for_auto_capture() {
    let authorize_response = CONNECTOR
        .make_payment(payment_method_details(), get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let void_response = CONNECTOR
        .void_payment(txn_id.unwrap(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        void_response.response.unwrap_err().message,
        "You cannot cancel this PaymentIntent because it has a status of succeeded."
    );
}

// Captures a payment using invalid connector payment id.
#[actix_web::test]
async fn should_fail_capture_for_invalid_payment() {
    let capture_response = CONNECTOR
        .capture_payment("123456789".to_string(), None, get_default_payment_info())
        .await
        .unwrap();
    assert_eq!(
        capture_response.response.unwrap_err().message,
        String::from("No such payment_intent: '123456789'")
    );
}

// Refunds a payment with refund amount higher than payment amount.
#[actix_web::test]
async fn should_fail_for_refund_amount_higher_than_payment_amount() {
    let response = CONNECTOR
        .make_payment_and_refund(
            payment_method_details(),
            Some(types::RefundsData {
                refund_amount: 150,
                ..utils::PaymentRefundType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Refund amount (₹1.50) is greater than charge amount (₹1.00)",
    );
}

// Connector dependent test cases goes here

// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests


// Function: get_vault_response_for_insert_payment_method_data
// File: crates/router/src/core/payment_methods.rs
// Module: router

pub fn get_vault_response_for_insert_payment_method_data<F>(
    router_data: VaultRouterData<F>,
) -> RouterResult<pm_types::AddVaultResponse>


// Struct: EventDetails
// File: crates/hyperswitch_connectors/src/connectors/xendit/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct EventDetails


// File: crates/external_services/src/file_storage.rs
// Module: external_services
// Public functions: 2
// Public structs: 1

//! Module for managing file storage operations with support for multiple storage schemes.

use std::{
    fmt::{Display, Formatter},
    sync::Arc,
};

use common_utils::errors::CustomResult;

/// Includes functionality for AWS S3 storage operations.
#[cfg(feature = "aws_s3")]
mod aws_s3;

mod file_system;

/// Enum representing different file storage configurations, allowing for multiple storage schemes.
#[derive(Debug, Clone, Default, serde::Deserialize)]
#[serde(tag = "file_storage_backend")]
#[serde(rename_all = "snake_case")]
pub enum FileStorageConfig {
    /// AWS S3 storage configuration.
    #[cfg(feature = "aws_s3")]
    AwsS3 {
        /// Configuration for AWS S3 file storage.
        aws_s3: aws_s3::AwsFileStorageConfig,
    },
    /// Local file system storage configuration.
    #[default]
    FileSystem,
}

impl FileStorageConfig {
    /// Validates the file storage configuration.
    pub fn validate(&self) -> Result<(), InvalidFileStorageConfig> {
        match self {
            #[cfg(feature = "aws_s3")]
            Self::AwsS3 { aws_s3 } => aws_s3.validate(),
            Self::FileSystem => Ok(()),
        }
    }

    /// Retrieves the appropriate file storage client based on the file storage configuration.
    pub async fn get_file_storage_client(&self) -> Arc<dyn FileStorageInterface> {
        match self {
            #[cfg(feature = "aws_s3")]
            Self::AwsS3 { aws_s3 } => Arc::new(aws_s3::AwsFileStorageClient::new(aws_s3).await),
            Self::FileSystem => Arc::new(file_system::FileSystem),
        }
    }
}

/// Trait for file storage operations
#[async_trait::async_trait]
pub trait FileStorageInterface: dyn_clone::DynClone + Sync + Send {
    /// Uploads a file to the selected storage scheme.
    async fn upload_file(
        &self,
        file_key: &str,
        file: Vec<u8>,
    ) -> CustomResult<(), FileStorageError>;

    /// Deletes a file from the selected storage scheme.
    async fn delete_file(&self, file_key: &str) -> CustomResult<(), FileStorageError>;

    /// Retrieves a file from the selected storage scheme.
    async fn retrieve_file(&self, file_key: &str) -> CustomResult<Vec<u8>, FileStorageError>;
}

dyn_clone::clone_trait_object!(FileStorageInterface);

/// Error thrown when the file storage config is invalid
#[derive(Debug, Clone)]
pub struct InvalidFileStorageConfig(&'static str);

impl std::error::Error for InvalidFileStorageConfig {}

impl Display for InvalidFileStorageConfig {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "file_storage: {}", self.0)
    }
}

/// Represents errors that can occur during file storage operations.
#[derive(Debug, thiserror::Error, PartialEq)]
pub enum FileStorageError {
    /// Indicates that the file upload operation failed.
    #[error("Failed to upload file")]
    UploadFailed,

    /// Indicates that the file retrieval operation failed.
    #[error("Failed to retrieve file")]
    RetrieveFailed,

    /// Indicates that the file deletion operation failed.
    #[error("Failed to delete file")]
    DeleteFailed,
}


// Struct: ProcessorResponseDetails
// File: crates/hyperswitch_connectors/src/connectors/fiserv/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ProcessorResponseDetails


// Struct: Amount
// File: crates/hyperswitch_connectors/src/connectors/getnet/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct Amount


// Function: get_redis_connection_for_global_tenant
// File: crates/router/src/utils/user.rs
// Module: router

pub fn get_redis_connection_for_global_tenant(
    state: &SessionState,
) -> UserResult<Arc<RedisConnectionPool>>


// File: crates/analytics/src/active_payments/accumulator.rs
// Module: analytics
// Public functions: 1
// Public structs: 2

use api_models::analytics::active_payments::ActivePaymentsMetricsBucketValue;

use super::metrics::ActivePaymentsMetricRow;

#[derive(Debug, Default)]
pub struct ActivePaymentsMetricsAccumulator {
    pub active_payments: CountAccumulator,
}

#[derive(Debug, Default)]
#[repr(transparent)]
pub struct CountAccumulator {
    pub count: Option<i64>,
}

pub trait ActivePaymentsMetricAccumulator {
    type MetricOutput;

    fn add_metrics_bucket(&mut self, metrics: &ActivePaymentsMetricRow);

    fn collect(self) -> Self::MetricOutput;
}

impl ActivePaymentsMetricAccumulator for CountAccumulator {
    type MetricOutput = Option<u64>;
    #[inline]
    fn add_metrics_bucket(&mut self, metrics: &ActivePaymentsMetricRow) {
        self.count = match (self.count, metrics.count) {
            (None, None) => None,
            (None, i @ Some(_)) | (i @ Some(_), None) => i,
            (Some(a), Some(b)) => Some(a + b),
        }
    }
    #[inline]
    fn collect(self) -> Self::MetricOutput {
        self.count.and_then(|i| u64::try_from(i).ok())
    }
}

impl ActivePaymentsMetricsAccumulator {
    #[allow(dead_code)]
    pub fn collect(self) -> ActivePaymentsMetricsBucketValue {
        ActivePaymentsMetricsBucketValue {
            active_payments: self.active_payments.collect(),
        }
    }
}


// Function: validate_payment_method_update
// File: crates/router/src/core/payment_methods/cards.rs
// Module: router

pub fn validate_payment_method_update(
    _card_updation_obj: CardDetailUpdate,
    _existing_card_data: api::CardDetailFromLocker,
) -> bool


// Struct: NuveiTransactionSyncResponse
// File: crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 1

pub struct NuveiTransactionSyncResponse


// Struct: Metadata
// File: crates/hyperswitch_connectors/src/connectors/affirm/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct Metadata


// Function: update_with_attempt_id
// File: crates/diesel_models/src/query/fraud_check.rs
// Module: diesel_models

pub fn update_with_attempt_id(
        self,
        conn: &PgPooledConn,
        fraud_check: FraudCheckUpdate,
    ) -> StorageResult<Self>


// Function: is_refund_event
// File: crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs
// Module: hyperswitch_connectors

pub fn is_refund_event(event_code: &WebhookEventType) -> bool


// Struct: PlaidBankAccountCredentialsRequest
// File: crates/pm_auth/src/connector/plaid/transformers.rs
// Module: pm_auth
// Implementations: 0

pub struct PlaidBankAccountCredentialsRequest


// Implementation: impl api::PaymentCapture for for Razorpay
// File: crates/hyperswitch_connectors/src/connectors/razorpay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentCapture for for Razorpay


// Implementation: impl DummyConnectors
// File: crates/router/src/routes/dummy_connector/types.rs
// Module: router
// Methods: 1 total (1 public)

impl DummyConnectors


// Implementation: impl CycleCheck
// File: crates/hyperswitch_constraint_graph/src/types.rs
// Module: hyperswitch_constraint_graph
// Methods: 1 total (1 public)

impl CycleCheck


// Function: retrieve_payment_method
// File: crates/router/src/core/payment_methods.rs
// Module: router

pub fn retrieve_payment_method(
    state: SessionState,
    pm: api::PaymentMethodId,
    merchant_context: domain::MerchantContext,
) -> RouterResponse<api::PaymentMethodResponse>


// Struct: AuthEventFilterRow
// File: crates/analytics/src/auth_events/filters.rs
// Module: analytics
// Implementations: 0

pub struct AuthEventFilterRow


// Struct: ListProfilesForUserInOrgAndMerchantAccountResponse
// File: crates/api_models/src/user.rs
// Module: api_models
// Implementations: 0

pub struct ListProfilesForUserInOrgAndMerchantAccountResponse


// Function: list_initial_webhook_delivery_attempts_with_jwtauth
// File: crates/openapi/src/routes/webhook_events.rs
// Module: openapi

pub fn list_initial_webhook_delivery_attempts_with_jwtauth()


// Implementation: impl api::PaymentSession for for Facilitapay
// File: crates/hyperswitch_connectors/src/connectors/facilitapay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentSession for for Facilitapay


// Function: vault_payment_method_internal
// File: crates/router/src/core/payment_methods.rs
// Module: router

pub fn vault_payment_method_internal(
    state: &SessionState,
    pmd: &domain::PaymentMethodVaultingData,
    merchant_context: &domain::MerchantContext,
    existing_vault_id: Option<domain::VaultId>,
    customer_id: &id_type::GlobalCustomerId,
) -> RouterResult<pm_types::AddVaultResponse>


// Function: generate_fingerprint
// File: crates/router/src/core/card_testing_guard/utils.rs
// Module: router

pub fn generate_fingerprint(
    payment_method_data: Option<&api_models::payments::PaymentMethodData>,
    business_profile: &domain::Profile,
) -> RouterResult<Secret<String>>