        Ok(Secret::new(encrypted_data.token.clone()))
    }
}

pub trait CryptoData {
    fn get_pay_currency(&self) -> Result<String, Error>;
}

impl CryptoData for domain::CryptoData {
    fn get_pay_currency(&self) -> Result<String, Error> {
        self.pay_currency
            .clone()
            .ok_or_else(missing_field_err("crypto_data.pay_currency"))
    }
}

pub trait PhoneDetailsData {
    fn get_number(&self) -> Result<Secret<String>, Error>;
    fn get_country_code(&self) -> Result<String, Error>;
    fn get_number_with_country_code(&self) -> Result<Secret<String>, Error>;
    fn get_number_with_hash_country_code(&self) -> Result<Secret<String>, Error>;
    fn extract_country_code(&self) -> Result<String, Error>;
}

impl PhoneDetailsData for hyperswitch_domain_models::address::PhoneDetails {
    fn get_country_code(&self) -> Result<String, Error> {
        self.country_code
            .clone()
            .ok_or_else(missing_field_err("billing.phone.country_code"))
    }
    fn extract_country_code(&self) -> Result<String, Error> {
        self.get_country_code()
            .map(|cc| cc.trim_start_matches('+').to_string())
    }
    fn get_number(&self) -> Result<Secret<String>, Error> {
        self.number
            .clone()
            .ok_or_else(missing_field_err("billing.phone.number"))
    }
    fn get_number_with_country_code(&self) -> Result<Secret<String>, Error> {
        let number = self.get_number()?;
        let country_code = self.get_country_code()?;
        Ok(Secret::new(format!("{}{}", country_code, number.peek())))
    }
    fn get_number_with_hash_country_code(&self) -> Result<Secret<String>, Error> {
        let number = self.get_number()?;
        let country_code = self.get_country_code()?;
        let number_without_plus = country_code.trim_start_matches('+');
        Ok(Secret::new(format!(
            "{}#{}",
            number_without_plus,
            number.peek()
        )))
    }
}

pub trait AddressDetailsData {
    fn get_first_name(&self) -> Result<&Secret<String>, Error>;
    fn get_last_name(&self) -> Result<&Secret<String>, Error>;
    fn get_full_name(&self) -> Result<Secret<String>, Error>;
    fn get_line1(&self) -> Result<&Secret<String>, Error>;
    fn get_city(&self) -> Result<&String, Error>;
    fn get_line2(&self) -> Result<&Secret<String>, Error>;
    fn get_state(&self) -> Result<&Secret<String>, Error>;
    fn get_zip(&self) -> Result<&Secret<String>, Error>;
    fn get_country(&self) -> Result<&api_models::enums::CountryAlpha2, Error>;
    fn get_combined_address_line(&self) -> Result<Secret<String>, Error>;
    fn get_optional_line2(&self) -> Option<Secret<String>>;
    fn get_optional_country(&self) -> Option<api_models::enums::CountryAlpha2>;
}

impl AddressDetailsData for hyperswitch_domain_models::address::AddressDetails {
    fn get_first_name(&self) -> Result<&Secret<String>, Error> {
        self.first_name
            .as_ref()
            .ok_or_else(missing_field_err("address.first_name"))
    }

    fn get_last_name(&self) -> Result<&Secret<String>, Error> {
        self.last_name
            .as_ref()
            .ok_or_else(missing_field_err("address.last_name"))
    }

    fn get_full_name(&self) -> Result<Secret<String>, Error> {
        let first_name = self.get_first_name()?.peek().to_owned();
        let last_name = self
            .get_last_name()
            .ok()
            .cloned()
            .unwrap_or(Secret::new("".to_string()));
        let last_name = last_name.peek();
        let full_name = format!("{first_name} {last_name}").trim().to_string();
        Ok(Secret::new(full_name))
    }

    fn get_line1(&self) -> Result<&Secret<String>, Error> {
        self.line1
            .as_ref()
            .ok_or_else(missing_field_err("address.line1"))
    }

    fn get_city(&self) -> Result<&String, Error> {
        self.city
            .as_ref()
            .ok_or_else(missing_field_err("address.city"))
    }

    fn get_state(&self) -> Result<&Secret<String>, Error> {
        self.state
            .as_ref()
            .ok_or_else(missing_field_err("address.state"))
    }

    fn get_line2(&self) -> Result<&Secret<String>, Error> {
        self.line2
            .as_ref()
            .ok_or_else(missing_field_err("address.line2"))
    }

    fn get_zip(&self) -> Result<&Secret<String>, Error> {
        self.zip
            .as_ref()
            .ok_or_else(missing_field_err("address.zip"))
    }

    fn get_country(&self) -> Result<&api_models::enums::CountryAlpha2, Error> {
        self.country
            .as_ref()
            .ok_or_else(missing_field_err("address.country"))
    }

    fn get_combined_address_line(&self) -> Result<Secret<String>, Error> {
        Ok(Secret::new(format!(
            "{},{}",
            self.get_line1()?.peek(),
            self.get_line2()?.peek()
        )))
    }

    fn get_optional_line2(&self) -> Option<Secret<String>> {
        self.line2.clone()
    }
    fn get_optional_country(&self) -> Option<api_models::enums::CountryAlpha2> {
        self.country
    }
}

pub trait MandateData {
    fn get_end_date(&self, format: date_time::DateFormat) -> Result<String, Error>;
    fn get_metadata(&self) -> Result<pii::SecretSerdeValue, Error>;
}

impl MandateData for payments::MandateAmountData {
    fn get_end_date(&self, format: date_time::DateFormat) -> Result<String, Error> {
        let date = self.end_date.ok_or_else(missing_field_err(
            "mandate_data.mandate_type.{multi_use|single_use}.end_date",
        ))?;
        date_time::format_date(date, format)
            .change_context(errors::ConnectorError::DateFormattingFailed)
    }
    fn get_metadata(&self) -> Result<pii::SecretSerdeValue, Error> {
        self.metadata.clone().ok_or_else(missing_field_err(
            "mandate_data.mandate_type.{multi_use|single_use}.metadata",
        ))
    }
}

pub trait RecurringMandateData {
    fn get_original_payment_amount(&self) -> Result<i64, Error>;
    fn get_original_payment_currency(&self) -> Result<enums::Currency, Error>;
}

impl RecurringMandateData for types::RecurringMandatePaymentData {
    fn get_original_payment_amount(&self) -> Result<i64, Error> {
        self.original_payment_authorized_amount
            .ok_or_else(missing_field_err("original_payment_authorized_amount"))
    }
    fn get_original_payment_currency(&self) -> Result<enums::Currency, Error> {
        self.original_payment_authorized_currency
            .ok_or_else(missing_field_err("original_payment_authorized_currency"))
    }
}

pub trait MandateReferenceData {
    fn get_connector_mandate_id(&self) -> Result<String, Error>;
}

impl MandateReferenceData for payments::ConnectorMandateReferenceId {
    fn get_connector_mandate_id(&self) -> Result<String, Error> {
        self.get_connector_mandate_id()
            .ok_or_else(missing_field_err("mandate_id"))
    }
}

pub fn get_header_key_value<'a>(
    key: &str,
    headers: &'a actix_web::http::header::HeaderMap,
) -> CustomResult<&'a str, errors::ConnectorError> {
    get_header_field(headers.get(key))
}

fn get_header_field(
    field: Option<&http::HeaderValue>,
) -> CustomResult<&str, errors::ConnectorError> {
    field
        .map(|header_value| {
            header_value
                .to_str()
                .change_context(errors::ConnectorError::WebhookSignatureNotFound)
        })
        .ok_or(report!(
            errors::ConnectorError::WebhookSourceVerificationFailed
        ))?
}

pub fn to_connector_meta<T>(connector_meta: Option<serde_json::Value>) -> Result<T, Error>
where
    T: serde::de::DeserializeOwned,
{
    let json = connector_meta.ok_or_else(missing_field_err("connector_meta_data"))?;
    json.parse_value(std::any::type_name::<T>()).switch()
}

pub fn to_connector_meta_from_secret<T>(
    connector_meta: Option<Secret<serde_json::Value>>,
) -> Result<T, Error>
where
    T: serde::de::DeserializeOwned,
{
    let connector_meta_secret =
        connector_meta.ok_or_else(missing_field_err("connector_meta_data"))?;
    let json = connector_meta_secret.expose();
    json.parse_value(std::any::type_name::<T>()).switch()
}

impl ForeignTryFrom<String> for UsStatesAbbreviation {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(value: String) -> Result<Self, Self::Error> {
        let state_abbreviation_check =
            StringExt::<Self>::parse_enum(value.to_uppercase().clone(), "UsStatesAbbreviation");

