// File: crates/router/src/core/payouts/transformers.rs
// Module: router

use std::collections::HashMap;

use common_utils::link_utils::EnabledPaymentMethod;

#[cfg(all(feature = "v1", feature = "olap"))]
use crate::types::transformers::ForeignInto;
#[cfg(feature = "olap")]
use crate::types::{api::payments, domain, storage};
use crate::{
    settings::PayoutRequiredFields,
    types::{api, transformers::ForeignFrom},
};

#[cfg(all(feature = "v2", feature = "olap"))]
impl
    ForeignFrom<(
        storage::Payouts,
        storage::PayoutAttempt,
        Option<domain::Customer>,
        Option<payments::Address>,
    )> for api::PayoutCreateResponse
{
    fn foreign_from(
        item: (
            storage::Payouts,
            storage::PayoutAttempt,
            Option<domain::Customer>,
            Option<payments::Address>,
        ),
    ) -> Self {
        todo!()
    }
}

#[cfg(all(feature = "v1", feature = "olap"))]
impl
    ForeignFrom<(
        storage::Payouts,
        storage::PayoutAttempt,
        Option<domain::Customer>,
        Option<payments::Address>,
    )> for api::PayoutCreateResponse
{
    fn foreign_from(
        item: (
            storage::Payouts,
            storage::PayoutAttempt,
            Option<domain::Customer>,
            Option<payments::Address>,
        ),
    ) -> Self {
        let (payout, payout_attempt, customer, address) = item;
        let attempt = api::PayoutAttemptResponse {
            attempt_id: payout_attempt.payout_attempt_id,
            status: payout_attempt.status,
            amount: payout.amount,
            currency: Some(payout.destination_currency),
            connector: payout_attempt.connector.clone(),
            error_code: payout_attempt.error_code.clone(),
            error_message: payout_attempt.error_message.clone(),
            payment_method: payout.payout_type,
            payout_method_type: None,
            connector_transaction_id: payout_attempt.connector_payout_id,
            cancellation_reason: None,
            unified_code: None,
            unified_message: None,
        };
        Self {
            payout_id: payout.payout_id,
            merchant_id: payout.merchant_id,
            merchant_connector_id: payout_attempt.merchant_connector_id,
            merchant_order_reference_id: payout_attempt.merchant_order_reference_id.clone(),
            amount: payout.amount,
            currency: payout.destination_currency,
            connector: payout_attempt.connector,
            payout_type: payout.payout_type,
            auto_fulfill: payout.auto_fulfill,
            customer_id: customer.as_ref().map(|cust| cust.customer_id.clone()),
            customer: customer.as_ref().map(|cust| cust.foreign_into()),
            return_url: payout.return_url,
            business_country: payout_attempt.business_country,
            business_label: payout_attempt.business_label,
            description: payout.description,
            entity_type: payout.entity_type,
            recurring: payout.recurring,
            metadata: payout.metadata,
            status: payout_attempt.status,
            error_message: payout_attempt.error_message,
            error_code: payout_attempt.error_code,
            profile_id: payout.profile_id,
            created: Some(payout.created_at),
            connector_transaction_id: attempt.connector_transaction_id.clone(),
            priority: payout.priority,
            billing: address,
            payout_method_data: payout_attempt.additional_payout_method_data.map(From::from),
            client_secret: None,
            payout_link: None,
            unified_code: attempt.unified_code.clone(),
            unified_message: attempt.unified_message.clone(),
            attempts: Some(vec![attempt]),
            email: customer
                .as_ref()
                .and_then(|customer| customer.email.clone()),
            name: customer.as_ref().and_then(|customer| customer.name.clone()),
            phone: customer
                .as_ref()
                .and_then(|customer| customer.phone.clone()),
            phone_country_code: customer
                .as_ref()
                .and_then(|customer| customer.phone_country_code.clone()),
            payout_method_id: payout.payout_method_id,
        }
    }
}

#[cfg(feature = "v1")]
impl
    ForeignFrom<(
        &PayoutRequiredFields,
        Vec<EnabledPaymentMethod>,
        api::RequiredFieldsOverrideRequest,
    )> for Vec<api::PayoutEnabledPaymentMethodsInfo>
{
    fn foreign_from(
        (payout_required_fields, enabled_payout_methods, value_overrides): (
            &PayoutRequiredFields,
            Vec<EnabledPaymentMethod>,
            api::RequiredFieldsOverrideRequest,
        ),
    ) -> Self {
        let value_overrides = value_overrides.flat_struct();

        enabled_payout_methods
            .into_iter()
            .map(|enabled_payout_method| {
                let payment_method = enabled_payout_method.payment_method;
                let payment_method_types_info = enabled_payout_method
                    .payment_method_types
                    .into_iter()
                    .filter_map(|pmt| {
                        payout_required_fields
                            .0
                            .get(&payment_method)
                            .and_then(|pmt_info| {
                                pmt_info.0.get(&pmt).map(|connector_fields| {
                                    let mut required_fields = HashMap::new();

                                    for required_field_final in connector_fields.fields.values() {
                                        required_fields.extend(required_field_final.common.clone());
                                    }

                                    for (key, value) in &value_overrides {
                                        required_fields.entry(key.to_string()).and_modify(
                                            |required_field| {
                                                required_field.value =
                                                    Some(masking::Secret::new(value.to_string()));
                                            },
                                        );
                                    }
                                    api::PaymentMethodTypeInfo {
                                        payment_method_type: pmt,
                                        required_fields: if required_fields.is_empty() {
                                            None
                                        } else {
                                            Some(required_fields)
                                        },
                                    }
                                })
                            })
                            .or(Some(api::PaymentMethodTypeInfo {
                                payment_method_type: pmt,
                                required_fields: None,
                            }))
                    })
                    .collect();

                api::PayoutEnabledPaymentMethodsInfo {
                    payment_method,
                    payment_method_types_info,
                }
            })
            .collect()
    }
}


// Function: delete_tokenized_data_core
// File: crates/router/src/core/tokenization.rs
// Module: router

pub fn delete_tokenized_data_core(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    token_id: &id_type::GlobalTokenId,
    payload: api_models::tokenization::DeleteTokenDataRequest,
) -> RouterResponse<api_models::tokenization::DeleteTokenDataResponse>


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

pub struct SwitchProfileRequest


// Function: get_client_id
// File: crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs
// Module: hyperswitch_connectors

pub fn get_client_id(&self) -> Secret<String>


// Struct: Provider
// File: crates/connector_configs/src/common_config.rs
// Module: connector_configs
// Implementations: 0

pub struct Provider


// Function: customers_mandates_list
// File: crates/openapi/src/routes/mandates.rs
// Module: openapi

pub fn customers_mandates_list()


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

pub struct CybersourceRouterData<T>


// Function: get_error_response
// File: crates/hyperswitch_connectors/src/connectors/wellsfargo/transformers.rs
// Module: hyperswitch_connectors

pub fn get_error_response(
    error_data: &Option<WellsfargoErrorInformation>,
    risk_information: &Option<ClientRiskInformation>,
    attempt_status: Option<enums::AttemptStatus>,
    status_code: u16,
    transaction_id: String,
) -> ErrorResponse


// File: crates/router/src/routes/user_role.rs
// Module: router
// Public functions: 19

use actix_web::{web, HttpRequest, HttpResponse};
use api_models::user_role::{self as user_role_api, role as role_api};
use common_enums::TokenPurpose;
use router_env::Flow;

use super::AppState;
use crate::{
    core::{
        api_locking,
        user_role::{self as user_role_core, role as role_core},
    },
    services::{
        api,
        authentication::{self as auth},
        authorization::permissions::Permission,
    },
};