        match state_abbreviation_check {
            Ok(state_abbreviation) => Ok(state_abbreviation),
            Err(_) => {
                let binding = value.as_str().to_lowercase();
                let state = binding.as_str();
                match state {
                    "alabama" => Ok(Self::AL),
                    "alaska" => Ok(Self::AK),
                    "american samoa" => Ok(Self::AS),
                    "arizona" => Ok(Self::AZ),
                    "arkansas" => Ok(Self::AR),
                    "california" => Ok(Self::CA),
                    "colorado" => Ok(Self::CO),
                    "connecticut" => Ok(Self::CT),
                    "delaware" => Ok(Self::DE),
                    "district of columbia" | "columbia" => Ok(Self::DC),
                    "federated states of micronesia" | "micronesia" => Ok(Self::FM),
                    "florida" => Ok(Self::FL),
                    "georgia" => Ok(Self::GA),
                    "guam" => Ok(Self::GU),
                    "hawaii" => Ok(Self::HI),
                    "idaho" => Ok(Self::ID),
                    "illinois" => Ok(Self::IL),
                    "indiana" => Ok(Self::IN),
                    "iowa" => Ok(Self::IA),
                    "kansas" => Ok(Self::KS),
                    "kentucky" => Ok(Self::KY),
                    "louisiana" => Ok(Self::LA),
                    "maine" => Ok(Self::ME),
                    "marshall islands" => Ok(Self::MH),
                    "maryland" => Ok(Self::MD),
                    "massachusetts" => Ok(Self::MA),
                    "michigan" => Ok(Self::MI),
                    "minnesota" => Ok(Self::MN),
                    "mississippi" => Ok(Self::MS),
                    "missouri" => Ok(Self::MO),
                    "montana" => Ok(Self::MT),
                    "nebraska" => Ok(Self::NE),
                    "nevada" => Ok(Self::NV),
                    "new hampshire" => Ok(Self::NH),
                    "new jersey" => Ok(Self::NJ),
                    "new mexico" => Ok(Self::NM),
                    "new york" => Ok(Self::NY),
                    "north carolina" => Ok(Self::NC),
                    "north dakota" => Ok(Self::ND),
                    "northern mariana islands" => Ok(Self::MP),
                    "ohio" => Ok(Self::OH),
                    "oklahoma" => Ok(Self::OK),
                    "oregon" => Ok(Self::OR),
                    "palau" => Ok(Self::PW),
                    "pennsylvania" => Ok(Self::PA),
                    "puerto rico" => Ok(Self::PR),
                    "rhode island" => Ok(Self::RI),
                    "south carolina" => Ok(Self::SC),
                    "south dakota" => Ok(Self::SD),
                    "tennessee" => Ok(Self::TN),
                    "texas" => Ok(Self::TX),
                    "utah" => Ok(Self::UT),
                    "vermont" => Ok(Self::VT),
                    "virgin islands" => Ok(Self::VI),
                    "virginia" => Ok(Self::VA),
                    "washington" => Ok(Self::WA),
                    "west virginia" => Ok(Self::WV),
                    "wisconsin" => Ok(Self::WI),
                    "wyoming" => Ok(Self::WY),
                    _ => Err(errors::ConnectorError::InvalidDataFormat {
                        field_name: "address.state",
                    }
                    .into()),
                }
            }
        }
    }
}

impl ForeignTryFrom<String> for CanadaStatesAbbreviation {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn foreign_try_from(value: String) -> Result<Self, Self::Error> {
        let state_abbreviation_check =
            StringExt::<Self>::parse_enum(value.to_uppercase().clone(), "CanadaStatesAbbreviation");
        match state_abbreviation_check {
            Ok(state_abbreviation) => Ok(state_abbreviation),
            Err(_) => {
                let binding = value.as_str().to_lowercase();
                let state = binding.as_str();
                match state {
                    "alberta" => Ok(Self::AB),
                    "british columbia" => Ok(Self::BC),
                    "manitoba" => Ok(Self::MB),
                    "new brunswick" => Ok(Self::NB),
                    "newfoundland and labrador" | "newfoundland & labrador" => Ok(Self::NL),
                    "northwest territories" => Ok(Self::NT),
                    "nova scotia" => Ok(Self::NS),
                    "nunavut" => Ok(Self::NU),
                    "ontario" => Ok(Self::ON),
                    "prince edward island" => Ok(Self::PE),
                    "quebec" => Ok(Self::QC),
                    "saskatchewan" => Ok(Self::SK),
                    "yukon" => Ok(Self::YT),
                    _ => Err(errors::ConnectorError::InvalidDataFormat {
                        field_name: "address.state",
                    }
                    .into()),
                }
            }
        }
    }
}

pub trait ConnectorErrorTypeMapping {
    fn get_connector_error_type(
        &self,
        _error_code: String,
        _error_message: String,
    ) -> ConnectorErrorType {
        ConnectorErrorType::UnknownError
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ErrorCodeAndMessage {
    pub error_code: String,
    pub error_message: String,
}

#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
//Priority of connector_error_type
pub enum ConnectorErrorType {
    UserError = 2,
    BusinessError = 3,
    TechnicalError = 4,
    UnknownError = 1,
}

//Gets the list of error_code_and_message, sorts based on the priority of error_type and gives most prior error
// This could be used in connectors where we get list of error_messages and have to choose one error_message
pub fn get_error_code_error_message_based_on_priority(
    connector: impl ConnectorErrorTypeMapping,
    error_list: Vec<ErrorCodeAndMessage>,
) -> Option<ErrorCodeAndMessage> {
    let error_type_list = error_list
        .iter()
        .map(|error| {
            connector
                .get_connector_error_type(error.error_code.clone(), error.error_message.clone())
        })
        .collect::<Vec<ConnectorErrorType>>();
    let mut error_zip_list = error_list
        .iter()
        .zip(error_type_list.iter())
        .collect::<Vec<(&ErrorCodeAndMessage, &ConnectorErrorType)>>();
    error_zip_list.sort_by_key(|&(_, error_type)| error_type);
    error_zip_list
        .first()
        .map(|&(error_code_message, _)| error_code_message)
        .cloned()
}

pub trait MultipleCaptureSyncResponse {
    fn get_connector_capture_id(&self) -> String;
    fn get_capture_attempt_status(&self) -> enums::AttemptStatus;
    fn is_capture_response(&self) -> bool;
    fn get_connector_reference_id(&self) -> Option<String> {
        None
    }
    fn get_amount_captured(&self) -> Result<Option<MinorUnit>, error_stack::Report<ParsingError>>;
}

#[cfg(feature = "frm")]
pub trait FraudCheckSaleRequest {
    fn get_order_details(&self) -> Result<Vec<OrderDetailsWithAmount>, Error>;
}
#[cfg(feature = "frm")]
impl FraudCheckSaleRequest for fraud_check::FraudCheckSaleData {
    fn get_order_details(&self) -> Result<Vec<OrderDetailsWithAmount>, Error> {
        self.order_details
            .clone()
            .ok_or_else(missing_field_err("order_details"))
    }
}

#[cfg(feature = "frm")]
pub trait FraudCheckRecordReturnRequest {
    fn get_currency(&self) -> Result<storage_enums::Currency, Error>;
}
#[cfg(feature = "frm")]
impl FraudCheckRecordReturnRequest for fraud_check::FraudCheckRecordReturnData {
    fn get_currency(&self) -> Result<storage_enums::Currency, Error> {
        self.currency.ok_or_else(missing_field_err("currency"))
    }
}

#[cfg(feature = "v1")]
pub trait PaymentsAttemptData {
    fn get_browser_info(&self)
        -> Result<BrowserInformation, error_stack::Report<ApiErrorResponse>>;
}

#[cfg(feature = "v1")]
impl PaymentsAttemptData for PaymentAttempt {
    fn get_browser_info(
        &self,
    ) -> Result<BrowserInformation, error_stack::Report<ApiErrorResponse>> {
        self.browser_info
            .clone()
            .ok_or(ApiErrorResponse::InvalidDataValue {
                field_name: "browser_info",
            })?
            .parse_value::<BrowserInformation>("BrowserInformation")
            .change_context(ApiErrorResponse::InvalidDataValue {
                field_name: "browser_info",
            })
    }
}

#[cfg(feature = "frm")]
pub trait FrmTransactionRouterDataRequest {
    fn is_payment_successful(&self) -> Option<bool>;
}

#[cfg(feature = "frm")]
impl FrmTransactionRouterDataRequest for fraud_check::FrmTransactionRouterData {
    fn is_payment_successful(&self) -> Option<bool> {
        match self.status {
            storage_enums::AttemptStatus::AuthenticationFailed
            | storage_enums::AttemptStatus::RouterDeclined
            | storage_enums::AttemptStatus::AuthorizationFailed
            | storage_enums::AttemptStatus::Voided
            | storage_enums::AttemptStatus::VoidedPostCharge
            | storage_enums::AttemptStatus::CaptureFailed
            | storage_enums::AttemptStatus::Failure
            | storage_enums::AttemptStatus::AutoRefunded
            | storage_enums::AttemptStatus::Expired => Some(false),

            storage_enums::AttemptStatus::AuthenticationSuccessful
            | storage_enums::AttemptStatus::PartialChargedAndChargeable
            | storage_enums::AttemptStatus::Authorized
            | storage_enums::AttemptStatus::Charged
            | storage_enums::AttemptStatus::PartiallyAuthorized => Some(true),

            storage_enums::AttemptStatus::Started
            | storage_enums::AttemptStatus::AuthenticationPending
            | storage_enums::AttemptStatus::Authorizing
            | storage_enums::AttemptStatus::CodInitiated
            | storage_enums::AttemptStatus::VoidInitiated
            | storage_enums::AttemptStatus::CaptureInitiated
            | storage_enums::AttemptStatus::VoidFailed
            | storage_enums::AttemptStatus::PartialCharged
            | storage_enums::AttemptStatus::Unresolved
            | storage_enums::AttemptStatus::Pending
            | storage_enums::AttemptStatus::PaymentMethodAwaited
            | storage_enums::AttemptStatus::ConfirmationAwaited
            | storage_enums::AttemptStatus::DeviceDataCollectionPending
            | storage_enums::AttemptStatus::IntegrityFailure => None,
        }
    }
}

pub fn is_payment_failure(status: enums::AttemptStatus) -> bool {
    match status {
        common_enums::AttemptStatus::AuthenticationFailed
        | common_enums::AttemptStatus::AuthorizationFailed
        | common_enums::AttemptStatus::CaptureFailed
        | common_enums::AttemptStatus::VoidFailed
        | common_enums::AttemptStatus::Failure
        | common_enums::AttemptStatus::Expired => true,
        common_enums::AttemptStatus::Started
        | common_enums::AttemptStatus::RouterDeclined
        | common_enums::AttemptStatus::AuthenticationPending
        | common_enums::AttemptStatus::AuthenticationSuccessful
        | common_enums::AttemptStatus::Authorized
        | common_enums::AttemptStatus::Charged
        | common_enums::AttemptStatus::Authorizing
        | common_enums::AttemptStatus::CodInitiated
        | common_enums::AttemptStatus::Voided
        | common_enums::AttemptStatus::VoidedPostCharge
        | common_enums::AttemptStatus::VoidInitiated
        | common_enums::AttemptStatus::CaptureInitiated
        | common_enums::AttemptStatus::AutoRefunded
        | common_enums::AttemptStatus::PartialCharged
        | common_enums::AttemptStatus::PartialChargedAndChargeable
        | common_enums::AttemptStatus::Unresolved
        | common_enums::AttemptStatus::Pending
        | common_enums::AttemptStatus::PaymentMethodAwaited
        | common_enums::AttemptStatus::ConfirmationAwaited
        | common_enums::AttemptStatus::DeviceDataCollectionPending
        | common_enums::AttemptStatus::IntegrityFailure
        | common_enums::AttemptStatus::PartiallyAuthorized => false,
    }
}

pub fn is_refund_failure(status: enums::RefundStatus) -> bool {
    match status {
        common_enums::RefundStatus::Failure | common_enums::RefundStatus::TransactionFailure => {
            true
        }
        common_enums::RefundStatus::ManualReview
        | common_enums::RefundStatus::Pending
        | common_enums::RefundStatus::Success => false,
    }
}

impl
    ForeignFrom<(
        Option<String>,
        Option<String>,
        Option<String>,
        u16,
        Option<enums::AttemptStatus>,
        Option<String>,
    )> for types::ErrorResponse
{
    fn foreign_from(
        (code, message, reason, http_code, attempt_status, connector_transaction_id): (
            Option<String>,
            Option<String>,
            Option<String>,
            u16,
            Option<enums::AttemptStatus>,
            Option<String>,
        ),
    ) -> Self {
        Self {
            code: code.unwrap_or(consts::NO_ERROR_CODE.to_string()),
            message: message
                .clone()
                .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()),
            reason,
            status_code: http_code,
            attempt_status,
            connector_transaction_id,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        }
    }
}

pub fn get_card_details(
    payment_method_data: domain::PaymentMethodData,
    connector_name: &'static str,
) -> Result<domain::payments::Card, errors::ConnectorError> {
    match payment_method_data {
        domain::PaymentMethodData::Card(details) => Ok(details),
        _ => Err(errors::ConnectorError::NotSupported {
            message: SELECTED_PAYMENT_METHOD.to_string(),
            connector: connector_name,
        })?,
    }
}

#[cfg(test)]
mod error_code_error_message_tests {
    #![allow(clippy::unwrap_used)]
    use super::*;

    struct TestConnector;

    impl ConnectorErrorTypeMapping for TestConnector {
        fn get_connector_error_type(
            &self,
            error_code: String,
            error_message: String,
        ) -> ConnectorErrorType {
            match (error_code.as_str(), error_message.as_str()) {
                ("01", "INVALID_MERCHANT") => ConnectorErrorType::BusinessError,
                ("03", "INVALID_CVV") => ConnectorErrorType::UserError,
                ("04", "04") => ConnectorErrorType::TechnicalError,
                _ => ConnectorErrorType::UnknownError,
            }
        }
    }

    #[test]
    fn test_get_error_code_error_message_based_on_priority() {
        let error_code_message_list_unknown = vec![
            ErrorCodeAndMessage {
                error_code: "01".to_string(),
                error_message: "INVALID_MERCHANT".to_string(),
            },
            ErrorCodeAndMessage {
                error_code: "05".to_string(),
                error_message: "05".to_string(),
            },
            ErrorCodeAndMessage {
                error_code: "03".to_string(),
                error_message: "INVALID_CVV".to_string(),
            },
            ErrorCodeAndMessage {
                error_code: "04".to_string(),
                error_message: "04".to_string(),
            },
        ];
        let error_code_message_list_user = vec![
            ErrorCodeAndMessage {
                error_code: "01".to_string(),
                error_message: "INVALID_MERCHANT".to_string(),
            },
            ErrorCodeAndMessage {
                error_code: "03".to_string(),
                error_message: "INVALID_CVV".to_string(),
            },
        ];
        let error_code_error_message_unknown = get_error_code_error_message_based_on_priority(
            TestConnector,
            error_code_message_list_unknown,
        );
        let error_code_error_message_user = get_error_code_error_message_based_on_priority(
            TestConnector,
            error_code_message_list_user,
        );
        let error_code_error_message_none =
            get_error_code_error_message_based_on_priority(TestConnector, vec![]);
        assert_eq!(
            error_code_error_message_unknown,
            Some(ErrorCodeAndMessage {
                error_code: "05".to_string(),
                error_message: "05".to_string(),
            })
        );
        assert_eq!(
            error_code_error_message_user,
            Some(ErrorCodeAndMessage {
                error_code: "03".to_string(),
                error_message: "INVALID_CVV".to_string(),
            })
        );
        assert_eq!(error_code_error_message_none, None);
    }
}

pub fn is_mandate_supported(
    selected_pmd: domain::payments::PaymentMethodData,
    payment_method_type: Option<types::storage::enums::PaymentMethodType>,
    mandate_implemented_pmds: HashSet<PaymentMethodDataType>,
    connector: &'static str,
) -> Result<(), Error> {
    if mandate_implemented_pmds.contains(&PaymentMethodDataType::from(selected_pmd.clone())) {
        Ok(())
    } else {
        match payment_method_type {
            Some(pm_type) => Err(errors::ConnectorError::NotSupported {
                message: format!("{pm_type} mandate payment"),
                connector,
            }
            .into()),
            None => Err(errors::ConnectorError::NotSupported {
                message: " mandate payment".to_string(),
                connector,
            }
            .into()),
        }
    }
}

#[derive(Debug, strum::Display, Eq, PartialEq, Hash)]
pub enum PaymentMethodDataType {
    Card,
    Knet,
    Benefit,
    MomoAtm,
    CardRedirect,
    AliPayQr,
    AliPayRedirect,
    AliPayHkRedirect,
    AmazonPay,
    AmazonPayRedirect,
    Paysera,
    Skrill,
    MomoRedirect,
    KakaoPayRedirect,
    GoPayRedirect,
    GcashRedirect,
    ApplePay,
    ApplePayRedirect,
    ApplePayThirdPartySdk,
    DanaRedirect,
    DuitNow,
    GooglePay,
    Bluecode,
    GooglePayRedirect,
    GooglePayThirdPartySdk,
    MbWayRedirect,
    MobilePayRedirect,
    PaypalRedirect,
    PaypalSdk,
    Paze,
    SamsungPay,
    TwintRedirect,
    VippsRedirect,
    TouchNGoRedirect,
    WeChatPayRedirect,
    WeChatPayQr,
    CashappQr,
    SwishQr,
    KlarnaRedirect,
    KlarnaSdk,
    AffirmRedirect,
    AfterpayClearpayRedirect,
    PayBrightRedirect,
    WalleyRedirect,
    AlmaRedirect,
    AtomeRedirect,
    BreadpayRedirect,
    FlexitiRedirect,
    BancontactCard,
    Bizum,
    Blik,
    Eft,
    Eps,
    Giropay,
    Ideal,
    Interac,
    LocalBankRedirect,
    OnlineBankingCzechRepublic,
    OnlineBankingFinland,
    OnlineBankingPoland,
    OnlineBankingSlovakia,
    OpenBankingUk,
    Przelewy24,
    Sofort,
    Trustly,
    OnlineBankingFpx,
    OnlineBankingThailand,
    AchBankDebit,
    SepaBankDebit,
    BecsBankDebit,
    BacsBankDebit,
    AchBankTransfer,
    SepaBankTransfer,
    BacsBankTransfer,
    MultibancoBankTransfer,
    PermataBankTransfer,
    BcaBankTransfer,
    BniVaBankTransfer,
    BriVaBankTransfer,
    CimbVaBankTransfer,
    DanamonVaBankTransfer,
    MandiriVaBankTransfer,
    Pix,
    Pse,
    Crypto,
    MandatePayment,
    Reward,
    Upi,
    Boleto,
    Efecty,
    PagoEfectivo,
    RedCompra,
    RedPagos,
    Alfamart,
    Indomaret,
    Oxxo,
    SevenEleven,
    Lawson,
    MiniStop,
    FamilyMart,
    Seicomart,
    PayEasy,
    Givex,
    BhnCardNetwork,
    PaySafeCar,
    CardToken,
    LocalBankTransfer,
    Mifinity,
    Fps,
    PromptPay,
    VietQr,
    OpenBanking,
    NetworkToken,
    DirectCarrierBilling,
    InstantBankTransfer,
    InstantBankTransferFinland,
    InstantBankTransferPoland,
    RevolutPay,
    IndonesianBankTransfer,
}

impl From<domain::payments::PaymentMethodData> for PaymentMethodDataType {
    fn from(pm_data: domain::payments::PaymentMethodData) -> Self {
        match pm_data {
            domain::payments::PaymentMethodData::Card(_) => Self::Card,
            domain::payments::PaymentMethodData::NetworkToken(_) => Self::NetworkToken,
            domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) => Self::Card,
            domain::payments::PaymentMethodData::CardRedirect(card_redirect_data) => {
                match card_redirect_data {
                    domain::CardRedirectData::Knet {} => Self::Knet,
                    domain::payments::CardRedirectData::Benefit {} => Self::Benefit,
                    domain::payments::CardRedirectData::MomoAtm {} => Self::MomoAtm,
                    domain::payments::CardRedirectData::CardRedirect {} => Self::CardRedirect,
                }
            }
            domain::payments::PaymentMethodData::Wallet(wallet_data) => match wallet_data {
                domain::payments::WalletData::AliPayQr(_) => Self::AliPayQr,
                domain::payments::WalletData::AliPayRedirect(_) => Self::AliPayRedirect,
                domain::payments::WalletData::AliPayHkRedirect(_) => Self::AliPayHkRedirect,
                domain::payments::WalletData::AmazonPay(_) => Self::AmazonPay,
                domain::payments::WalletData::AmazonPayRedirect(_) => Self::AmazonPayRedirect,
                domain::payments::WalletData::Paysera(_) => Self::Paysera,
                domain::payments::WalletData::Skrill(_) => Self::Skrill,
                domain::payments::WalletData::MomoRedirect(_) => Self::MomoRedirect,
                domain::payments::WalletData::KakaoPayRedirect(_) => Self::KakaoPayRedirect,
                domain::payments::WalletData::GoPayRedirect(_) => Self::GoPayRedirect,
                domain::payments::WalletData::GcashRedirect(_) => Self::GcashRedirect,
                domain::payments::WalletData::ApplePay(_) => Self::ApplePay,
                domain::payments::WalletData::ApplePayRedirect(_) => Self::ApplePayRedirect,
                domain::payments::WalletData::ApplePayThirdPartySdk(_) => {
                    Self::ApplePayThirdPartySdk
                }
                domain::payments::WalletData::DanaRedirect {} => Self::DanaRedirect,
                domain::payments::WalletData::GooglePay(_) => Self::GooglePay,
                domain::payments::WalletData::BluecodeRedirect {} => Self::Bluecode,
                domain::payments::WalletData::GooglePayRedirect(_) => Self::GooglePayRedirect,
                domain::payments::WalletData::GooglePayThirdPartySdk(_) => {
                    Self::GooglePayThirdPartySdk
                }
                domain::payments::WalletData::MbWayRedirect(_) => Self::MbWayRedirect,
                domain::payments::WalletData::MobilePayRedirect(_) => Self::MobilePayRedirect,
                domain::payments::WalletData::PaypalRedirect(_) => Self::PaypalRedirect,
                domain::payments::WalletData::PaypalSdk(_) => Self::PaypalSdk,
                domain::payments::WalletData::Paze(_) => Self::Paze,
                domain::payments::WalletData::SamsungPay(_) => Self::SamsungPay,
                domain::payments::WalletData::TwintRedirect {} => Self::TwintRedirect,
                domain::payments::WalletData::VippsRedirect {} => Self::VippsRedirect,
                domain::payments::WalletData::TouchNGoRedirect(_) => Self::TouchNGoRedirect,
                domain::payments::WalletData::WeChatPayRedirect(_) => Self::WeChatPayRedirect,
                domain::payments::WalletData::WeChatPayQr(_) => Self::WeChatPayQr,
                domain::payments::WalletData::CashappQr(_) => Self::CashappQr,
                domain::payments::WalletData::SwishQr(_) => Self::SwishQr,
                domain::payments::WalletData::Mifinity(_) => Self::Mifinity,
                domain::payments::WalletData::RevolutPay(_) => Self::RevolutPay,
            },
            domain::payments::PaymentMethodData::PayLater(pay_later_data) => match pay_later_data {
                domain::payments::PayLaterData::KlarnaRedirect { .. } => Self::KlarnaRedirect,
                domain::payments::PayLaterData::KlarnaSdk { .. } => Self::KlarnaSdk,
                domain::payments::PayLaterData::AffirmRedirect {} => Self::AffirmRedirect,
                domain::payments::PayLaterData::AfterpayClearpayRedirect { .. } => {
                    Self::AfterpayClearpayRedirect
                }
                domain::payments::PayLaterData::PayBrightRedirect {} => Self::PayBrightRedirect,
                domain::payments::PayLaterData::WalleyRedirect {} => Self::WalleyRedirect,
                domain::payments::PayLaterData::AlmaRedirect {} => Self::AlmaRedirect,
                domain::payments::PayLaterData::FlexitiRedirect {} => Self::FlexitiRedirect,
                domain::payments::PayLaterData::AtomeRedirect {} => Self::AtomeRedirect,
                domain::payments::PayLaterData::BreadpayRedirect {} => Self::BreadpayRedirect,
            },
            domain::payments::PaymentMethodData::BankRedirect(bank_redirect_data) => {
                match bank_redirect_data {
                    domain::payments::BankRedirectData::BancontactCard { .. } => {
                        Self::BancontactCard
                    }
                    domain::payments::BankRedirectData::Bizum {} => Self::Bizum,
                    domain::payments::BankRedirectData::Blik { .. } => Self::Blik,
                    domain::payments::BankRedirectData::Eft { .. } => Self::Eft,
                    domain::payments::BankRedirectData::Eps { .. } => Self::Eps,
                    domain::payments::BankRedirectData::Giropay { .. } => Self::Giropay,
                    domain::payments::BankRedirectData::Ideal { .. } => Self::Ideal,
                    domain::payments::BankRedirectData::Interac { .. } => Self::Interac,
                    domain::payments::BankRedirectData::OnlineBankingCzechRepublic { .. } => {
                        Self::OnlineBankingCzechRepublic
                    }
                    domain::payments::BankRedirectData::OnlineBankingFinland { .. } => {
                        Self::OnlineBankingFinland
                    }
                    domain::payments::BankRedirectData::OnlineBankingPoland { .. } => {
                        Self::OnlineBankingPoland
                    }
                    domain::payments::BankRedirectData::OnlineBankingSlovakia { .. } => {
                        Self::OnlineBankingSlovakia
                    }
                    domain::payments::BankRedirectData::OpenBankingUk { .. } => Self::OpenBankingUk,
                    domain::payments::BankRedirectData::Przelewy24 { .. } => Self::Przelewy24,
                    domain::payments::BankRedirectData::Sofort { .. } => Self::Sofort,
                    domain::payments::BankRedirectData::Trustly { .. } => Self::Trustly,
                    domain::payments::BankRedirectData::OnlineBankingFpx { .. } => {
                        Self::OnlineBankingFpx
                    }
                    domain::payments::BankRedirectData::OnlineBankingThailand { .. } => {
                        Self::OnlineBankingThailand
                    }
                    domain::payments::BankRedirectData::LocalBankRedirect { } => {
                        Self::LocalBankRedirect
                    }
                }
            }
            domain::payments::PaymentMethodData::BankDebit(bank_debit_data) => {
                match bank_debit_data {


// Struct: ApplepayMerchantVerificationConfigs
// File: crates/api_models/src/verifications.rs
// Module: api_models
// Implementations: 0

pub struct ApplepayMerchantVerificationConfigs


// Function: switch_profile_for_user_in_org_and_merchant
// File: crates/router/src/routes/user.rs
// Module: router

pub fn switch_profile_for_user_in_org_and_merchant(
    state: web::Data<AppState>,
    http_req: HttpRequest,
    json_payload: web::Json<user_api::SwitchProfileRequest>,
) -> HttpResponse


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

impl api::PaymentCapture for for Datatrans


// Implementation: impl Responder
// File: crates/router/src/routes/payments.rs
// Module: router
// Methods: 0 total (0 public)

impl Responder


// Implementation: impl api::ConnectorAccessToken for for Nordea
// File: crates/hyperswitch_connectors/src/connectors/nordea.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::ConnectorAccessToken for for Nordea


// Implementation: impl ClientSecretInterface for for KafkaStore
// File: crates/router/src/db/kafka_store.rs
// Module: router
// Methods: 3 total (0 public)

impl ClientSecretInterface for for KafkaStore


// Module Structure
// File: crates/euclid/src/backend/interpreter.rs
// Module: euclid

// Public submodules:
pub mod types;


// Struct: PixTransactionRequest
// File: crates/hyperswitch_connectors/src/connectors/facilitapay/requests.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PixTransactionRequest


// Implementation: impl MandateAmountData
// File: crates/hyperswitch_domain_models/src/mandates.rs
// Module: hyperswitch_domain_models
// Methods: 2 total (2 public)

impl MandateAmountData


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

impl api::PaymentSession for for Finix


// Struct: OutgoingWebhookRequestContent
// File: crates/api_models/src/webhook_events.rs
// Module: api_models
// Implementations: 0

pub struct OutgoingWebhookRequestContent


// Struct: GetApiEventFiltersRequest
// File: crates/api_models/src/analytics.rs
// Module: api_models
// Implementations: 0

pub struct GetApiEventFiltersRequest


// Implementation: impl HashiCorpVault
// File: crates/external_services/src/hashicorp_vault/core.rs
// Module: external_services
// Methods: 2 total (1 public)

impl HashiCorpVault


// Function: delete_all_user_scoped_dashboard_metadata_by_merchant_id
// File: crates/diesel_models/src/query/dashboard_metadata.rs
// Module: diesel_models

pub fn delete_all_user_scoped_dashboard_metadata_by_merchant_id(
        conn: &PgPooledConn,
        user_id: String,
        merchant_id: id_type::MerchantId,
    ) -> StorageResult<bool>


// Struct: MerchantAccountIdentifier
// File: crates/router/src/types/domain/user.rs
// Module: router
// Implementations: 0

pub struct MerchantAccountIdentifier


// File: crates/common_utils/src/macros.rs
// Module: common_utils
// Public functions: 4

//! Utility macros

#[allow(missing_docs)]
#[macro_export]
macro_rules! newtype_impl {
    ($is_pub:vis, $name:ident, $ty_path:path) => {
        impl core::ops::Deref for $name {
            type Target = $ty_path;

            fn deref(&self) -> &Self::Target {
                &self.0
            }
        }

        impl core::ops::DerefMut for $name {
            fn deref_mut(&mut self) -> &mut Self::Target {
                &mut self.0
            }
        }

        impl From<$ty_path> for $name {
            fn from(ty: $ty_path) -> Self {
                Self(ty)
            }
        }

        impl $name {
            pub fn into_inner(self) -> $ty_path {
                self.0
            }
        }
    };
}

#[allow(missing_docs)]
#[macro_export]
macro_rules! newtype {
    ($is_pub:vis $name:ident = $ty_path:path) => {
        $is_pub struct $name(pub $ty_path);

        $crate::newtype_impl!($is_pub, $name, $ty_path);
    };

    ($is_pub:vis $name:ident = $ty_path:path, derives = ($($trt:path),*)) => {
        #[derive($($trt),*)]
        $is_pub struct $name(pub $ty_path);

        $crate::newtype_impl!($is_pub, $name, $ty_path);
    };
}

/// Use this to ensure that the corresponding
/// openapi route has been implemented in the openapi crate
#[macro_export]
macro_rules! openapi_route {
    ($route_name: ident) => {{
        #[cfg(feature = "openapi")]
        use openapi::routes::$route_name as _;

        $route_name
    }};
}

#[allow(missing_docs)]
#[macro_export]
macro_rules! fallback_reverse_lookup_not_found {
    ($a:expr,$b:expr) => {
        match $a {
            Ok(res) => res,
            Err(err) => {
                router_env::logger::error!(reverse_lookup_fallback = ?err);
                match err.current_context() {
                    errors::StorageError::ValueNotFound(_) => return $b,
                    errors::StorageError::DatabaseError(data_err) => {
                        match data_err.current_context() {
                            diesel_models::errors::DatabaseError::NotFound => return $b,
                            _ => return Err(err)
                        }
                    }
                    _=> return Err(err)
                }
            }
        };
    };
}

/// Collects names of all optional fields that are `None`.
/// This is typically useful for constructing error messages including a list of all missing fields.
#[macro_export]
macro_rules! collect_missing_value_keys {
    [$(($key:literal, $option:expr)),+] => {
        {
            let mut keys: Vec<&'static str> = Vec::new();
            $(
                if $option.is_none() {
                    keys.push($key);
                }
            )*
            keys
        }
    };
}

/// Implements the `ToSql` and `FromSql` traits on a type to allow it to be serialized/deserialized
/// to/from JSON data in the database.
#[macro_export]
macro_rules! impl_to_sql_from_sql_json {
    ($type:ty, $diesel_type:ty) => {
        #[allow(unused_qualifications)]
        impl diesel::serialize::ToSql<$diesel_type, diesel::pg::Pg> for $type {
            fn to_sql<'b>(
                &'b self,
                out: &mut diesel::serialize::Output<'b, '_, diesel::pg::Pg>,
            ) -> diesel::serialize::Result {
                let value = serde_json::to_value(self)?;

                // the function `reborrow` only works in case of `Pg` backend. But, in case of other backends
                // please refer to the diesel migration blog:
                // https://github.com/Diesel-rs/Diesel/blob/master/guide_drafts/migration_guide.md#changed-tosql-implementations
                <serde_json::Value as diesel::serialize::ToSql<
                                                                $diesel_type,
                                                                diesel::pg::Pg,
                                                            >>::to_sql(&value, &mut out.reborrow())
            }
        }

        #[allow(unused_qualifications)]
        impl diesel::deserialize::FromSql<$diesel_type, diesel::pg::Pg> for $type {
            fn from_sql(
                bytes: <diesel::pg::Pg as diesel::backend::Backend>::RawValue<'_>,
            ) -> diesel::deserialize::Result<Self> {
                let value = <serde_json::Value as diesel::deserialize::FromSql<
                    $diesel_type,
                    diesel::pg::Pg,
                >>::from_sql(bytes)?;
                Ok(serde_json::from_value(value)?)
            }
        }
    };
    ($type: ty) => {
        $crate::impl_to_sql_from_sql_json!($type, diesel::sql_types::Json);
        $crate::impl_to_sql_from_sql_json!($type, diesel::sql_types::Jsonb);
    };
}

mod id_type {
    /// Defines an ID type.
    #[macro_export]
    macro_rules! id_type {
        ($type:ident, $doc:literal, $diesel_type:ty, $max_length:expr, $min_length:expr) => {
            #[doc = $doc]
            #[derive(
                Clone,
                Hash,
                PartialEq,
                Eq,
                serde::Serialize,
                serde::Deserialize,
                diesel::expression::AsExpression,
                utoipa::ToSchema,
            )]
            #[diesel(sql_type = $diesel_type)]
            #[schema(value_type = String)]
            pub struct $type($crate::id_type::LengthId<$max_length, $min_length>);
        };
        ($type:ident, $doc:literal) => {
            $crate::id_type!(
                $type,
                $doc,
                diesel::sql_types::Text,
                { $crate::consts::MAX_ALLOWED_MERCHANT_REFERENCE_ID_LENGTH },
                { $crate::consts::MIN_REQUIRED_MERCHANT_REFERENCE_ID_LENGTH }
            );
        };
    }

    /// Defines a Global Id type
    #[cfg(feature = "v2")]
    #[macro_export]
    macro_rules! global_id_type {
        ($type:ident, $doc:literal) => {
            #[doc = $doc]
            #[derive(
                Debug,
                Clone,
                Hash,
                PartialEq,
                Eq,
                serde::Serialize,
                serde::Deserialize,
                diesel::expression::AsExpression,
            )]
            #[diesel(sql_type = diesel::sql_types::Text)]
            pub struct $type($crate::id_type::global_id::GlobalId);
        };
    }