// TODO: To be deprecated
pub async fn get_authorization_info(
    state: web::Data<AppState>,
    http_req: HttpRequest,
) -> HttpResponse {
    let flow = Flow::GetAuthorizationInfo;
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &http_req,
        (),
        |state, _: (), _, _| async move {
            user_role_core::get_authorization_info_with_groups(state).await
        },
        &auth::JWTAuth {
            permission: Permission::MerchantUserRead,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn get_role_from_token(state: web::Data<AppState>, req: HttpRequest) -> HttpResponse {
    let flow = Flow::GetRoleFromToken;

    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        (),
        |state, user, _, _| async move {
            role_core::get_role_from_token_with_groups(state, user).await
        },
        &auth::DashboardNoPermissionAuth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn get_groups_and_resources_for_role_from_token(
    state: web::Data<AppState>,
    req: HttpRequest,
) -> HttpResponse {
    let flow = Flow::GetRoleFromTokenV2;

    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        (),
        |state, user, _, _| async move {
            role_core::get_groups_and_resources_for_role_from_token(state, user).await
        },
        &auth::DashboardNoPermissionAuth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}
// TODO: To be deprecated
pub async fn create_role(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<role_api::CreateRoleRequest>,
) -> HttpResponse {
    let flow = Flow::CreateRole;
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        json_payload.into_inner(),
        role_core::create_role,
        &auth::JWTAuth {
            permission: Permission::MerchantUserWrite,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn create_role_v2(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<role_api::CreateRoleV2Request>,
) -> HttpResponse {
    let flow = Flow::CreateRoleV2;
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        json_payload.into_inner(),
        role_core::create_role_v2,
        &auth::JWTAuth {
            permission: Permission::MerchantUserWrite,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn get_role(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
) -> HttpResponse {
    let flow = Flow::GetRole;
    let request_payload = user_role_api::role::GetRoleRequest {
        role_id: path.into_inner(),
    };
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        request_payload,
        |state, user, payload, _| async move {
            role_core::get_role_with_groups(state, user, payload).await
        },
        &auth::JWTAuth {
            permission: Permission::ProfileUserRead,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn get_parent_info_for_role(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
) -> HttpResponse {
    let flow = Flow::GetRoleV2;
    let request_payload = user_role_api::role::GetRoleRequest {
        role_id: path.into_inner(),
    };
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        request_payload,
        |state, user, payload, _| async move {
            role_core::get_parent_info_for_role(state, user, payload).await
        },
        &auth::JWTAuth {
            permission: Permission::ProfileUserRead,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn update_role(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<role_api::UpdateRoleRequest>,
    path: web::Path<String>,
) -> HttpResponse {
    let flow = Flow::UpdateRole;
    let role_id = path.into_inner();

    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        json_payload.into_inner(),
        |state, user, req, _| role_core::update_role(state, user, req, &role_id),
        &auth::JWTAuth {
            permission: Permission::MerchantUserWrite,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn update_user_role(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<user_role_api::UpdateUserRoleRequest>,
) -> HttpResponse {
    let flow = Flow::UpdateUserRole;
    let payload = json_payload.into_inner();
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        payload,
        user_role_core::update_user_role,
        &auth::JWTAuth {
            permission: Permission::ProfileUserWrite,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn accept_invitations_v2(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<user_role_api::AcceptInvitationsV2Request>,
) -> HttpResponse {
    let flow = Flow::AcceptInvitationsV2;
    let payload = json_payload.into_inner();
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        payload,
        |state, user, req_body, _| user_role_core::accept_invitations_v2(state, user, req_body),
        &auth::DashboardNoPermissionAuth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn accept_invitations_pre_auth(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<user_role_api::AcceptInvitationsPreAuthRequest>,
) -> HttpResponse {
    let flow = Flow::AcceptInvitationsPreAuth;
    let payload = json_payload.into_inner();
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        payload,
        |state, user, req_body, _| async move {
            user_role_core::accept_invitations_pre_auth(state, user, req_body).await
        },
        &auth::SinglePurposeJWTAuth(TokenPurpose::AcceptInvite),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn delete_user_role(
    state: web::Data<AppState>,
    req: HttpRequest,
    payload: web::Json<user_role_api::DeleteUserRoleRequest>,
) -> HttpResponse {
    let flow = Flow::DeleteUserRole;
    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        payload.into_inner(),
        user_role_core::delete_user_role,
        &auth::JWTAuth {
            permission: Permission::ProfileUserWrite,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn get_role_information(
    state: web::Data<AppState>,
    http_req: HttpRequest,
) -> HttpResponse {
    let flow = Flow::GetRolesInfo;

    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &http_req,
        (),
        |_, _: (), _, _| async move {
            user_role_core::get_authorization_info_with_group_tag().await
        },
        &auth::JWTAuth {
            permission: Permission::ProfileUserRead,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn get_parent_group_info(
    state: web::Data<AppState>,
    http_req: HttpRequest,
    query: web::Query<role_api::GetParentGroupsInfoQueryParams>,
) -> HttpResponse {
    let flow = Flow::GetParentGroupInfo;

    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &http_req,
        query.into_inner(),
        |state, user_from_token, request, _| async move {
            user_role_core::get_parent_group_info(state, user_from_token, request).await
        },
        &auth::JWTAuth {
            permission: Permission::ProfileUserRead,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn list_users_in_lineage(
    state: web::Data<AppState>,
    req: HttpRequest,
    query: web::Query<user_role_api::ListUsersInEntityRequest>,
) -> HttpResponse {
    let flow = Flow::ListUsersInLineage;

    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        query.into_inner(),
        |state, user_from_token, request, _| {
            user_role_core::list_users_in_lineage(state, user_from_token, request)
        },
        &auth::DashboardNoPermissionAuth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn list_roles_with_info(
    state: web::Data<AppState>,
    req: HttpRequest,
    query: web::Query<role_api::ListRolesQueryParams>,
) -> HttpResponse {
    let flow = Flow::ListRolesV2;

    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        query.into_inner(),
        |state, user_from_token, request, _| {
            role_core::list_roles_with_info(state, user_from_token, request)
        },
        &auth::JWTAuth {
            permission: Permission::ProfileUserRead,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn list_invitable_roles_at_entity_level(
    state: web::Data<AppState>,
    req: HttpRequest,
    query: web::Query<role_api::ListRolesAtEntityLevelRequest>,
) -> HttpResponse {
    let flow = Flow::ListInvitableRolesAtEntityLevel;

    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        query.into_inner(),
        |state, user_from_token, req, _| {
            role_core::list_roles_at_entity_level(
                state,
                user_from_token,
                req,
                role_api::RoleCheckType::Invite,
            )
        },
        &auth::JWTAuth {
            permission: Permission::ProfileUserRead,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn list_updatable_roles_at_entity_level(
    state: web::Data<AppState>,
    req: HttpRequest,
    query: web::Query<role_api::ListRolesAtEntityLevelRequest>,
) -> HttpResponse {
    let flow = Flow::ListUpdatableRolesAtEntityLevel;

    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        query.into_inner(),
        |state, user_from_token, req, _| {
            role_core::list_roles_at_entity_level(
                state,
                user_from_token,
                req,
                role_api::RoleCheckType::Update,
            )
        },
        &auth::JWTAuth {
            permission: Permission::ProfileUserRead,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

pub async fn list_invitations_for_user(
    state: web::Data<AppState>,
    req: HttpRequest,
) -> HttpResponse {
    let flow = Flow::ListInvitationsForUser;

    Box::pin(api::server_wrap(
        flow,
        state.clone(),
        &req,
        (),
        |state, user_id_from_token, _, _| {
            user_role_core::list_invitations_for_user(state, user_id_from_token)
        },
        &auth::SinglePurposeOrLoginTokenAuth(TokenPurpose::AcceptInvite),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


// Module Structure
// File: crates/router/src/compatibility/stripe.rs
// Module: router

// Public submodules:
pub mod app;
pub mod customers;
pub mod payment_intents;
pub mod refunds;
pub mod setup_intents;
pub mod webhooks;
pub mod errors;


// Implementation: impl ArchipelFlowStatus
// File: crates/hyperswitch_connectors/src/connectors/archipel/transformers.rs
// Module: hyperswitch_connectors
// Methods: 1 total (0 public)

impl ArchipelFlowStatus


// Function: retrieve_mandates_list
// File: crates/router/src/routes/mandates.rs
// Module: router

pub fn retrieve_mandates_list(
    state: web::Data<AppState>,
    req: HttpRequest,
    payload: web::Query<api_models::mandates::MandateListConstraints>,
) -> HttpResponse


// Function: get_outgoing_webhook_event
// File: crates/analytics/src/outgoing_webhook_event/events.rs
// Module: analytics

pub fn get_outgoing_webhook_event<T>(
    merchant_id: &common_utils::id_type::MerchantId,
    query_param: OutgoingWebhookLogsRequest,
    pool: &T,
) -> FiltersResult<Vec<OutgoingWebhookLogsResult>>
where
    T: AnalyticsDataSource + OutgoingWebhookLogsFilterAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,


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

impl PaymentIncrementalAuthorization for for Stripe


// Implementation: impl HealthCheck for for SqlxClient
// File: crates/analytics/src/sqlx.rs
// Module: analytics
// Methods: 1 total (0 public)

impl HealthCheck for for SqlxClient


// Struct: WellsfargopayoutPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/wellsfargopayout/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct WellsfargopayoutPaymentsRequest


// File: crates/storage_impl/src/payments.rs
// Module: storage_impl

pub mod payment_attempt;
pub mod payment_intent;

use diesel_models::{payment_attempt::PaymentAttempt, PaymentIntent};

use crate::redis::kv_store::KvStorePartition;

impl KvStorePartition for PaymentIntent {}
impl KvStorePartition for PaymentAttempt {}


// Struct: PaymentsRedirectResponseData
// File: crates/router/src/core/payments.rs
// Module: router
// Implementations: 0

pub struct PaymentsRedirectResponseData


// Implementation: impl std::ops::Deref for for PaymentsMandateReference
// File: crates/diesel_models/src/payment_method.rs
// Module: diesel_models
// Methods: 1 total (0 public)

impl std::ops::Deref for for PaymentsMandateReference


// Implementation: impl CustomerUpdateRequest
// File: crates/api_models/src/customers.rs
// Module: api_models
// Methods: 1 total (1 public)

impl CustomerUpdateRequest


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

impl ConnectorSpecifications for for Hyperwallet


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

impl api::ConnectorAccessToken for for Airwallex


// Struct: PaymentsResponseScheme
// File: crates/hyperswitch_connectors/src/connectors/worldpay/response.rs
// Module: hyperswitch_connectors
// Implementations: 1

pub struct PaymentsResponseScheme


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

impl IncomingWebhook for for Stripe


// File: crates/common_utils/src/types/user/theme.rs
// Module: common_utils
// Public functions: 7
// Public structs: 1

use common_enums::EntityType;
use serde::{Deserialize, Serialize};

use crate::{
    events::{ApiEventMetric, ApiEventsType},
    id_type, impl_api_event_type,
};

/// Enum for having all the required lineage for every level.
/// Currently being used for theme related APIs and queries.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(tag = "entity_type", rename_all = "snake_case")]
pub enum ThemeLineage {
    /// Tenant lineage variant
    Tenant {
        /// tenant_id: TenantId
        tenant_id: id_type::TenantId,
    },
    /// Org lineage variant
    Organization {
        /// tenant_id: TenantId
        tenant_id: id_type::TenantId,
        /// org_id: OrganizationId
        org_id: id_type::OrganizationId,
    },
    /// Merchant lineage variant
    Merchant {
        /// tenant_id: TenantId
        tenant_id: id_type::TenantId,
        /// org_id: OrganizationId
        org_id: id_type::OrganizationId,
        /// merchant_id: MerchantId
        merchant_id: id_type::MerchantId,
    },
    /// Profile lineage variant
    Profile {
        /// tenant_id: TenantId
        tenant_id: id_type::TenantId,
        /// org_id: OrganizationId
        org_id: id_type::OrganizationId,
        /// merchant_id: MerchantId
        merchant_id: id_type::MerchantId,
        /// profile_id: ProfileId
        profile_id: id_type::ProfileId,
    },
}

impl_api_event_type!(Miscellaneous, (ThemeLineage));

impl ThemeLineage {
    /// Constructor for ThemeLineage
    pub fn new(
        entity_type: EntityType,
        tenant_id: id_type::TenantId,
        org_id: id_type::OrganizationId,
        merchant_id: id_type::MerchantId,
        profile_id: id_type::ProfileId,
    ) -> Self {
        match entity_type {
            EntityType::Tenant => Self::Tenant { tenant_id },
            EntityType::Organization => Self::Organization { tenant_id, org_id },
            EntityType::Merchant => Self::Merchant {
                tenant_id,
                org_id,
                merchant_id,
            },
            EntityType::Profile => Self::Profile {
                tenant_id,
                org_id,
                merchant_id,
                profile_id,
            },
        }
    }

    /// Get the entity_type from the lineage
    pub fn entity_type(&self) -> EntityType {
        match self {
            Self::Tenant { .. } => EntityType::Tenant,
            Self::Organization { .. } => EntityType::Organization,
            Self::Merchant { .. } => EntityType::Merchant,
            Self::Profile { .. } => EntityType::Profile,
        }
    }

    /// Get the tenant_id from the lineage
    pub fn tenant_id(&self) -> &id_type::TenantId {
        match self {
            Self::Tenant { tenant_id }
            | Self::Organization { tenant_id, .. }
            | Self::Merchant { tenant_id, .. }
            | Self::Profile { tenant_id, .. } => tenant_id,
        }
    }

    /// Get the org_id from the lineage
    pub fn org_id(&self) -> Option<&id_type::OrganizationId> {
        match self {
            Self::Tenant { .. } => None,
            Self::Organization { org_id, .. }
            | Self::Merchant { org_id, .. }
            | Self::Profile { org_id, .. } => Some(org_id),
        }
    }

    /// Get the merchant_id from the lineage
    pub fn merchant_id(&self) -> Option<&id_type::MerchantId> {
        match self {
            Self::Tenant { .. } | Self::Organization { .. } => None,
            Self::Merchant { merchant_id, .. } | Self::Profile { merchant_id, .. } => {
                Some(merchant_id)
            }
        }
    }

    /// Get the profile_id from the lineage
    pub fn profile_id(&self) -> Option<&id_type::ProfileId> {
        match self {
            Self::Tenant { .. } | Self::Organization { .. } | Self::Merchant { .. } => None,
            Self::Profile { profile_id, .. } => Some(profile_id),
        }
    }

    /// Get higher lineages from the current lineage
    pub fn get_same_and_higher_lineages(self) -> Vec<Self> {
        match &self {
            Self::Tenant { .. } => vec![self],
            Self::Organization { tenant_id, .. } => vec![
                Self::Tenant {
                    tenant_id: tenant_id.clone(),
                },
                self,
            ],
            Self::Merchant {
                tenant_id, org_id, ..
            } => vec![
                Self::Tenant {
                    tenant_id: tenant_id.clone(),
                },
                Self::Organization {
                    tenant_id: tenant_id.clone(),
                    org_id: org_id.clone(),
                },
                self,
            ],
            Self::Profile {
                tenant_id,
                org_id,
                merchant_id,
                ..
            } => vec![
                Self::Tenant {
                    tenant_id: tenant_id.clone(),
                },
                Self::Organization {
                    tenant_id: tenant_id.clone(),
                    org_id: org_id.clone(),
                },
                Self::Merchant {
                    tenant_id: tenant_id.clone(),
                    org_id: org_id.clone(),
                    merchant_id: merchant_id.clone(),
                },
                self,
            ],
        }
    }
}

/// Struct for holding the theme settings for email
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct EmailThemeConfig {
    /// The entity name to be used in the email
    pub entity_name: String,

    /// The URL of the entity logo to be used in the email
    pub entity_logo_url: String,

    /// The primary color to be used in the email
    pub primary_color: String,

    /// The foreground color to be used in the email
    pub foreground_color: String,

    /// The background color to be used in the email
    pub background_color: String,
}


// Struct: ProcessDisputePTData
// File: crates/router/src/types/api/disputes.rs
// Module: router
// Implementations: 0

pub struct ProcessDisputePTData


// Implementation: impl api::Payment for for Mollie
// File: crates/hyperswitch_connectors/src/connectors/mollie.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Payment for for Mollie


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

impl api::PaymentCapture for for Archipel


// Function: get_ip_address
// File: crates/common_types/src/payments.rs
// Module: common_types

// Documentation: Get the IP address

pub fn get_ip_address(&self) -> Option<String>


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

pub struct AuthoriseIntegrityObject


// Struct: WellsfargopayoutErrorResponse
// File: crates/hyperswitch_connectors/src/connectors/wellsfargopayout/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct WellsfargopayoutErrorResponse


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

impl api::ConnectorAccessToken for for Coingate


// Implementation: impl api::PaymentVoid for for Santander
// File: crates/hyperswitch_connectors/src/connectors/santander.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentVoid for for Santander


// Implementation: impl api::Payment for for Bankofamerica
// File: crates/hyperswitch_connectors/src/connectors/bankofamerica.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Payment for for Bankofamerica


// Implementation: impl ConnectorCommon for for Bitpay
// File: crates/hyperswitch_connectors/src/connectors/bitpay.rs
// Module: hyperswitch_connectors
// Methods: 6 total (0 public)

impl ConnectorCommon for for Bitpay


// File: crates/router/src/core/payment_methods/utils.rs
// Module: router
// Public functions: 3

use std::{str::FromStr, sync::Arc};

use api_models::{
    admin::{self, PaymentMethodsEnabled},
    enums as api_enums,
    payment_methods::RequestPaymentMethodTypes,
};
use common_enums::enums;
#[cfg(feature = "v2")]
use common_utils::ext_traits::{OptionExt, StringExt};
#[cfg(feature = "v2")]
use error_stack::ResultExt;
use euclid::frontend::dir;
use hyperswitch_constraint_graph as cgraph;
use kgraph_utils::{error::KgraphError, transformers::IntoDirValue};
use masking::ExposeInterface;
use storage_impl::redis::cache::{CacheKey, PM_FILTERS_CGRAPH_CACHE};

use crate::{configs::settings, routes::SessionState};
#[cfg(feature = "v2")]
use crate::{
    db::{
        errors,
        storage::{self, enums as storage_enums},
    },
    services::logger,
};

pub fn make_pm_graph(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
    domain_id: cgraph::DomainId,
    payment_methods: &[masking::Secret<serde_json::value::Value>],
    connector: String,
    pm_config_mapping: &settings::ConnectorFilters,
    supported_payment_methods_for_mandate: &settings::SupportedPaymentMethodsForMandate,
    supported_payment_methods_for_update_mandate: &settings::SupportedPaymentMethodsForMandate,
) -> Result<(), KgraphError> {
    for payment_method in payment_methods.iter() {
        let pm_enabled =
            serde_json::from_value::<PaymentMethodsEnabled>(payment_method.clone().expose());
        if let Ok(payment_methods_enabled) = pm_enabled {
            compile_pm_graph(
                builder,
                domain_id,
                payment_methods_enabled.clone(),
                connector.clone(),
                pm_config_mapping,
                supported_payment_methods_for_mandate,
                supported_payment_methods_for_update_mandate,
            )?;
        };
    }
    Ok(())
}

pub async fn get_merchant_pm_filter_graph(
    state: &SessionState,
    key: &str,
) -> Option<Arc<hyperswitch_constraint_graph::ConstraintGraph<dir::DirValue>>> {
    PM_FILTERS_CGRAPH_CACHE
        .get_val::<Arc<hyperswitch_constraint_graph::ConstraintGraph<dir::DirValue>>>(CacheKey {
            key: key.to_string(),
            prefix: state.tenant.redis_key_prefix.clone(),
        })
        .await
}

pub async fn refresh_pm_filters_cache(
    state: &SessionState,
    key: &str,
    graph: cgraph::ConstraintGraph<dir::DirValue>,
) -> Arc<hyperswitch_constraint_graph::ConstraintGraph<dir::DirValue>> {
    let pm_filter_graph = Arc::new(graph);
    PM_FILTERS_CGRAPH_CACHE
        .push(
            CacheKey {
                key: key.to_string(),
                prefix: state.tenant.redis_key_prefix.clone(),
            },
            pm_filter_graph.clone(),
        )
        .await;
    pm_filter_graph
}

fn compile_pm_graph(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
    domain_id: cgraph::DomainId,
    pm_enabled: PaymentMethodsEnabled,
    connector: String,
    config: &settings::ConnectorFilters,
    supported_payment_methods_for_mandate: &settings::SupportedPaymentMethodsForMandate,
    supported_payment_methods_for_update_mandate: &settings::SupportedPaymentMethodsForMandate,
) -> Result<(), KgraphError> {
    if let Some(payment_method_types) = pm_enabled.payment_method_types {
        for pmt in payment_method_types {
            let mut agg_nodes: Vec<(cgraph::NodeId, cgraph::Relation, cgraph::Strength)> =
                Vec::new();
            let mut agg_or_nodes_for_mandate_filters: Vec<(
                cgraph::NodeId,
                cgraph::Relation,
                cgraph::Strength,
            )> = Vec::new();

            // Connector supported for Update mandate filter
            let res = construct_supported_connectors_for_update_mandate_node(
                builder,
                domain_id,
                supported_payment_methods_for_update_mandate,
                pmt.clone(),
                pm_enabled.payment_method,
            );
            if let Ok(Some(connector_eligible_for_update_mandates_node)) = res {
                agg_or_nodes_for_mandate_filters.push((
                    connector_eligible_for_update_mandates_node,
                    cgraph::Relation::Positive,
                    cgraph::Strength::Strong,
                ))
            }

            // Connector supported for mandates filter
            if let Some(supported_pm_for_mandates) = supported_payment_methods_for_mandate
                .0
                .get(&pm_enabled.payment_method)
            {
                if let Some(supported_connector_for_mandates) =
                    supported_pm_for_mandates.0.get(&pmt.payment_method_type)
                {
                    let supported_connectors: Vec<api_enums::Connector> =
                        supported_connector_for_mandates
                            .connector_list
                            .clone()
                            .into_iter()
                            .collect();
                    if let Ok(Some(connector_eligible_for_mandates_node)) =
                        construct_supported_connectors_for_mandate_node(
                            builder,
                            domain_id,
                            supported_connectors,
                        )
                    {
                        agg_or_nodes_for_mandate_filters.push((
                            connector_eligible_for_mandates_node,
                            cgraph::Relation::Positive,
                            cgraph::Strength::Strong,
                        ))
                    }
                }
            }

            // Non Prominent Mandate flows
            let payment_type_non_mandate_value_node = builder.make_value_node(
                cgraph::NodeValue::Value(dir::DirValue::PaymentType(
                    euclid::enums::PaymentType::NonMandate,
                )),
                None,
                None::<()>,
            );
            let payment_type_setup_mandate_value_node = builder.make_value_node(
                cgraph::NodeValue::Value(dir::DirValue::PaymentType(
                    euclid::enums::PaymentType::SetupMandate,
                )),
                None,
                None::<()>,
            );

            let non_major_mandate_any_node = builder
                .make_any_aggregator(
                    &[
                        (
                            payment_type_non_mandate_value_node,
                            cgraph::Relation::Positive,
                            cgraph::Strength::Strong,
                        ),
                        (
                            payment_type_setup_mandate_value_node,
                            cgraph::Relation::Positive,
                            cgraph::Strength::Strong,
                        ),
                    ],
                    None,
                    None::<()>,
                    Some(domain_id),
                )
                .map_err(KgraphError::GraphConstructionError)?;

            agg_or_nodes_for_mandate_filters.push((
                non_major_mandate_any_node,
                cgraph::Relation::Positive,
                cgraph::Strength::Strong,
            ));

            let agg_or_node = builder
                .make_any_aggregator(
                    &agg_or_nodes_for_mandate_filters,
                    None,
                    None::<()>,
                    Some(domain_id),
                )
                .map_err(KgraphError::GraphConstructionError)?;

            agg_nodes.push((
                agg_or_node,
                cgraph::Relation::Positive,
                cgraph::Strength::Strong,
            ));

            // Capture Method filter
            config
                .0
                .get(connector.as_str())
                .or_else(|| config.0.get("default"))
                .map(|inner| {
                    if let Ok(Some(capture_method_filter)) =
                        construct_capture_method_node(builder, inner, pmt.payment_method_type)
                    {
                        agg_nodes.push((
                            capture_method_filter,
                            cgraph::Relation::Negative,
                            cgraph::Strength::Strong,
                        ))
                    }
                });

            // Country filter
            if let Ok(Some(country_node)) = compile_accepted_countries_for_mca(
                builder,
                domain_id,
                pmt.payment_method_type,
                pmt.accepted_countries,
                config,
                connector.clone(),
            ) {
                agg_nodes.push((
                    country_node,
                    cgraph::Relation::Positive,
                    cgraph::Strength::Strong,
                ))
            }

            // Currency filter
            if let Ok(Some(currency_node)) = compile_accepted_currency_for_mca(
                builder,
                domain_id,
                pmt.payment_method_type,
                pmt.accepted_currencies,
                config,
                connector.clone(),
            ) {
                agg_nodes.push((
                    currency_node,
                    cgraph::Relation::Positive,
                    cgraph::Strength::Strong,
                ))
            }

            let and_node_for_all_the_filters = builder
                .make_all_aggregator(&agg_nodes, None, None::<()>, Some(domain_id))
                .map_err(KgraphError::GraphConstructionError)?;

            // Making our output node
            let pmt_info = "PaymentMethodType";
            let dir_node: cgraph::NodeValue<dir::DirValue> =
                (pmt.payment_method_type, pm_enabled.payment_method)
                    .into_dir_value()
                    .map(Into::into)?;
            let payment_method_type_value_node =
                builder.make_value_node(dir_node, Some(pmt_info), None::<()>);

            builder
                .make_edge(
                    and_node_for_all_the_filters,
                    payment_method_type_value_node,
                    cgraph::Strength::Normal,
                    cgraph::Relation::Positive,
                    Some(domain_id),
                )
                .map_err(KgraphError::GraphConstructionError)?;
        }
    }
    Ok(())
}

fn construct_supported_connectors_for_update_mandate_node(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
    domain_id: cgraph::DomainId,
    supported_payment_methods_for_update_mandate: &settings::SupportedPaymentMethodsForMandate,
    pmt: RequestPaymentMethodTypes,
    payment_method: enums::PaymentMethod,
) -> Result<Option<cgraph::NodeId>, KgraphError> {
    let card_value_node = builder.make_value_node(
        cgraph::NodeValue::Value(dir::DirValue::PaymentMethod(enums::PaymentMethod::Card)),
        None,
        None::<()>,
    );

    let payment_type_value_node = builder.make_value_node(
        cgraph::NodeValue::Value(dir::DirValue::PaymentType(
            euclid::enums::PaymentType::UpdateMandate,
        )),
        None,
        None::<()>,
    );

    let mut agg_nodes: Vec<(cgraph::NodeId, cgraph::Relation, cgraph::Strength)> = Vec::new();
    let mut card_dir_values = Vec::new();
    let mut non_card_dir_values = Vec::new();

    if let Some(supported_pm_for_mandates) = supported_payment_methods_for_update_mandate
        .0
        .get(&payment_method)
    {
        if payment_method == enums::PaymentMethod::Card {
            if let Some(credit_connector_list) = supported_pm_for_mandates
                .0
                .get(&api_enums::PaymentMethodType::Credit)
            {
                card_dir_values.extend(
                    credit_connector_list
                        .connector_list
                        .clone()
                        .into_iter()
                        .filter_map(|connector| {
                            api_enums::RoutableConnectors::from_str(connector.to_string().as_str())
                                .ok()
                                .map(|connector| {
                                    dir::DirValue::Connector(Box::new(
                                        api_models::routing::ast::ConnectorChoice { connector },
                                    ))
                                })
                        }),
                );
            }

            if let Some(debit_connector_list) = supported_pm_for_mandates
                .0
                .get(&api_enums::PaymentMethodType::Debit)
            {
                card_dir_values.extend(
                    debit_connector_list
                        .connector_list
                        .clone()
                        .into_iter()
                        .filter_map(|connector| {
                            api_enums::RoutableConnectors::from_str(connector.to_string().as_str())
                                .ok()
                                .map(|connector| {
                                    dir::DirValue::Connector(Box::new(
                                        api_models::routing::ast::ConnectorChoice { connector },
                                    ))
                                })
                        }),
                );
            }
            let card_in_node = builder
                .make_in_aggregator(card_dir_values, None, None::<()>)
                .map_err(KgraphError::GraphConstructionError)?;

            let card_and_node = builder
                .make_all_aggregator(
                    &[
                        (
                            card_value_node,
                            cgraph::Relation::Positive,
                            cgraph::Strength::Strong,
                        ),
                        (
                            payment_type_value_node,
                            cgraph::Relation::Positive,
                            cgraph::Strength::Strong,
                        ),
                        (
                            card_in_node,
                            cgraph::Relation::Positive,
                            cgraph::Strength::Strong,
                        ),
                    ],
                    None,
                    None::<()>,
                    Some(domain_id),
                )
                .map_err(KgraphError::GraphConstructionError)?;

            agg_nodes.push((
                card_and_node,
                cgraph::Relation::Positive,
                cgraph::Strength::Strong,
            ));
        } else if let Some(connector_list) =
            supported_pm_for_mandates.0.get(&pmt.payment_method_type)
        {
            non_card_dir_values.extend(
                connector_list
                    .connector_list
                    .clone()
                    .into_iter()
                    .filter_map(|connector| {
                        api_enums::RoutableConnectors::from_str(connector.to_string().as_str())
                            .ok()
                            .map(|connector| {
                                dir::DirValue::Connector(Box::new(
                                    api_models::routing::ast::ConnectorChoice { connector },
                                ))
                            })
                    }),
            );
            let non_card_mandate_in_node = builder
                .make_in_aggregator(non_card_dir_values, None, None::<()>)
                .map_err(KgraphError::GraphConstructionError)?;

            let non_card_and_node = builder
                .make_all_aggregator(
                    &[
                        (
                            card_value_node,
                            cgraph::Relation::Negative,
                            cgraph::Strength::Strong,
                        ),
                        (
                            payment_type_value_node,
                            cgraph::Relation::Positive,
                            cgraph::Strength::Strong,
                        ),
                        (
                            non_card_mandate_in_node,
                            cgraph::Relation::Positive,
                            cgraph::Strength::Strong,
                        ),
                    ],
                    None,
                    None::<()>,
                    Some(domain_id),
                )
                .map_err(KgraphError::GraphConstructionError)?;

            agg_nodes.push((
                non_card_and_node,
                cgraph::Relation::Positive,
                cgraph::Strength::Strong,
            ));
        }
    }

    if !agg_nodes.is_empty() {
        Ok(Some(
            builder
                .make_any_aggregator(
                    &agg_nodes,
                    Some("any node for card and non card pm"),
                    None::<()>,
                    Some(domain_id),
                )
                .map_err(KgraphError::GraphConstructionError)?,
        ))
    } else {
        Ok(None)
    }
}

fn construct_supported_connectors_for_mandate_node(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
    domain_id: cgraph::DomainId,
    eligible_connectors: Vec<api_enums::Connector>,
) -> Result<Option<cgraph::NodeId>, KgraphError> {
    let payment_type_value_node = builder.make_value_node(
        cgraph::NodeValue::Value(dir::DirValue::PaymentType(
            euclid::enums::PaymentType::NewMandate,
        )),
        None,
        None::<()>,
    );
    let connectors_from_config: Vec<dir::DirValue> = eligible_connectors
        .into_iter()
        .filter_map(|connector| {
            match api_enums::RoutableConnectors::from_str(connector.to_string().as_str()) {
                Ok(connector) => Some(dir::DirValue::Connector(Box::new(
                    api_models::routing::ast::ConnectorChoice { connector },
                ))),
                Err(_) => None,
            }
        })
        .collect();

    if connectors_from_config.is_empty() {
        Ok(None)
    } else {
        let connector_in_aggregator = builder
            .make_in_aggregator(connectors_from_config, None, None::<()>)
            .map_err(KgraphError::GraphConstructionError)?;
        Ok(Some(
            builder
                .make_all_aggregator(
                    &[
                        (
                            payment_type_value_node,
                            cgraph::Relation::Positive,
                            cgraph::Strength::Strong,
                        ),
                        (
                            connector_in_aggregator,
                            cgraph::Relation::Positive,
                            cgraph::Strength::Strong,
                        ),
                    ],
                    None,
                    None::<()>,
                    Some(domain_id),
                )
                .map_err(KgraphError::GraphConstructionError)?,
        ))
    }
}

fn construct_capture_method_node(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
    payment_method_filters: &settings::PaymentMethodFilters,
    payment_method_type: api_enums::PaymentMethodType,
) -> Result<Option<cgraph::NodeId>, KgraphError> {
    if !payment_method_filters
        .0
        .get(&settings::PaymentMethodFilterKey::PaymentMethodType(
            payment_method_type,
        ))
        .and_then(|v| v.not_available_flows)
        .and_then(|v| v.capture_method)
        .map(|v| !matches!(v, api_enums::CaptureMethod::Manual))
        .unwrap_or(true)
    {
        return Ok(Some(builder.make_value_node(
            cgraph::NodeValue::Value(dir::DirValue::CaptureMethod(
                common_enums::CaptureMethod::Manual,
            )),
            None,
            None::<()>,
        )));
    }
    Ok(None)
}

// fn construct_card_network_nodes(
//     builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
//     mca_card_networks: Vec<api_enums::CardNetwork>,
// ) -> Result<Option<cgraph::NodeId>, KgraphError> {
//     Ok(Some(
//         builder
//             .make_in_aggregator(
//                 mca_card_networks
//                     .into_iter()
//                     .map(dir::DirValue::CardNetwork)
//                     .collect(),
//                 None,
//                 None::<()>,
//             )
//             .map_err(KgraphError::GraphConstructionError)?,
//     ))
// }

fn compile_accepted_countries_for_mca(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
    domain_id: cgraph::DomainId,
    payment_method_type: enums::PaymentMethodType,
    pm_countries: Option<admin::AcceptedCountries>,
    config: &settings::ConnectorFilters,
    connector: String,
) -> Result<Option<cgraph::NodeId>, KgraphError> {
    let mut agg_nodes: Vec<(cgraph::NodeId, cgraph::Relation, cgraph::Strength)> = Vec::new();

    // Country from the MCA
    if let Some(pm_obj_countries) = pm_countries {
        match pm_obj_countries {
            admin::AcceptedCountries::EnableOnly(countries) => {
                let pm_object_country_value_node = builder
                    .make_in_aggregator(
                        countries
                            .into_iter()
                            .map(|country| {
                                dir::DirValue::BillingCountry(common_enums::Country::from_alpha2(
                                    country,
                                ))
                            })
                            .collect(),
                        None,
                        None::<()>,
                    )
                    .map_err(KgraphError::GraphConstructionError)?;
                agg_nodes.push((
                    pm_object_country_value_node,
                    cgraph::Relation::Positive,
                    cgraph::Strength::Weak,
                ));
            }
            admin::AcceptedCountries::DisableOnly(countries) => {
                let pm_object_country_value_node = builder
                    .make_in_aggregator(
                        countries
                            .into_iter()
                            .map(|country| {
                                dir::DirValue::BillingCountry(common_enums::Country::from_alpha2(
                                    country,
                                ))
                            })
                            .collect(),
                        None,
                        None::<()>,
                    )
                    .map_err(KgraphError::GraphConstructionError)?;
                agg_nodes.push((
                    pm_object_country_value_node,
                    cgraph::Relation::Negative,
                    cgraph::Strength::Weak,
                ));
            }
            admin::AcceptedCountries::AllAccepted => return Ok(None),
        }
    }

    // country from config
    if let Some(derived_config) = config
        .0
        .get(connector.as_str())
        .or_else(|| config.0.get("default"))
    {
        if let Some(value) =
            derived_config
                .0
                .get(&settings::PaymentMethodFilterKey::PaymentMethodType(
                    payment_method_type,
                ))
        {
            if let Some(config_countries) = value.country.as_ref() {
                let config_countries: Vec<common_enums::Country> = Vec::from_iter(config_countries)
                    .into_iter()
                    .map(|country| common_enums::Country::from_alpha2(*country))
                    .collect();
                let dir_countries: Vec<dir::DirValue> = config_countries
                    .into_iter()
                    .map(dir::DirValue::BillingCountry)
                    .collect();

                let config_country_agg_node = builder
                    .make_in_aggregator(dir_countries, None, None::<()>)
                    .map_err(KgraphError::GraphConstructionError)?;

                agg_nodes.push((
                    config_country_agg_node,
                    cgraph::Relation::Positive,
                    cgraph::Strength::Weak,
                ));
            }
        } else if let Some(default_derived_config) = config.0.get("default") {
            if let Some(value) =
                default_derived_config
                    .0
                    .get(&settings::PaymentMethodFilterKey::PaymentMethodType(
                        payment_method_type,
                    ))
            {
                if let Some(config_countries) = value.country.as_ref() {
                    let config_countries: Vec<common_enums::Country> =
                        Vec::from_iter(config_countries)
                            .into_iter()
                            .map(|country| common_enums::Country::from_alpha2(*country))
                            .collect();
                    let dir_countries: Vec<dir::DirValue> = config_countries
                        .into_iter()
                        .map(dir::DirValue::BillingCountry)
                        .collect();

                    let config_country_agg_node = builder
                        .make_in_aggregator(dir_countries, None, None::<()>)
                        .map_err(KgraphError::GraphConstructionError)?;

                    agg_nodes.push((
                        config_country_agg_node,
                        cgraph::Relation::Positive,
                        cgraph::Strength::Weak,
                    ));
                }
            }
        };
    }
    Ok(Some(
        builder
            .make_all_aggregator(&agg_nodes, None, None::<()>, Some(domain_id))
            .map_err(KgraphError::GraphConstructionError)?,
    ))
}

fn compile_accepted_currency_for_mca(
    builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
    domain_id: cgraph::DomainId,
    payment_method_type: enums::PaymentMethodType,
    pm_currency: Option<admin::AcceptedCurrencies>,
    config: &settings::ConnectorFilters,
    connector: String,
) -> Result<Option<cgraph::NodeId>, KgraphError> {
    let mut agg_nodes: Vec<(cgraph::NodeId, cgraph::Relation, cgraph::Strength)> = Vec::new();
    // Currency from the MCA
    if let Some(pm_obj_currency) = pm_currency {
        match pm_obj_currency {
            admin::AcceptedCurrencies::EnableOnly(currency) => {
                let pm_object_currency_value_node = builder
                    .make_in_aggregator(
                        currency
                            .into_iter()
                            .map(dir::DirValue::PaymentCurrency)
                            .collect(),
                        None,
                        None::<()>,
                    )
                    .map_err(KgraphError::GraphConstructionError)?;
                agg_nodes.push((
                    pm_object_currency_value_node,
                    cgraph::Relation::Positive,
                    cgraph::Strength::Weak,
                ));
            }
            admin::AcceptedCurrencies::DisableOnly(currency) => {
                let pm_object_currency_value_node = builder
                    .make_in_aggregator(
                        currency
                            .into_iter()
                            .map(dir::DirValue::PaymentCurrency)
                            .collect(),
                        None,
                        None::<()>,
                    )
                    .map_err(KgraphError::GraphConstructionError)?;
                agg_nodes.push((
                    pm_object_currency_value_node,
                    cgraph::Relation::Negative,
                    cgraph::Strength::Weak,
                ));
            }
            admin::AcceptedCurrencies::AllAccepted => return Ok(None),
        }
    }

    // currency from config
    if let Some(derived_config) = config
        .0
        .get(connector.as_str())
        .or_else(|| config.0.get("default"))
    {
        if let Some(value) =
            derived_config
                .0
                .get(&settings::PaymentMethodFilterKey::PaymentMethodType(
                    payment_method_type,
                ))
        {
            if let Some(config_currencies) = value.currency.as_ref() {
                let config_currency: Vec<common_enums::Currency> =
                    Vec::from_iter(config_currencies)
                        .into_iter()
                        .copied()
                        .collect();

                let dir_currencies: Vec<dir::DirValue> = config_currency
                    .into_iter()
                    .map(dir::DirValue::PaymentCurrency)
                    .collect();

                let config_currency_agg_node = builder
                    .make_in_aggregator(dir_currencies, None, None::<()>)
                    .map_err(KgraphError::GraphConstructionError)?;

                agg_nodes.push((
                    config_currency_agg_node,
                    cgraph::Relation::Positive,
                    cgraph::Strength::Weak,
                ));
            }
        } else if let Some(default_derived_config) = config.0.get("default") {
            if let Some(value) =
                default_derived_config
                    .0
                    .get(&settings::PaymentMethodFilterKey::PaymentMethodType(
                        payment_method_type,
                    ))
            {
                if let Some(config_currencies) = value.currency.as_ref() {
                    let config_currency: Vec<common_enums::Currency> =
                        Vec::from_iter(config_currencies)
                            .into_iter()
                            .copied()
                            .collect();

                    let dir_currencies: Vec<dir::DirValue> = config_currency
                        .into_iter()
                        .map(dir::DirValue::PaymentCurrency)
                        .collect();

                    let config_currency_agg_node = builder
                        .make_in_aggregator(dir_currencies, None, None::<()>)
                        .map_err(KgraphError::GraphConstructionError)?;

                    agg_nodes.push((
                        config_currency_agg_node,
                        cgraph::Relation::Positive,
                        cgraph::Strength::Weak,
                    ))
                }
            }
        };
    }
    Ok(Some(
        builder
            .make_all_aggregator(&agg_nodes, None, None::<()>, Some(domain_id))
            .map_err(KgraphError::GraphConstructionError)?,
    ))
}

#[cfg(feature = "v2")]
pub(super) async fn retrieve_payment_token_data(
    state: &SessionState,
    token: String,
    payment_method: Option<&storage_enums::PaymentMethod>,
) -> errors::RouterResult<storage::PaymentTokenData> {
    let redis_conn = state
        .store
        .get_redis_conn()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to get redis connection")?;

    let key = format!(
        "pm_token_{}_{}_hyperswitch",
        token,
        payment_method
            .get_required_value("payment_method")
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Payment method is required")?
    );

    let token_data_string = redis_conn
        .get_key::<Option<String>>(&key.into())
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to fetch the token from redis")?
        .ok_or(error_stack::Report::new(
            errors::ApiErrorResponse::UnprocessableEntity {
                message: "Token is invalid or expired".to_owned(),
            },
        ))?;

    token_data_string
        .clone()
        .parse_struct("PaymentTokenData")
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("failed to deserialize hyperswitch token data")
}

#[cfg(feature = "v2")]
pub(super) async fn delete_payment_token_data(
    state: &SessionState,
    key_for_token: &str,
) -> errors::RouterResult<()> {
    let redis_conn = state
        .store
        .get_redis_conn()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to get redis connection")?;
    match redis_conn.delete_key(&key_for_token.into()).await {
        Ok(_) => Ok(()),
        Err(err) => {
            {
                logger::error!("Error while deleting redis key: {:?}", err)
            };
            Ok(())
        }
    }
}


// Function: start_web_server
// File: crates/router/src/bin/scheduler.rs
// Module: router

pub fn start_web_server(
    state: routes::AppState,
    service: String,
) -> errors::ApplicationResult<Server>


// Function: card_migrated
// File: crates/payment_methods/src/core/migration.rs
// Module: payment_methods

pub fn card_migrated(&mut self, card_migrated: bool)


// Struct: RoutingRetrieveQuery
// File: crates/api_models/src/routing.rs
// Module: api_models
// Implementations: 0

pub struct RoutingRetrieveQuery


// Struct: ConnectorBankNames
// File: crates/payment_methods/src/configs/settings.rs
// Module: payment_methods
// Implementations: 0

pub struct ConnectorBankNames


// Function: get_payment_methods_supporting_extended_authorization
// File: crates/common_enums/src/connector_enums.rs
// Module: common_enums

pub fn get_payment_methods_supporting_extended_authorization(self) -> HashSet<PaymentMethod>


// Function: to_merchant_category_name
// File: crates/common_enums/src/enums.rs
// Module: common_enums

pub fn to_merchant_category_name(&self) -> MerchantCategory


// Implementation: impl api::Payment for for HyperswitchVault
// File: crates/hyperswitch_connectors/src/connectors/hyperswitch_vault.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Payment for for HyperswitchVault


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

pub struct Amount


// Module Structure
// File: crates/hyperswitch_connectors/src/connectors/digitalvirgo.rs
// Module: hyperswitch_connectors

// Public submodules:
pub mod transformers;


// Struct: DlocalErrorResponse
// File: crates/hyperswitch_connectors/src/connectors/dlocal/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct DlocalErrorResponse


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

use std::str::FromStr;

use cards::CardNumber;
use common_utils::{pii::Email, types::MinorUnit};
use hyperswitch_domain_models::types::OrderDetailsWithAmount;
use masking::Secret;
use router::types::{self, domain, storage::enums};

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

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

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

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

static CONNECTOR: ZenTest = ZenTest {};

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

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

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

// Synchronizes a payment using the manual capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_sync_authorized_payment() {
    let authorize_response = CONNECTOR
        .authorize_payment(None, None)
        .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(),
                ),
                encoded_data: None,
                capture_method: None,
                sync_type: types::SyncRequestType::SinglePaymentSync,
                connector_meta: None,
                mandate_id: None,
                payment_method_type: None,
                currency: enums::Currency::USD,
                payment_experience: None,
                amount: MinorUnit::new(100),
                integrity_object: None,
                ..Default::default()
            }),
            None,
        )
        .await
        .expect("PSync response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
}

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

// Refunds a payment using the manual capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card and capture is not supported"]
#[actix_web::test]
async fn should_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(None, None, None, None)
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

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

// Synchronizes a refund using the manual capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card and capture is not supported"]
#[actix_web::test]
async fn should_sync_manually_captured_refund() {
    let refund_response = CONNECTOR
        .capture_payment_and_refund(None, None, None, None)
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

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

// Synchronizes a payment using the automatic capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_sync_auto_captured_payment() {
    let authorize_response = CONNECTOR.make_payment(None, None).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(),
                ),
                encoded_data: None,
                capture_method: Some(enums::CaptureMethod::Automatic),
                sync_type: types::SyncRequestType::SinglePaymentSync,
                connector_meta: None,
                mandate_id: None,
                payment_method_type: None,
                currency: enums::Currency::USD,
                payment_experience: None,
                amount: MinorUnit::new(100),
                integrity_object: None,
                ..Default::default()
            }),
            None,
        )
        .await
        .unwrap();
    assert_eq!(response.status, enums::AttemptStatus::Charged,);
}

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

// Partially refunds a payment using the automatic capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_partially_refund_succeeded_payment() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            None,
        )
        .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).
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_refund_succeeded_payment_multiple_times() {
    CONNECTOR
        .make_payment_and_multiple_refund(
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            None,
        )
        .await;
}

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

// Cards Negative scenarios
// Creates a payment with incorrect card number.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_card_number() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_number: CardNumber::from_str("1234567891011").unwrap(),
                    ..utils::CCardType::default().0
                }),
                order_details: Some(vec![OrderDetailsWithAmount {
                    product_name: "iphone 13".to_string(),
                    quantity: 1,
                    amount: MinorUnit::new(1000),
                    product_img_link: None,
                    requires_shipping: None,
                    product_id: None,
                    category: None,
                    sub_category: None,
                    brand: None,
                    product_type: None,
                    product_tax_code: None,
                    tax_rate: None,
                    total_tax_amount: None,
                    description: None,
                    sku: None,
                    upc: None,
                    commodity_code: None,
                    unit_of_measure: None,
                    total_amount: None,
                    unit_discount_amount: None,
                }]),
                email: Some(Email::from_str("test@gmail.com").unwrap()),
                webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()),
                ..utils::PaymentAuthorizeType::default().0
            }),
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        response
            .response
            .unwrap_err()
            .message
            .split_once(';')
            .unwrap()
            .0,
        "Request data doesn't pass validation".to_string(),
    );
}

// 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: domain::PaymentMethodData::Card(domain::Card {
                    card_cvc: Secret::new("12345".to_string()),
                    ..utils::CCardType::default().0
                }),
                order_details: Some(vec![OrderDetailsWithAmount {
                    product_name: "iphone 13".to_string(),
                    quantity: 1,
                    amount: MinorUnit::new(1000),
                    product_img_link: None,
                    requires_shipping: None,
                    product_id: None,
                    category: None,
                    sub_category: None,
                    brand: None,
                    product_type: None,
                    product_tax_code: None,
                    tax_rate: None,
                    total_tax_amount: None,
                    description: None,
                    sku: None,
                    upc: None,
                    commodity_code: None,
                    unit_of_measure: None,
                    total_amount: None,
                    unit_discount_amount: None,
                }]),
                email: Some(Email::from_str("test@gmail.com").unwrap()),
                webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()),
                ..utils::PaymentAuthorizeType::default().0
            }),
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        response
            .response
            .unwrap_err()
            .message
            .split_once(';')
            .unwrap()
            .0,
        "Request data doesn't pass validation".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: domain::PaymentMethodData::Card(domain::Card {
                    card_exp_month: Secret::new("20".to_string()),
                    ..utils::CCardType::default().0
                }),
                order_details: Some(vec![OrderDetailsWithAmount {
                    product_name: "iphone 13".to_string(),
                    quantity: 1,
                    amount: MinorUnit::new(1000),
                    product_img_link: None,
                    requires_shipping: None,
                    product_id: None,
                    category: None,
                    sub_category: None,
                    brand: None,
                    product_type: None,
                    product_tax_code: None,
                    tax_rate: None,
                    total_tax_amount: None,
                    description: None,
                    sku: None,
                    upc: None,
                    commodity_code: None,
                    unit_of_measure: None,
                    total_amount: None,
                    unit_discount_amount: None,
                }]),
                email: Some(Email::from_str("test@gmail.com").unwrap()),
                webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()),
                ..utils::PaymentAuthorizeType::default().0
            }),
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        response
            .response
            .unwrap_err()
            .message
            .split_once(';')
            .unwrap()
            .0,
        "Request data doesn't pass validation".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: domain::PaymentMethodData::Card(domain::Card {
                    card_exp_year: Secret::new("2000".to_string()),
                    ..utils::CCardType::default().0
                }),
                order_details: Some(vec![OrderDetailsWithAmount {
                    product_name: "iphone 13".to_string(),
                    quantity: 1,
                    amount: MinorUnit::new(1000),
                    product_img_link: None,
                    requires_shipping: None,
                    product_id: None,
                    category: None,
                    sub_category: None,
                    brand: None,
                    product_type: None,
                    product_tax_code: None,
                    tax_rate: None,
                    total_tax_amount: None,
                    description: None,
                    sku: None,
                    upc: None,
                    commodity_code: None,
                    unit_of_measure: None,
                    total_amount: None,
                    unit_discount_amount: None,
                }]),
                email: Some(Email::from_str("test@gmail.com").unwrap()),
                webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()),
                ..utils::PaymentAuthorizeType::default().0
            }),
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        response
            .response
            .unwrap_err()
            .message
            .split_once(';')
            .unwrap()
            .0,
        "Request data doesn't pass validation".to_string(),
    );
}

// Voids a payment using automatic capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card and void is not supported"]
#[actix_web::test]
async fn should_fail_void_payment_for_auto_capture() {
    let authorize_response = CONNECTOR.make_payment(None, None).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, None)
        .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.
#[ignore = "Connector triggers 3DS payment on test card and capture is not supported"]
#[actix_web::test]
async fn should_fail_capture_for_invalid_payment() {
    let capture_response = CONNECTOR
        .capture_payment("123456789".to_string(), None, None)
        .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.
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_fail_for_refund_amount_higher_than_payment_amount() {
    let response = CONNECTOR
        .make_payment_and_refund(
            None,
            Some(types::RefundsData {
                refund_amount: 150,
                ..utils::PaymentRefundType::default().0
            }),
            None,
        )
        .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


// Struct: AppState
// File: crates/drainer/src/settings.rs
// Module: drainer
// Implementations: 1

pub struct AppState


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

impl api::ConnectorAccessToken for for Cybersource


// Implementation: impl Capturable for for CompleteAuthorizeData
// File: crates/router/src/types.rs
// Module: router
// Methods: 2 total (0 public)

impl Capturable for for CompleteAuthorizeData


// File: crates/router/src/types/storage/configs.rs
// Module: router

pub use diesel_models::configs::{Config, ConfigNew, ConfigUpdate, ConfigUpdateInternal};


// Implementation: impl api::PaymentToken for for Taxjar
// File: crates/hyperswitch_connectors/src/connectors/taxjar.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentToken for for Taxjar


// Struct: VoltAuthUpdateResponse
// File: crates/hyperswitch_connectors/src/connectors/volt/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct VoltAuthUpdateResponse


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

impl Responder


// Struct: NordeaPaymentsConfirmResponse
// File: crates/hyperswitch_connectors/src/connectors/nordea/responses.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NordeaPaymentsConfirmResponse


{
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        item: &ChargebeeRouterData<&hyperswitch_domain_models::types::ConnectorCustomerRouterData>,
    ) -> Result<Self, Self::Error> {
        let req = &item.router_data.request;

        Ok(Self {
            customer_id: req
                .customer_id
                .as_ref()
                .ok_or_else(|| errors::ConnectorError::MissingRequiredField {
                    field_name: "customer_id",
                })?
                .clone(),
            name: req.name.clone(),
            email: req.email.clone(),
            billing_address_first_name: req
                .billing_address
                .as_ref()
                .and_then(|address| address.first_name.clone()),
            billing_address_last_name: req
                .billing_address
                .as_ref()
                .and_then(|address| address.last_name.clone()),
            billing_address_line1: req
                .billing_address
                .as_ref()
                .and_then(|addr| addr.line1.clone()),
            billing_address_city: req
                .billing_address
                .as_ref()
                .and_then(|addr| addr.city.clone()),
            billing_address_country: req
                .billing_address
                .as_ref()
                .and_then(|addr| addr.country.map(|country| country.to_string())),
            billing_address_state: req
                .billing_address
                .as_ref()
                .and_then(|addr| addr.state.clone()),
            billing_address_zip: req
                .billing_address
                .as_ref()
                .and_then(|addr| addr.zip.clone()),
        })
    }
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ChargebeeCustomerCreateResponse {
    pub customer: ChargebeeCustomerDetails,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ChargebeeCustomerDetails {
    pub id: String,
    #[serde(rename = "first_name")]
    pub name: Option<Secret<String>>,
    pub email: Option<Email>,
    pub billing_address: Option<api_models::payments::AddressDetails>,
}

impl
    TryFrom<
        ResponseRouterData<
            CreateConnectorCustomer,
            ChargebeeCustomerCreateResponse,
            ConnectorCustomerData,
            PaymentsResponseData,
        >,
    > for hyperswitch_domain_models::types::ConnectorCustomerRouterData
{
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(
        item: ResponseRouterData<
            CreateConnectorCustomer,
            ChargebeeCustomerCreateResponse,
            ConnectorCustomerData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        let customer_response = &item.response.customer;

        Ok(Self {
            response: Ok(PaymentsResponseData::ConnectorCustomerResponse(
                ConnectorCustomerResponseData::new(
                    customer_response.id.clone(),
                    customer_response
                        .name
                        .as_ref()
                        .map(|name| name.clone().expose()),
                    customer_response
                        .email
                        .as_ref()
                        .map(|email| email.clone().expose().expose()),
                    customer_response.billing_address.clone(),
                ),
            )),
            ..item.data
        })
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChargebeeSubscriptionEstimateRequest {
    pub price_id: String,
}

impl TryFrom<&GetSubscriptionEstimateRouterData> for ChargebeeSubscriptionEstimateRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &GetSubscriptionEstimateRouterData) -> Result<Self, Self::Error> {
        let price_id = item.request.price_id.to_owned();
        Ok(Self { price_id })
    }
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChargebeeGetPlanPricesResponse {
    pub list: Vec<ChargebeeGetPlanPriceList>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChargebeeGetPlanPriceList {
    pub item_price: ChargebeePlanPriceItem,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChargebeePlanPriceItem {
    pub id: String,
    pub name: String,
    pub currency_code: common_enums::Currency,
    pub free_quantity: i64,
    #[serde(default, with = "common_utils::custom_serde::timestamp::option")]
    pub created_at: Option<PrimitiveDateTime>,
    pub deleted: bool,
    pub item_id: Option<String>,
    pub period: i64,
    pub period_unit: ChargebeePeriodUnit,
    pub trial_period: Option<i64>,
    pub trial_period_unit: ChargebeeTrialPeriodUnit,
    pub price: MinorUnit,
    pub pricing_model: ChargebeePricingModel,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ChargebeePricingModel {
    FlatFee,
    PerUnit,
    Tiered,
    Volume,
    Stairstep,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ChargebeePeriodUnit {
    Day,
    Week,
    Month,
    Year,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ChargebeeTrialPeriodUnit {
    Day,
    Month,
}

impl<F, T>
    TryFrom<
        ResponseRouterData<F, ChargebeeGetPlanPricesResponse, T, GetSubscriptionPlanPricesResponse>,
    > for RouterData<F, T, GetSubscriptionPlanPricesResponse>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            ChargebeeGetPlanPricesResponse,
            T,
            GetSubscriptionPlanPricesResponse,
        >,
    ) -> Result<Self, Self::Error> {
        let plan_prices = item
            .response
            .list
            .into_iter()
            .map(|prices| subscriptions::SubscriptionPlanPrices {
                price_id: prices.item_price.id,
                plan_id: prices.item_price.item_id,
                amount: prices.item_price.price,
                currency: prices.item_price.currency_code,
                interval: match prices.item_price.period_unit {
                    ChargebeePeriodUnit::Day => subscriptions::PeriodUnit::Day,
                    ChargebeePeriodUnit::Week => subscriptions::PeriodUnit::Week,
                    ChargebeePeriodUnit::Month => subscriptions::PeriodUnit::Month,
                    ChargebeePeriodUnit::Year => subscriptions::PeriodUnit::Year,
                },
                interval_count: prices.item_price.period,
                trial_period: prices.item_price.trial_period,
                trial_period_unit: match prices.item_price.trial_period_unit {
                    ChargebeeTrialPeriodUnit::Day => Some(subscriptions::PeriodUnit::Day),
                    ChargebeeTrialPeriodUnit::Month => Some(subscriptions::PeriodUnit::Month),
                },
            })
            .collect();
        Ok(Self {
            response: Ok(GetSubscriptionPlanPricesResponse { list: plan_prices }),
            ..item.data
        })
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubscriptionEstimateResponse {
    pub estimate: ChargebeeEstimate,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChargebeeEstimate {
    pub created_at: i64,
    /// type of the object will be `estimate`
    pub object: String,
    pub subscription_estimate: SubscriptionEstimate,
    pub invoice_estimate: InvoiceEstimate,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubscriptionEstimate {
    pub status: String,
    #[serde(default, with = "common_utils::custom_serde::timestamp::option")]
    pub next_billing_at: Option<PrimitiveDateTime>,
    /// type of the object will be `subscription_estimate`
    pub object: String,
    pub currency_code: enums::Currency,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InvoiceEstimate {
    pub recurring: bool,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub date: PrimitiveDateTime,
    pub price_type: String,
    pub sub_total: MinorUnit,
    pub total: MinorUnit,
    pub credits_applied: MinorUnit,
    pub amount_paid: MinorUnit,
    pub amount_due: MinorUnit,
    /// type of the object will be `invoice_estimate`
    pub object: String,
    pub customer_id: String,
    pub line_items: Vec<LineItem>,
    pub currency_code: enums::Currency,
    pub round_off_amount: MinorUnit,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LineItem {
    pub id: String,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub date_from: PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub date_to: PrimitiveDateTime,
    pub unit_amount: MinorUnit,
    pub quantity: i64,
    pub amount: MinorUnit,
    pub pricing_model: String,
    pub is_taxed: bool,
    pub tax_amount: MinorUnit,
    /// type of the object will be `line_item`
    pub object: String,
    pub customer_id: String,
    pub description: String,
    pub entity_type: String,
    pub entity_id: String,
    pub discount_amount: MinorUnit,
    pub item_level_discount_amount: MinorUnit,
}


// Function: get_groups_and_resources_for_role_from_token
// File: crates/router/src/core/user_role/role.rs
// Module: router

pub fn get_groups_and_resources_for_role_from_token(
    state: SessionState,
    user_from_token: UserFromToken,
) -> UserResponse<role_api::GroupsAndResources>


// Function: generate_fingerprint
// File: crates/router/src/core/blocklist/transformers.rs
// Module: router

pub fn generate_fingerprint(
    state: &routes::SessionState,
    card_number: StrongSecret<String>,
    hash_key: StrongSecret<String>,
    locker_choice: api_enums::LockerChoice,
) -> CustomResult<blocklist::GenerateFingerprintResponsePayload, errors::VaultError>


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

pub struct MerchantLevel


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

pub fn migrate_rules_for_profile(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    query_params: routing_types::RuleMigrationQuery,
) -> RouterResult<routing_types::RuleMigrationResult>


// Implementation: impl api::Refund for for Mollie
// File: crates/hyperswitch_connectors/src/connectors/mollie.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::Refund for for Mollie


// Struct: CeleroPaymentsResponse
// File: crates/hyperswitch_connectors/src/connectors/celero/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CeleroPaymentsResponse