    /// Implements common methods on the specified ID type.
    #[macro_export]
    macro_rules! impl_id_type_methods {
        ($type:ty, $field_name:literal) => {
            impl $type {
                /// Get the string representation of the ID type.
                pub fn get_string_repr(&self) -> &str {
                    &self.0 .0 .0
                }
            }
        };
    }

    /// Implements the `Debug` trait on the specified ID type.
    #[macro_export]
    macro_rules! impl_debug_id_type {
        ($type:ty) => {
            impl core::fmt::Debug for $type {
                fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
                    f.debug_tuple(stringify!($type))
                        .field(&self.0 .0 .0)
                        .finish()
                }
            }
        };
    }

    /// Implements the `TryFrom<Cow<'static, str>>` trait on the specified ID type.
    #[macro_export]
    macro_rules! impl_try_from_cow_str_id_type {
        ($type:ty, $field_name:literal) => {
            impl TryFrom<std::borrow::Cow<'static, str>> for $type {
                type Error = error_stack::Report<$crate::errors::ValidationError>;

                fn try_from(value: std::borrow::Cow<'static, str>) -> Result<Self, Self::Error> {
                    use error_stack::ResultExt;

                    let merchant_ref_id = $crate::id_type::LengthId::from(value).change_context(
                        $crate::errors::ValidationError::IncorrectValueProvided {
                            field_name: $field_name,
                        },
                    )?;

                    Ok(Self(merchant_ref_id))
                }
            }
        };
    }

    /// Implements the `Default` trait on the specified ID type.
    #[macro_export]
    macro_rules! impl_default_id_type {
        ($type:ty, $prefix:literal) => {
            impl Default for $type {
                fn default() -> Self {
                    Self($crate::generate_ref_id_with_default_length($prefix))
                }
            }
        };
    }

    /// Implements the `GenerateId` trait on the specified ID type.
    #[macro_export]
    macro_rules! impl_generate_id_id_type {
        ($type:ty, $prefix:literal) => {
            impl $crate::id_type::GenerateId for $type {
                fn generate() -> Self {
                    Self($crate::generate_ref_id_with_default_length($prefix))
                }
            }
        };
    }

    /// Implements the `SerializableSecret` trait on the specified ID type.
    #[macro_export]
    macro_rules! impl_serializable_secret_id_type {
        ($type:ty) => {
            impl masking::SerializableSecret for $type {}
        };
    }

    /// Implements the `ToSql` and `FromSql` traits on the specified ID type.
    #[macro_export]
    macro_rules! impl_to_sql_from_sql_id_type {
        ($type:ty, $diesel_type:ty, $max_length:expr, $min_length:expr) => {
            impl<DB> diesel::serialize::ToSql<$diesel_type, DB> for $type
            where
                DB: diesel::backend::Backend,
                $crate::id_type::LengthId<$max_length, $min_length>:
                    diesel::serialize::ToSql<$diesel_type, DB>,
            {
                fn to_sql<'b>(
                    &'b self,
                    out: &mut diesel::serialize::Output<'b, '_, DB>,
                ) -> diesel::serialize::Result {
                    self.0.to_sql(out)
                }
            }

            impl<DB> diesel::deserialize::FromSql<$diesel_type, DB> for $type
            where
                DB: diesel::backend::Backend,
                $crate::id_type::LengthId<$max_length, $min_length>:
                    diesel::deserialize::FromSql<$diesel_type, DB>,
            {
                fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
                    $crate::id_type::LengthId::<$max_length, $min_length>::from_sql(value).map(Self)
                }
            }
        };
        ($type:ty) => {
            $crate::impl_to_sql_from_sql_id_type!(
                $type,
                diesel::sql_types::Text,
                { $crate::consts::MAX_ALLOWED_MERCHANT_REFERENCE_ID_LENGTH },
                { $crate::consts::MIN_REQUIRED_MERCHANT_REFERENCE_ID_LENGTH }
            );
        };
    }

    #[cfg(feature = "v2")]
    /// Implements the `ToSql` and `FromSql` traits on the specified Global ID type.
    #[macro_export]
    macro_rules! impl_to_sql_from_sql_global_id_type {
        ($type:ty, $diesel_type:ty) => {
            impl<DB> diesel::serialize::ToSql<$diesel_type, DB> for $type
            where
                DB: diesel::backend::Backend,
                $crate::id_type::global_id::GlobalId: diesel::serialize::ToSql<$diesel_type, DB>,
            {
                fn to_sql<'b>(
                    &'b self,
                    out: &mut diesel::serialize::Output<'b, '_, DB>,
                ) -> diesel::serialize::Result {
                    self.0.to_sql(out)
                }
            }

            impl<DB> diesel::deserialize::FromSql<$diesel_type, DB> for $type
            where
                DB: diesel::backend::Backend,
                $crate::id_type::global_id::GlobalId:
                    diesel::deserialize::FromSql<$diesel_type, DB>,
            {
                fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result<Self> {
                    $crate::id_type::global_id::GlobalId::from_sql(value).map(Self)
                }
            }
        };
        ($type:ty) => {
            $crate::impl_to_sql_from_sql_global_id_type!($type, diesel::sql_types::Text);
        };
    }

    /// Implements the `Queryable` trait on the specified ID type.
    #[macro_export]
    macro_rules! impl_queryable_id_type {
        ($type:ty, $diesel_type:ty) => {
            impl<DB> diesel::Queryable<$diesel_type, DB> for $type
            where
                DB: diesel::backend::Backend,
                Self: diesel::deserialize::FromSql<$diesel_type, DB>,
            {
                type Row = Self;

                fn build(row: Self::Row) -> diesel::deserialize::Result<Self> {
                    Ok(row)
                }
            }
        };
        ($type:ty) => {
            $crate::impl_queryable_id_type!($type, diesel::sql_types::Text);
        };
    }
}

/// Create new generic list wrapper
#[macro_export]
macro_rules! create_list_wrapper {
    (
        $wrapper_name:ident,
        $type_name: ty,
        impl_functions: {
            $($function_def: tt)*
        }
    ) => {
        #[derive(Clone, Debug)]
        pub struct $wrapper_name(Vec<$type_name>);
        impl $wrapper_name {
            pub fn new(list: Vec<$type_name>) -> Self {
                Self(list)
            }
            pub fn with_capacity(size: usize) -> Self {
                Self(Vec::with_capacity(size))
            }
            $($function_def)*
        }
        impl std::ops::Deref for $wrapper_name {
            type Target = Vec<$type_name>;
            fn deref(&self) -> &<Self as std::ops::Deref>::Target {
                &self.0
            }
        }
        impl std::ops::DerefMut for $wrapper_name {
            fn deref_mut(&mut self) -> &mut Self::Target {
                &mut self.0
            }
        }
        impl IntoIterator for $wrapper_name {
            type Item = $type_name;
            type IntoIter = std::vec::IntoIter<$type_name>;
            fn into_iter(self) -> Self::IntoIter {
                self.0.into_iter()
            }
        }

        impl<'a> IntoIterator for &'a $wrapper_name {
            type Item = &'a $type_name;
            type IntoIter = std::slice::Iter<'a, $type_name>;
            fn into_iter(self) -> Self::IntoIter {
                self.0.iter()
            }
        }

        impl FromIterator<$type_name> for $wrapper_name {
            fn from_iter<T: IntoIterator<Item = $type_name>>(iter: T) -> Self {
                Self(iter.into_iter().collect())
            }
        }
    };
}

/// Get the type name for a type
#[macro_export]
macro_rules! type_name {
    ($type:ty) => {
        std::any::type_name::<$type>()
            .rsplit("::")
            .nth(1)
            .unwrap_or_default();
    };
}

/// **Note** Creates an enum wrapper that implements `FromStr`, `Display`, `Serialize`, and `Deserialize`
/// based on a specific string representation format: `"VariantName<delimiter>FieldValue"`.
/// It handles parsing errors by returning a dedicated `Invalid` variant.
/// *Note*: The macro adds `Invalid,` automatically.
///
/// # Use Case
///
/// This macro is designed for scenarios where you need an enum, with each variant
/// holding a single piece of associated data, to be easily convertible to and from
/// a simple string format. This is useful for cases where enum is serialized to key value pairs
///
/// It avoids more complex serialization structures (like JSON objects `{"VariantName": value}`)
/// in favor of a plain string representation.
///
/// # Input Enum Format and Constraints
///
/// To use this macro, the enum definition must adhere to the following structure:
///
/// 1.  **Public Enum:** The enum must be declared as `pub enum EnumName { ... }`.
/// 2.  **Struct Variants Only:** All variants must be struct variants (using `{}`).
/// 3.  **Exactly One Field:** Each struct variant must contain *exactly one* named field.
///     * **Valid:** `VariantA { value: i32 }`
///     * **Invalid:** `VariantA(i32)` (tuple variant)
///     * **Invalid:** `VariantA` or `VariantA {}` (no field)
///     * **Invalid:** `VariantA { value: i32, other: bool }` (multiple fields)
/// 4.  **Tag Delimiter:** The macro invocation must specify a `tag_delimiter` literal,
///     which is the character used to separate the variant name from the field data in
///     the string representation (e.g., `tag_delimiter = ":",`).
/// 5.  **Field Type Requirements:** The type of the single field in each variant (`$field_ty`)
///     must implement:
///     * `core::str::FromStr`: To parse the field's data from the string part.
///       The `Err` type should ideally be convertible to a meaningful error, though the
///       macro currently uses a generic error message upon failure.
///     * `core::fmt::Display`: To convert the field's data into the string part.
///     * `serde::Serialize` and `serde::Deserialize<'de>`: Although the macro implements
///       custom `Serialize`/`Deserialize` for the *enum* using the string format, the field
///       type itself must satisfy these bounds if required elsewhere or by generic contexts.
///       The macro's implementations rely solely on `Display` and `FromStr` for the conversion.
/// 6.  **Error Type:** This macro uses `core::convert::Infallible` as it never fails but gives
///     `Self::Invalid` variant.
///
/// # Serialization and Deserialization (`serde`)
///
/// When `serde` features are enabled and the necessary traits are derived or implemented,
/// this macro implements `Serialize` and `Deserialize` for the enum:
///
/// **Serialization:** An enum value like `MyEnum::VariantA { value: 123 }` (with `tag_delimiter = ":",`)
///     will be serialized into the string `"VariantA:123"`. If serializing to JSON, this results
///     in a JSON string: `"\"VariantA:123\""`.
/// **Deserialization:** The macro expects a string matching the format `"VariantName<delimiter>FieldValue"`.
///     It uses the enum's `FromStr` implementation internally. When deserializing from JSON, it
///     expects a JSON string containing the correctly formatted value (e.g., `"\"VariantA:123\""`).
///
/// # `Display` and `FromStr`
///
/// **`Display`:** Formats valid variants to `"VariantName<delimiter>FieldValue"` and catch-all cases to `"Invalid"`.
/// **`FromStr`:** Parses `"VariantName<delimiter>FieldValue"` to the variant, or returns `Self::Invalid`
///   if the input string is malformed or `"Invalid"`.
///
/// # Example
///
/// ```rust
/// use std::str::FromStr;
///
/// crate::impl_enum_str!(
///     tag_delimiter = ":",
///     #[derive(Debug, PartialEq, Clone)] // Add other derives as needed
///     pub enum Setting {
///         Timeout { duration_ms: u32 },
///         Username { name: String },
///     }
/// );
/// // Note: The macro adds `Invalid,` automatically.
///
/// fn main() {
///     // Display
///     let setting1 = Setting::Timeout { duration_ms: 5000 };
///     assert_eq!(setting1.to_string(), "Timeout:5000");
///     assert_eq!(Setting::Invalid.to_string(), "Invalid");
///
///     // FromStr (returns Self, not Result)
///     let parsed_setting: Setting = "Username:admin".parse().expect("Valid parse"); // parse() itself doesn't panic
///     assert_eq!(parsed_setting, Setting::Username { name: "admin".to_string() });
///
///     let invalid_format: Setting = "Timeout".parse().expect("Parse always returns Self");
///     assert_eq!(invalid_format, Setting::Invalid); // Malformed input yields Invalid
///
///     let bad_data: Setting = "Timeout:fast".parse().expect("Parse always returns Self");
///     assert_eq!(bad_data, Setting::Invalid); // Bad field data yields Invalid
///
///     let unknown_tag: Setting = "Unknown:abc".parse().expect("Parse always returns Self");
///     assert_eq!(unknown_tag, Setting::Invalid); // Unknown tag yields Invalid
///
///     let explicit_invalid: Setting = "Invalid".parse().expect("Parse always returns Self");
///     assert_eq!(explicit_invalid, Setting::Invalid); // "Invalid" string yields Invalid
///
///     // Serde (requires derive Serialize/Deserialize on Setting)
///     // let json_output = serde_json::to_string(&setting1).unwrap();
///     // assert_eq!(json_output, "\"Timeout:5000\"");
///     // let invalid_json_output = serde_json::to_string(&Setting::Invalid).unwrap();
///     // assert_eq!(invalid_json_output, "\"Invalid\"");
///
///     // let deserialized: Setting = serde_json::from_str("\"Username:guest\"").unwrap();
///     // assert_eq!(deserialized, Setting::Username { name: "guest".to_string() });
///     // let deserialized_invalid: Setting = serde_json::from_str("\"Invalid\"").unwrap();
///     // assert_eq!(deserialized_invalid, Setting::Invalid);
///     // let deserialized_malformed: Setting = serde_json::from_str("\"TimeoutFast\"").unwrap();
///     // assert_eq!(deserialized_malformed, Setting::Invalid); // Malformed -> Invalid
/// }
///
/// # // Mock macro definition for doctest purposes
/// # #[macro_export] macro_rules! impl_enum_str { ($($tt:tt)*) => { $($tt)* } }
/// ```
#[macro_export]
macro_rules! impl_enum_str {
    (
        tag_delimiter = $tag_delim:literal,
        $(#[$enum_attr:meta])*
        pub enum $enum_name:ident {
            $(
                $(#[$variant_attr:meta])*
                $variant:ident {
                    $(#[$field_attr:meta])*
                    $field:ident : $field_ty:ty $(,)?
                }
            ),* $(,)?
        }
    ) => {
        $(#[$enum_attr])*
        pub enum $enum_name {
            $(
                $(#[$variant_attr])*
                $variant {
                    $(#[$field_attr])*
                    $field : $field_ty
                },
            )*
            /// Represents a parsing failure.
            Invalid, // Automatically add the Invalid variant
        }

        // Implement FromStr - now returns Self, not Result
        impl core::str::FromStr for $enum_name {
            // No associated error type needed
            type Err = core::convert::Infallible; // FromStr requires an Err type, use Infallible

            fn from_str(s: &str) -> Result<Self, Self::Err> {
                // Check for explicit "Invalid" string first
                if s == "Invalid" {
                    return Ok(Self::Invalid);
                }

                let Some((tag, associated_data)) = s.split_once($tag_delim) else {
                    // Missing delimiter -> Invalid
                    return Ok(Self::Invalid);
                };

                let result = match tag {
                    $(
                        stringify!($variant) => {
                            // Try to parse the field data
                            match associated_data.parse::<$field_ty>() {
                                Ok(parsed_field) => {
                                    // Success -> construct the variant
                                     Self::$variant { $field: parsed_field }
                                },
                                Err(_) => {
                                     // Field parse failure -> Invalid
                                     Self::Invalid
                                }
                            }
                        }
                    ),*
                    // Unknown tag -> Invalid
                    _ => Self::Invalid,
                };
                Ok(result) // Always Ok because failure modes return Self::Invalid
            }
        }

        // Implement Serialize
        impl ::serde::Serialize for $enum_name {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: ::serde::Serializer,
            {
                match self {
                    $(
                        Self::$variant { $field } => {
                            let s = format!("{}{}{}", stringify!($variant), $tag_delim, $field);
                            serializer.serialize_str(&s)
                        }
                    )*
                    // Handle Invalid variant
                    Self::Invalid => serializer.serialize_str("Invalid"),
                }
            }
        }

        // Implement Deserialize
        impl<'de> ::serde::Deserialize<'de> for $enum_name {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
            where
                D: ::serde::Deserializer<'de>,
            {
                struct EnumVisitor;

                impl<'de> ::serde::de::Visitor<'de> for EnumVisitor {
                    type Value = $enum_name;

                    fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
                        formatter.write_str(concat!("a string like VariantName", $tag_delim, "field_data or 'Invalid'"))
                    }

                    // Leverage the FromStr implementation which now returns Self::Invalid on failure
                    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
                    where
                        E: ::serde::de::Error,
                    {
                        // parse() now returns Result<Self, Infallible>
                        // We unwrap() the Ok because it's infallible.
                       Ok(value.parse::<$enum_name>().unwrap())
                    }

                     fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
                    where
                        E: ::serde::de::Error,
                    {
                        Ok(value.parse::<$enum_name>().unwrap())
                    }
                }

                deserializer.deserialize_str(EnumVisitor)
            }
        }

        // Implement Display
        impl core::fmt::Display for $enum_name {
            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
                match self {
                    $(
                        Self::$variant { $field } => {
                            write!(f, "{}{}{}", stringify!($variant), $tag_delim, $field)
                        }
                    )*
                     // Handle Invalid variant
                    Self::Invalid => write!(f, "Invalid"),
                }
            }
        }
    };
}

// --- Tests ---
#[cfg(test)]
mod tests {
    #![allow(clippy::panic, clippy::expect_used)]

    use serde_json::{json, Value as JsonValue};

    use crate::impl_enum_str;

    impl_enum_str!(
        tag_delimiter = ":",
        #[derive(Debug, PartialEq, Clone)]
        pub enum TestEnum {
            VariantA { value: i32 },
            VariantB { text: String },
            VariantC { id: u64 },
            VariantJson { data: JsonValue },
        } // Note: Invalid variant is added automatically by the macro
    );

    #[test]
    fn test_enum_from_str_ok() {
        // Success cases just parse directly
        let parsed_a: TestEnum = "VariantA:42".parse().unwrap(); // Unwrapping Infallible is fine
        assert_eq!(parsed_a, TestEnum::VariantA { value: 42 });

        let parsed_b: TestEnum = "VariantB:hello world".parse().unwrap();
        assert_eq!(
            parsed_b,
            TestEnum::VariantB {
                text: "hello world".to_string()
            }
        );

        let parsed_c: TestEnum = "VariantC:123456789012345".parse().unwrap();
        assert_eq!(
            parsed_c,
            TestEnum::VariantC {
                id: 123456789012345
            }
        );

        let parsed_json: TestEnum = r#"VariantJson:{"ok":true}"#.parse().unwrap();
        assert_eq!(
            parsed_json,
            TestEnum::VariantJson {
                data: json!({"ok": true})
            }
        );
    }

    #[test]
    fn test_enum_from_str_failures_yield_invalid() {
        // Missing delimiter
        let parsed: TestEnum = "VariantA".parse().unwrap();
        assert_eq!(parsed, TestEnum::Invalid);

        // Unknown tag
        let parsed: TestEnum = "UnknownVariant:123".parse().unwrap();
        assert_eq!(parsed, TestEnum::Invalid);

        // Bad field data for i32
        let parsed: TestEnum = "VariantA:not_a_number".parse().unwrap();
        assert_eq!(parsed, TestEnum::Invalid);

        // Bad field data for JsonValue
        let parsed: TestEnum = r#"VariantJson:{"bad_json"#.parse().unwrap();
        assert_eq!(parsed, TestEnum::Invalid);

        // Empty field data for non-string (e.g., i32)
        let parsed: TestEnum = "VariantA:".parse().unwrap();
        assert_eq!(parsed, TestEnum::Invalid);

        // Empty field data for string IS valid for String type
        let parsed_str: TestEnum = "VariantB:".parse().unwrap();
        assert_eq!(
            parsed_str,
            TestEnum::VariantB {
                text: "".to_string()
            }
        );

        // Parsing the literal "Invalid" string
        let parsed_invalid_str: TestEnum = "Invalid".parse().unwrap();
        assert_eq!(parsed_invalid_str, TestEnum::Invalid);
    }

    #[test]
    fn test_enum_display_and_serialize() {
        // Display valid
        let value_a = TestEnum::VariantA { value: 99 };
        assert_eq!(value_a.to_string(), "VariantA:99");
        // Serialize valid
        let json_a = serde_json::to_string(&value_a).expect("Serialize A failed");
        assert_eq!(json_a, "\"VariantA:99\""); // Serializes to JSON string

        // Display Invalid
        let value_invalid = TestEnum::Invalid;
        assert_eq!(value_invalid.to_string(), "Invalid");
        // Serialize Invalid
        let json_invalid = serde_json::to_string(&value_invalid).expect("Serialize Invalid failed");
        assert_eq!(json_invalid, "\"Invalid\""); // Serializes to JSON string "Invalid"
    }

    #[test]
    fn test_enum_deserialize() {
        // Deserialize valid
        let input_a = "\"VariantA:123\"";
        let deserialized_a: TestEnum = serde_json::from_str(input_a).expect("Deserialize A failed");
        assert_eq!(deserialized_a, TestEnum::VariantA { value: 123 });

        // Deserialize explicit "Invalid"
        let input_invalid = "\"Invalid\"";
        let deserialized_invalid: TestEnum =
            serde_json::from_str(input_invalid).expect("Deserialize Invalid failed");
        assert_eq!(deserialized_invalid, TestEnum::Invalid);

        // Deserialize malformed string (according to macro rules) -> Invalid
        let input_malformed = "\"VariantA_no_delimiter\"";
        let deserialized_malformed: TestEnum =
            serde_json::from_str(input_malformed).expect("Deserialize malformed should succeed");
        assert_eq!(deserialized_malformed, TestEnum::Invalid);

        // Deserialize string with bad field data -> Invalid
        let input_bad_data = "\"VariantA:not_a_number\"";
        let deserialized_bad_data: TestEnum =
            serde_json::from_str(input_bad_data).expect("Deserialize bad data should succeed");
        assert_eq!(deserialized_bad_data, TestEnum::Invalid);
    }
}


// Function: find_by_global_customer_id
// File: crates/diesel_models/src/query/payment_method.rs
// Module: diesel_models

pub fn find_by_global_customer_id(
        conn: &PgPooledConn,
        customer_id: &common_utils::id_type::GlobalCustomerId,
        limit: Option<i64>,
    ) -> StorageResult<Vec<Self>>


// Struct: BankAccountDetails
// File: crates/pm_auth/src/types.rs
// Module: pm_auth
// Implementations: 0

pub struct BankAccountDetails


// Implementation: impl ConnectorSpecifications for for Cashtocode
// File: crates/hyperswitch_connectors/src/connectors/cashtocode.rs
// Module: hyperswitch_connectors
// Methods: 3 total (0 public)

impl ConnectorSpecifications for for Cashtocode


// Struct: PayboxCaptureRequest
// File: crates/hyperswitch_connectors/src/connectors/paybox/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PayboxCaptureRequest


// Implementation: impl PaymentLinkInterface for for KafkaStore
// File: crates/router/src/db/kafka_store.rs
// Module: router
// Methods: 3 total (0 public)

impl PaymentLinkInterface for for KafkaStore


// Struct: CoBadgedCardRequest
// File: crates/api_models/src/open_router.rs
// Module: api_models
// Implementations: 0

pub struct CoBadgedCardRequest


// Function: get_checkout_event_status_and_reason
// File: crates/router/src/core/unified_authentication_service/utils.rs
// Module: router

pub fn get_checkout_event_status_and_reason(
    attempt_status: common_enums::AttemptStatus,
) -> (Option<String>, Option<String>)


// Struct: RecurlyRouterData
// File: crates/hyperswitch_connectors/src/connectors/recurly/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RecurlyRouterData<T>


// Function: delete_by_merchant_id
// File: crates/diesel_models/src/query/merchant_key_store.rs
// Module: diesel_models

pub fn delete_by_merchant_id(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> StorageResult<bool>


// Function: elimination_routing_update_configs
// File: crates/router/src/routes/routing.rs
// Module: router

pub fn elimination_routing_update_configs(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<routing_types::DynamicRoutingUpdateConfigQuery>,
    json_payload: web::Json<routing_types::EliminationRoutingConfig>,
) -> impl Responder


// Function: populate_error_reason
// File: crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs
// Module: hyperswitch_connectors

pub fn populate_error_reason(
    code: Option<String>,
    message: Option<String>,
    reason: Option<String>,
    http_code: u16,
    attempt_status: Option<AttemptStatus>,
    connector_transaction_id: Option<String>,
) -> ErrorResponse


// Function: perform_eligibility_analysis
// File: crates/router/src/core/payments/routing.rs
// Module: router

pub fn perform_eligibility_analysis(
    state: &SessionState,
    key_store: &domain::MerchantKeyStore,
    chosen: Vec<routing_types::RoutableConnectorChoice>,
    transaction_data: &routing::TransactionData<'_>,
    eligible_connectors: Option<&Vec<api_enums::RoutableConnectors>>,
    profile_id: &common_utils::id_type::ProfileId,
) -> RoutingResult<Vec<routing_types::RoutableConnectorChoice>>


// File: crates/router/src/utils/user/dashboard_metadata.rs
// Module: router
// Public functions: 13

use std::{net::IpAddr, ops::Not, str::FromStr};

use actix_web::http::header::HeaderMap;
use api_models::user::dashboard_metadata::{
    GetMetaDataRequest, GetMultipleMetaDataPayload, ProdIntent, SetMetaDataRequest,
};
use common_utils::id_type;
use diesel_models::{
    enums::DashboardMetadata as DBEnum,
    user::dashboard_metadata::{DashboardMetadata, DashboardMetadataNew, DashboardMetadataUpdate},
};
use error_stack::{report, ResultExt};
use masking::{ExposeInterface, PeekInterface, Secret};
use router_env::logger;

use crate::{
    core::errors::{UserErrors, UserResult},
    headers, SessionState,
};

pub async fn insert_merchant_scoped_metadata_to_db(
    state: &SessionState,
    user_id: String,
    merchant_id: id_type::MerchantId,
    org_id: id_type::OrganizationId,
    metadata_key: DBEnum,
    metadata_value: impl serde::Serialize,
) -> UserResult<DashboardMetadata> {
    let now = common_utils::date_time::now();
    let data_value = serde_json::to_value(metadata_value)
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Error Converting Struct To Serde Value")?;
    state
        .store
        .insert_metadata(DashboardMetadataNew {
            user_id: None,
            merchant_id,
            org_id,
            data_key: metadata_key,
            data_value: Secret::from(data_value),
            created_by: user_id.clone(),
            created_at: now,
            last_modified_by: user_id,
            last_modified_at: now,
        })
        .await
        .map_err(|e| {
            if e.current_context().is_db_unique_violation() {
                return e.change_context(UserErrors::MetadataAlreadySet);
            }
            e.change_context(UserErrors::InternalServerError)
        })
}
pub async fn insert_user_scoped_metadata_to_db(
    state: &SessionState,
    user_id: String,
    merchant_id: id_type::MerchantId,
    org_id: id_type::OrganizationId,
    metadata_key: DBEnum,
    metadata_value: impl serde::Serialize,
) -> UserResult<DashboardMetadata> {
    let now = common_utils::date_time::now();
    let data_value = serde_json::to_value(metadata_value)
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Error Converting Struct To Serde Value")?;
    state
        .store
        .insert_metadata(DashboardMetadataNew {
            user_id: Some(user_id.clone()),
            merchant_id,
            org_id,
            data_key: metadata_key,
            data_value: Secret::from(data_value),
            created_by: user_id.clone(),
            created_at: now,
            last_modified_by: user_id,
            last_modified_at: now,
        })
        .await
        .map_err(|e| {
            if e.current_context().is_db_unique_violation() {
                return e.change_context(UserErrors::MetadataAlreadySet);
            }
            e.change_context(UserErrors::InternalServerError)
        })
}

pub async fn get_merchant_scoped_metadata_from_db(
    state: &SessionState,
    merchant_id: id_type::MerchantId,
    org_id: id_type::OrganizationId,
    metadata_keys: Vec<DBEnum>,
) -> UserResult<Vec<DashboardMetadata>> {
    state
        .store
        .find_merchant_scoped_dashboard_metadata(&merchant_id, &org_id, metadata_keys)
        .await
        .change_context(UserErrors::InternalServerError)
        .attach_printable("DB Error Fetching DashboardMetaData")
}
pub async fn get_user_scoped_metadata_from_db(
    state: &SessionState,
    user_id: String,
    merchant_id: id_type::MerchantId,
    org_id: id_type::OrganizationId,
    metadata_keys: Vec<DBEnum>,
) -> UserResult<Vec<DashboardMetadata>> {
    match state
        .store
        .find_user_scoped_dashboard_metadata(&user_id, &merchant_id, &org_id, metadata_keys)
        .await
    {
        Ok(data) => Ok(data),
        Err(e) => {
            if e.current_context().is_db_not_found() {
                return Ok(Vec::with_capacity(0));
            }
            Err(e
                .change_context(UserErrors::InternalServerError)
                .attach_printable("DB Error Fetching DashboardMetaData"))
        }
    }
}

pub async fn update_merchant_scoped_metadata(
    state: &SessionState,
    user_id: String,
    merchant_id: id_type::MerchantId,
    org_id: id_type::OrganizationId,
    metadata_key: DBEnum,
    metadata_value: impl serde::Serialize,
) -> UserResult<DashboardMetadata> {
    let data_value = serde_json::to_value(metadata_value)
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Error Converting Struct To Serde Value")?;

    state
        .store
        .update_metadata(
            None,
            merchant_id,
            org_id,
            metadata_key,
            DashboardMetadataUpdate::UpdateData {
                data_key: metadata_key,
                data_value: Secret::from(data_value),
                last_modified_by: user_id,
            },
        )
        .await
        .change_context(UserErrors::InternalServerError)
}
pub async fn update_user_scoped_metadata(
    state: &SessionState,
    user_id: String,
    merchant_id: id_type::MerchantId,
    org_id: id_type::OrganizationId,
    metadata_key: DBEnum,
    metadata_value: impl serde::Serialize,
) -> UserResult<DashboardMetadata> {
    let data_value = serde_json::to_value(metadata_value)
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Error Converting Struct To Serde Value")?;

    state
        .store
        .update_metadata(
            Some(user_id.clone()),
            merchant_id,
            org_id,
            metadata_key,
            DashboardMetadataUpdate::UpdateData {
                data_key: metadata_key,
                data_value: Secret::from(data_value),
                last_modified_by: user_id,
            },
        )
        .await
        .change_context(UserErrors::InternalServerError)
}

pub fn deserialize_to_response<T>(data: Option<&DashboardMetadata>) -> UserResult<Option<T>>
where
    T: serde::de::DeserializeOwned,
{
    data.map(|metadata| serde_json::from_value(metadata.data_value.clone().expose()))
        .transpose()
        .change_context(UserErrors::InternalServerError)
        .attach_printable("Error Serializing Metadata from DB")
}

pub fn separate_metadata_type_based_on_scope(
    metadata_keys: Vec<DBEnum>,
) -> (Vec<DBEnum>, Vec<DBEnum>) {
    let (mut merchant_scoped, mut user_scoped) = (
        Vec::with_capacity(metadata_keys.len()),
        Vec::with_capacity(metadata_keys.len()),
    );
    for key in metadata_keys {
        match key {
            DBEnum::ProductionAgreement
            | DBEnum::SetupProcessor
            | DBEnum::ConfigureEndpoint
            | DBEnum::SetupComplete
            | DBEnum::FirstProcessorConnected
            | DBEnum::SecondProcessorConnected
            | DBEnum::ConfiguredRouting
            | DBEnum::TestPayment
            | DBEnum::IntegrationMethod
            | DBEnum::ConfigurationType
            | DBEnum::IntegrationCompleted
            | DBEnum::StripeConnected
            | DBEnum::PaypalConnected
            | DBEnum::SpRoutingConfigured
            | DBEnum::SpTestPayment
            | DBEnum::DownloadWoocom
            | DBEnum::ConfigureWoocom
            | DBEnum::SetupWoocomWebhook
            | DBEnum::OnboardingSurvey
            | DBEnum::IsMultipleConfiguration
            | DBEnum::ReconStatus
            | DBEnum::ProdIntent => merchant_scoped.push(key),
            DBEnum::Feedback | DBEnum::IsChangePasswordRequired => user_scoped.push(key),
        }
    }
    (merchant_scoped, user_scoped)
}

pub fn is_update_required(metadata: &UserResult<DashboardMetadata>) -> bool {
    match metadata {
        Ok(_) => false,
        Err(e) => matches!(e.current_context(), UserErrors::MetadataAlreadySet),
    }
}

pub fn is_backfill_required(metadata_key: DBEnum) -> bool {
    matches!(
        metadata_key,
        DBEnum::StripeConnected | DBEnum::PaypalConnected
    )
}

pub fn set_ip_address_if_required(
    request: &mut SetMetaDataRequest,
    headers: &HeaderMap,
) -> UserResult<()> {
    if let SetMetaDataRequest::ProductionAgreement(req) = request {
        let ip_address_from_request: Secret<String, common_utils::pii::IpAddress> = headers
            .get(headers::X_FORWARDED_FOR)
            .ok_or(report!(UserErrors::IpAddressParsingFailed))
            .attach_printable("X-Forwarded-For header not found")?
            .to_str()
            .change_context(UserErrors::IpAddressParsingFailed)
            .attach_printable("Error converting Header Value to Str")?
            .split(',')
            .next()
            .and_then(|ip| {
                let ip_addr: Result<IpAddr, _> = ip.parse();
                ip_addr.ok()
            })
            .ok_or(report!(UserErrors::IpAddressParsingFailed))
            .attach_printable("Error Parsing header value to ip")?
            .to_string()
            .into();
        req.ip_address = Some(ip_address_from_request)
    }
    Ok(())
}

pub fn parse_string_to_enums(query: String) -> UserResult<GetMultipleMetaDataPayload> {
    Ok(GetMultipleMetaDataPayload {
        results: query
            .split(',')
            .map(GetMetaDataRequest::from_str)
            .collect::<Result<Vec<GetMetaDataRequest>, _>>()
            .change_context(UserErrors::InvalidMetadataRequest)
            .attach_printable("Error Parsing to DashboardMetadata enums")?,
    })
}

fn not_contains_string(value: Option<&str>, value_to_be_checked: &str) -> bool {
    value.is_some_and(|mail| !mail.contains(value_to_be_checked))
}

pub fn is_prod_email_required(data: &ProdIntent, user_email: String) -> bool {
    let poc_email_check = not_contains_string(
        data.poc_email.as_ref().map(|email| email.peek().as_str()),
        "juspay",
    );
    let business_website_check = not_contains_string(data.business_website.as_deref(), "juspay")
        && not_contains_string(data.business_website.as_deref(), "hyperswitch");
    let user_email_check = not_contains_string(Some(&user_email), "juspay");

    if (poc_email_check && business_website_check && user_email_check).not() {
        logger::info!(prod_intent_email = poc_email_check);
        logger::info!(prod_intent_email = business_website_check);
        logger::info!(prod_intent_email = user_email_check);
    }

    poc_email_check && business_website_check && user_email_check
}


// Struct: CybersourceFulfillResponse
// File: crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CybersourceFulfillResponse