        let redis_conn = state
            .store
            .get_redis_conn()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to get redis connection")?;
        redis_conn
            .serialize_and_set_key_with_expiry(
                &self.key_for_token.as_str().into(),
                token,
                fulfillment_time,
            )
            .await
            .change_context(errors::StorageError::KVError)
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to add token in redis")?;

        Ok(())
    }

    pub fn should_delete_payment_method_token(&self, status: IntentStatus) -> bool {
        // RequiresMerchantAction: When the payment goes for merchant review incase of potential fraud allow payment_method_token to be stored until resolved
        ![
            IntentStatus::RequiresCustomerAction,
            IntentStatus::RequiresMerchantAction,
        ]
        .contains(&status)
    }

    pub async fn delete(&self, state: &SessionState) -> CustomResult<(), errors::ApiErrorResponse> {
        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(&self.key_for_token.as_str().into())
            .await
        {
            Ok(_) => Ok(()),
            Err(err) => {
                {
                    logger::info!("Error while deleting redis key: {:?}", err)
                };
                Ok(())
            }
        }
    }
}

#[cfg(all(feature = "v1", any(feature = "olap", feature = "oltp")))]
#[instrument(skip_all, fields(flow = ?Flow::TokenizeCard))]
pub async fn tokenize_card_api(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<payment_methods::CardNetworkTokenizeRequest>,
) -> HttpResponse {
    let flow = Flow::TokenizeCard;

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        json_payload.into_inner(),
        |state, _, req, _| async move {
            let merchant_id = req.merchant_id.clone();
            let (key_store, merchant_account) = get_merchant_account(&state, &merchant_id).await?;
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(merchant_account, key_store),
            ));
            let res = Box::pin(cards::tokenize_card_flow(
                &state,
                CardNetworkTokenizeRequest::foreign_from(req),
                &merchant_context,
            ))
            .await?;
            Ok(services::ApplicationResponse::Json(res))
        },
        &auth::AdminApiAuth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(all(feature = "v1", any(feature = "olap", feature = "oltp")))]
#[instrument(skip_all, fields(flow = ?Flow::TokenizeCardUsingPaymentMethodId))]
pub async fn tokenize_card_using_pm_api(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
    json_payload: web::Json<payment_methods::CardNetworkTokenizeRequest>,
) -> HttpResponse {
    let flow = Flow::TokenizeCardUsingPaymentMethodId;
    let pm_id = path.into_inner();
    let mut payload = json_payload.into_inner();
    if let payment_methods::TokenizeDataRequest::ExistingPaymentMethod(ref mut pm_data) =
        payload.data
    {
        pm_data.payment_method_id = pm_id;
    } else {
        return api::log_and_return_error_response(error_stack::report!(
            errors::ApiErrorResponse::InvalidDataValue { field_name: "card" }
        ));
    }

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, _, req, _| async move {
            let merchant_id = req.merchant_id.clone();
            let (key_store, merchant_account) = get_merchant_account(&state, &merchant_id).await?;
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(merchant_account, key_store),
            ));
            let res = Box::pin(cards::tokenize_card_flow(
                &state,
                CardNetworkTokenizeRequest::foreign_from(req),
                &merchant_context,
            ))
            .await?;
            Ok(services::ApplicationResponse::Json(res))
        },
        &auth::AdminApiAuth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(all(feature = "v1", any(feature = "olap", feature = "oltp")))]
#[instrument(skip_all, fields(flow = ?Flow::TokenizeCardBatch))]
pub async fn tokenize_card_batch_api(
    state: web::Data<AppState>,
    req: HttpRequest,
    MultipartForm(form): MultipartForm<tokenize::CardNetworkTokenizeForm>,
) -> HttpResponse {
    let flow = Flow::TokenizeCardBatch;
    let (merchant_id, records) = match tokenize::get_tokenize_card_form_records(form) {
        Ok(res) => res,
        Err(e) => return api::log_and_return_error_response(e.into()),
    };

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        records,
        |state, _, req, _| {
            let merchant_id = merchant_id.clone();
            async move {
                let (key_store, merchant_account) =
                    get_merchant_account(&state, &merchant_id).await?;
                let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                    domain::Context(merchant_account, key_store),
                ));
                Box::pin(tokenize::tokenize_cards(&state, req, &merchant_context)).await
            }
        },
        &auth::AdminApiAuth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v2")]
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodSessionCreate))]
pub async fn payment_methods_session_create(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<api_models::payment_methods::PaymentMethodSessionRequest>,
) -> HttpResponse {
    let flow = Flow::PaymentMethodSessionCreate;
    let payload = json_payload.into_inner();

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, request, _| async move {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payment_methods_routes::payment_methods_session_create(state, merchant_context, request)
                .await
        },
        &auth::V2ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v2")]
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodSessionUpdate))]
pub async fn payment_methods_session_update(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<id_type::GlobalPaymentMethodSessionId>,
    json_payload: web::Json<api_models::payment_methods::PaymentMethodsSessionUpdateRequest>,
) -> HttpResponse {
    let flow = Flow::PaymentMethodSessionUpdate;
    let payment_method_session_id = path.into_inner();
    let payload = json_payload.into_inner();
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, req, _| {
            let value = payment_method_session_id.clone();
            async move {
                let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                    domain::Context(auth.merchant_account, auth.key_store),
                ));
                payment_methods_routes::payment_methods_session_update(
                    state,
                    merchant_context,
                    value.clone(),
                    req,
                )
                .await
            }
        },
        &auth::V2ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v2")]
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodSessionRetrieve))]
pub async fn payment_methods_session_retrieve(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<id_type::GlobalPaymentMethodSessionId>,
) -> HttpResponse {
    let flow = Flow::PaymentMethodSessionRetrieve;
    let payment_method_session_id = path.into_inner();

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payment_method_session_id.clone(),
        |state, auth: auth::AuthenticationData, payment_method_session_id, _| async move {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payment_methods_routes::payment_methods_session_retrieve(
                state,
                merchant_context,
                payment_method_session_id,
            )
            .await
        },
        auth::api_or_client_auth(
            &auth::V2ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            },
            &auth::V2ClientAuth(
                common_utils::types::authentication::ResourceId::PaymentMethodSession(
                    payment_method_session_id,
                ),
            ),
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v2")]
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodsList))]
pub async fn payment_method_session_list_payment_methods(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<id_type::GlobalPaymentMethodSessionId>,
) -> HttpResponse {
    let flow = Flow::PaymentMethodsList;
    let payment_method_session_id = path.into_inner();

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payment_method_session_id.clone(),
        |state, auth: auth::AuthenticationData, payment_method_session_id, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payment_methods_routes::list_payment_methods_for_session(
                state,
                merchant_context,
                auth.profile,
                payment_method_session_id,
            )
        },
        &auth::V2ClientAuth(
            common_utils::types::authentication::ResourceId::PaymentMethodSession(
                payment_method_session_id,
            ),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, serde::Serialize)]
struct PaymentMethodsSessionGenericRequest<T: serde::Serialize> {
    payment_method_session_id: id_type::GlobalPaymentMethodSessionId,
    #[serde(flatten)]
    request: T,
}

#[cfg(feature = "v2")]
impl<T: serde::Serialize> common_utils::events::ApiEventMetric
    for PaymentMethodsSessionGenericRequest<T>
{
    fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
        Some(common_utils::events::ApiEventsType::PaymentMethodSession {
            payment_method_session_id: self.payment_method_session_id.clone(),
        })
    }
}

#[cfg(feature = "v2")]
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodSessionConfirm))]
pub async fn payment_method_session_confirm(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<id_type::GlobalPaymentMethodSessionId>,
    json_payload: web::Json<api_models::payment_methods::PaymentMethodSessionConfirmRequest>,
) -> HttpResponse {
    let flow = Flow::PaymentMethodSessionConfirm;
    let payload = json_payload.into_inner();
    let payment_method_session_id = path.into_inner();

    let request = PaymentMethodsSessionGenericRequest {
        payment_method_session_id: payment_method_session_id.clone(),
        request: payload,
    };

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        request,
        |state, auth: auth::AuthenticationData, request, req_state| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payment_methods_routes::payment_methods_session_confirm(
                state,
                req_state,
                merchant_context,
                auth.profile,
                request.payment_method_session_id,
                request.request,
            )
        },
        &auth::V2ClientAuth(
            common_utils::types::authentication::ResourceId::PaymentMethodSession(
                payment_method_session_id,
            ),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v2")]
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodSessionUpdateSavedPaymentMethod))]
pub async fn payment_method_session_update_saved_payment_method(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<id_type::GlobalPaymentMethodSessionId>,
    json_payload: web::Json<
        api_models::payment_methods::PaymentMethodSessionUpdateSavedPaymentMethod,
    >,
) -> HttpResponse {
    let flow = Flow::PaymentMethodSessionUpdateSavedPaymentMethod;
    let payload = json_payload.into_inner();
    let payment_method_session_id = path.into_inner();

    let request = PaymentMethodsSessionGenericRequest {
        payment_method_session_id: payment_method_session_id.clone(),
        request: payload,
    };

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        request,
        |state, auth: auth::AuthenticationData, request, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payment_methods_routes::payment_methods_session_update_payment_method(
                state,
                merchant_context,
                auth.profile,
                request.payment_method_session_id,
                request.request,
            )
        },
        &auth::V2ClientAuth(
            common_utils::types::authentication::ResourceId::PaymentMethodSession(
                payment_method_session_id,
            ),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v2")]
#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodSessionUpdateSavedPaymentMethod))]
pub async fn payment_method_session_delete_saved_payment_method(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<id_type::GlobalPaymentMethodSessionId>,
    json_payload: web::Json<
        api_models::payment_methods::PaymentMethodSessionDeleteSavedPaymentMethod,
    >,
) -> HttpResponse {
    let flow = Flow::PaymentMethodSessionDeleteSavedPaymentMethod;
    let payload = json_payload.into_inner();
    let payment_method_session_id = path.into_inner();

    let request = PaymentMethodsSessionGenericRequest {
        payment_method_session_id: payment_method_session_id.clone(),
        request: payload,
    };

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        request,
        |state, auth: auth::AuthenticationData, request, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payment_methods_routes::payment_methods_session_delete_payment_method(
                state,
                merchant_context,
                auth.profile,
                request.request.payment_method_id,
                request.payment_method_session_id,
            )
        },
        &auth::V2ClientAuth(
            common_utils::types::authentication::ResourceId::PaymentMethodSession(
                payment_method_session_id,
            ),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


// Function: routing_events_core
// File: crates/analytics/src/routing_events/core.rs
// Module: analytics

pub fn routing_events_core(
    pool: &AnalyticsProvider,
    req: RoutingEventsRequest,
    merchant_id: &common_utils::id_type::MerchantId,
) -> AnalyticsResult<Vec<RoutingEventsResult>>


// Trait: SecretState
// File: crates/hyperswitch_interfaces/src/secrets_interface/secret_state.rs
// Module: hyperswitch_interfaces

// Documentation: Trait defining the states of a secret

pub trait SecretState


// Struct: NodeData
// File: crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NodeData


// Struct: CoinbaseRouterData
// File: crates/hyperswitch_connectors/src/connectors/coinbase/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CoinbaseRouterData<T>


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

pub fn create_payment_method_for_confirm(
    state: &SessionState,
    customer_id: &id_type::GlobalCustomerId,
    payment_method_id: id_type::GlobalPaymentMethodId,
    external_vault_source: Option<id_type::MerchantConnectorAccountId>,
    merchant_id: &id_type::MerchantId,
    key_store: &domain::MerchantKeyStore,
    storage_scheme: enums::MerchantStorageScheme,
    payment_method_type: storage_enums::PaymentMethod,
    payment_method_subtype: storage_enums::PaymentMethodType,
    encrypted_payment_method_billing_address: Option<
        Encryptable<hyperswitch_domain_models::address::Address>,
    >,
    encrypted_payment_method_data: Option<Encryptable<payment_methods::PaymentMethodsData>>,
    encrypted_external_vault_token_data: Option<
        Encryptable<payment_methods::ExternalVaultTokenData>,
    >,
    vault_type: Option<common_enums::VaultType>,
) -> CustomResult<domain::PaymentMethod, errors::ApiErrorResponse>


// Implementation: impl MerchantCategoryCode
// File: crates/common_enums/src/enums.rs
// Module: common_enums
// Methods: 1 total (1 public)

impl MerchantCategoryCode


// File: crates/router/src/core/user_role/role.rs
// Module: router
// Public functions: 9

use std::{cmp, collections::HashSet, ops::Not};

use api_models::user_role::role as role_api;
use common_enums::{EntityType, ParentGroup, PermissionGroup};
use common_utils::generate_id_with_default_len;
use diesel_models::role::{ListRolesByEntityPayload, RoleNew, RoleUpdate};
use error_stack::{report, ResultExt};

use crate::{
    core::errors::{StorageErrorExt, UserErrors, UserResponse},
    routes::{app::ReqState, SessionState},
    services::{
        authentication::{blacklist, UserFromToken},
        authorization::{
            permission_groups::{ParentGroupExt, PermissionGroupExt},
            roles::{self, predefined_roles::PREDEFINED_ROLES},
        },
        ApplicationResponse,
    },
    types::domain::user::RoleName,
    utils,
};

pub async fn get_role_from_token_with_groups(
    state: SessionState,
    user_from_token: UserFromToken,
) -> UserResponse<Vec<PermissionGroup>> {
    let role_info = user_from_token
        .get_role_info_from_db(&state)
        .await
        .attach_printable("Invalid role_id in JWT")?;

    let permissions = role_info.get_permission_groups().to_vec();

    Ok(ApplicationResponse::Json(permissions))
}

pub async fn get_groups_and_resources_for_role_from_token(
    state: SessionState,
    user_from_token: UserFromToken,
) -> UserResponse<role_api::GroupsAndResources> {
    let role_info = user_from_token.get_role_info_from_db(&state).await?;

    let groups = role_info
        .get_permission_groups()
        .into_iter()
        .collect::<Vec<_>>();
    let resources = groups
        .iter()
        .flat_map(|group| group.resources())
        .collect::<HashSet<_>>()
        .into_iter()
        .collect();

    Ok(ApplicationResponse::Json(role_api::GroupsAndResources {
        groups,
        resources,
    }))
}

pub async fn create_role(
    state: SessionState,
    user_from_token: UserFromToken,
    req: role_api::CreateRoleRequest,
    _req_state: ReqState,
) -> UserResponse<role_api::RoleInfoWithGroupsResponse> {
    let now = common_utils::date_time::now();

    let user_entity_type = user_from_token
        .get_role_info_from_db(&state)
        .await
        .attach_printable("Invalid role_id in JWT")?
        .get_entity_type();

    let role_entity_type = req.entity_type.unwrap_or(EntityType::Merchant);

    if matches!(role_entity_type, EntityType::Organization) {
        return Err(report!(UserErrors::InvalidRoleOperation))
            .attach_printable("User trying to create org level custom role");
    }
    let requestor_entity_from_role_scope = EntityType::from(req.role_scope);

    if requestor_entity_from_role_scope < role_entity_type {
        return Err(report!(UserErrors::InvalidRoleOperation)).attach_printable(format!(
            "User is trying to create role of type {role_entity_type} and scope {requestor_entity_from_role_scope}",

        ));
    }
    let max_from_scope_and_entity = cmp::max(requestor_entity_from_role_scope, role_entity_type);

    if user_entity_type < max_from_scope_and_entity {
        return Err(report!(UserErrors::InvalidRoleOperation)).attach_printable(format!(
            "{user_entity_type} is trying to create of scope {requestor_entity_from_role_scope} and of type {role_entity_type}",

        ));
    }

    let role_name = RoleName::new(req.role_name)?;

    utils::user_role::validate_role_groups(&req.groups)?;
    utils::user_role::validate_role_name(
        &state,
        &role_name,
        &user_from_token.merchant_id,
        &user_from_token.org_id,
        user_from_token
            .tenant_id
            .as_ref()
            .unwrap_or(&state.tenant.tenant_id),
        &user_from_token.profile_id,
        &role_entity_type,
    )
    .await?;

    let (org_id, merchant_id, profile_id) = match role_entity_type {
        EntityType::Organization | EntityType::Tenant => (user_from_token.org_id, None, None),
        EntityType::Merchant => (
            user_from_token.org_id,
            Some(user_from_token.merchant_id),
            None,
        ),
        EntityType::Profile => (
            user_from_token.org_id,
            Some(user_from_token.merchant_id),
            Some(user_from_token.profile_id),
        ),
    };

    let role = state
        .global_store
        .insert_role(RoleNew {
            role_id: generate_id_with_default_len("role"),
            role_name: role_name.get_role_name(),
            merchant_id,
            org_id,
            groups: req.groups,
            scope: req.role_scope,
            entity_type: role_entity_type,
            created_by: user_from_token.user_id.clone(),
            last_modified_by: user_from_token.user_id,
            created_at: now,
            last_modified_at: now,
            profile_id,
            tenant_id: user_from_token.tenant_id.unwrap_or(state.tenant.tenant_id),
        })
        .await
        .to_duplicate_response(UserErrors::RoleNameAlreadyExists)?;

    Ok(ApplicationResponse::Json(
        role_api::RoleInfoWithGroupsResponse {
            groups: role.groups,
            role_id: role.role_id,
            role_name: role.role_name,
            role_scope: role.scope,
            entity_type: role.entity_type,
        },
    ))
}

pub async fn create_role_v2(
    state: SessionState,
    user_from_token: UserFromToken,
    req: role_api::CreateRoleV2Request,
    _req_state: ReqState,
) -> UserResponse<role_api::RoleInfoResponseWithParentsGroup> {
    let now = common_utils::date_time::now();

    let user_entity_type = user_from_token
        .get_role_info_from_db(&state)
        .await
        .attach_printable("Invalid role_id in JWT")?
        .get_entity_type();

    let role_entity_type = req.entity_type.unwrap_or(EntityType::Merchant);

    if matches!(role_entity_type, EntityType::Organization) {
        return Err(report!(UserErrors::InvalidRoleOperation))
            .attach_printable("User trying to create org level custom role");
    }

    let requestor_entity_from_role_scope = EntityType::from(req.role_scope);

    if requestor_entity_from_role_scope < role_entity_type {
        return Err(report!(UserErrors::InvalidRoleOperation)).attach_printable(format!(
            "User is trying to create role of type {role_entity_type} and scope {requestor_entity_from_role_scope}",
        ));
    }

    let max_from_scope_and_entity = cmp::max(requestor_entity_from_role_scope, role_entity_type);

    if user_entity_type < max_from_scope_and_entity {
        return Err(report!(UserErrors::InvalidRoleOperation)).attach_printable(format!(
            "{user_entity_type} is trying to create of scope {requestor_entity_from_role_scope} and of type {role_entity_type}",
        ));
    }

    let role_name = RoleName::new(req.role_name.clone())?;

    let permission_groups =
        utils::user_role::parent_group_info_request_to_permission_groups(&req.parent_groups)?;

    utils::user_role::validate_role_groups(&permission_groups)?;
    utils::user_role::validate_role_name(
        &state,
        &role_name,
        &user_from_token.merchant_id,
        &user_from_token.org_id,
        user_from_token
            .tenant_id
            .as_ref()
            .unwrap_or(&state.tenant.tenant_id),
        &user_from_token.profile_id,
        &role_entity_type,
    )
    .await?;

    let (org_id, merchant_id, profile_id) = match role_entity_type {
        EntityType::Organization | EntityType::Tenant => (user_from_token.org_id, None, None),
        EntityType::Merchant => (
            user_from_token.org_id,
            Some(user_from_token.merchant_id),
            None,
        ),
        EntityType::Profile => (
            user_from_token.org_id,
            Some(user_from_token.merchant_id),
            Some(user_from_token.profile_id),
        ),
    };

    let role = state
        .global_store
        .insert_role(RoleNew {
            role_id: generate_id_with_default_len("role"),
            role_name: role_name.get_role_name(),
            merchant_id,
            org_id,
            groups: permission_groups,
            scope: req.role_scope,
            entity_type: role_entity_type,
            created_by: user_from_token.user_id.clone(),
            last_modified_by: user_from_token.user_id,
            created_at: now,
            last_modified_at: now,
            profile_id,
            tenant_id: user_from_token.tenant_id.unwrap_or(state.tenant.tenant_id),
        })
        .await
        .to_duplicate_response(UserErrors::RoleNameAlreadyExists)?;

    let response_parent_groups =
        utils::user_role::permission_groups_to_parent_group_info(&role.groups, role.entity_type);

    Ok(ApplicationResponse::Json(
        role_api::RoleInfoResponseWithParentsGroup {
            role_id: role.role_id,
            role_name: role.role_name,
            role_scope: role.scope,
            entity_type: role.entity_type,
            parent_groups: response_parent_groups,
        },
    ))
}

pub async fn get_role_with_groups(
    state: SessionState,
    user_from_token: UserFromToken,
    role: role_api::GetRoleRequest,
) -> UserResponse<role_api::RoleInfoWithGroupsResponse> {
    let role_info = roles::RoleInfo::from_role_id_org_id_tenant_id(
        &state,
        &role.role_id,
        &user_from_token.org_id,
        user_from_token
            .tenant_id
            .as_ref()
            .unwrap_or(&state.tenant.tenant_id),
    )
    .await
    .to_not_found_response(UserErrors::InvalidRoleId)?;

    if role_info.is_internal() {
        return Err(UserErrors::InvalidRoleId.into());
    }

    Ok(ApplicationResponse::Json(
        role_api::RoleInfoWithGroupsResponse {
            groups: role_info.get_permission_groups().to_vec(),
            role_id: role.role_id,
            role_name: role_info.get_role_name().to_string(),
            role_scope: role_info.get_scope(),
            entity_type: role_info.get_entity_type(),
        },
    ))
}

pub async fn get_parent_info_for_role(
    state: SessionState,
    user_from_token: UserFromToken,
    role: role_api::GetRoleRequest,
) -> UserResponse<role_api::RoleInfoWithParents> {
    let role_info = roles::RoleInfo::from_role_id_org_id_tenant_id(
        &state,
        &role.role_id,
        &user_from_token.org_id,
        user_from_token
            .tenant_id
            .as_ref()
            .unwrap_or(&state.tenant.tenant_id),
    )
    .await
    .to_not_found_response(UserErrors::InvalidRoleId)?;

    if role_info.is_internal() {
        return Err(UserErrors::InvalidRoleId.into());
    }

    let parent_groups = ParentGroup::get_descriptions_for_groups(
        role_info.get_entity_type(),
        role_info.get_permission_groups().to_vec(),
    )
    .ok_or(UserErrors::InternalServerError)
    .attach_printable(format!(
        "No group descriptions found for role_id: {}",
        role.role_id
    ))?
    .into_iter()
    .map(|(parent_group, description)| role_api::ParentGroupInfo {
        name: parent_group.clone(),
        description,
        scopes: role_info
            .get_permission_groups()
            .iter()
            .filter_map(|group| (group.parent() == parent_group).then_some(group.scope()))
            // TODO: Remove this hashset conversion when merchant access
            // and organization access groups are removed
            .collect::<HashSet<_>>()
            .into_iter()
            .collect(),
    })
    .collect();

    Ok(ApplicationResponse::Json(role_api::RoleInfoWithParents {
        role_id: role.role_id,
        parent_groups,
        role_name: role_info.get_role_name().to_string(),
        role_scope: role_info.get_scope(),
    }))
}

pub async fn update_role(
    state: SessionState,
    user_from_token: UserFromToken,
    req: role_api::UpdateRoleRequest,
    role_id: &str,
) -> UserResponse<role_api::RoleInfoWithGroupsResponse> {
    let role_name = req.role_name.map(RoleName::new).transpose()?;

    let role_info = roles::RoleInfo::from_role_id_in_lineage(
        &state,
        role_id,
        &user_from_token.merchant_id,
        &user_from_token.org_id,
        &user_from_token.profile_id,
        user_from_token
            .tenant_id
            .as_ref()
            .unwrap_or(&state.tenant.tenant_id),
    )
    .await
    .to_not_found_response(UserErrors::InvalidRoleOperation)?;

    let user_role_info = user_from_token.get_role_info_from_db(&state).await?;

    let requested_entity_from_role_scope = EntityType::from(role_info.get_scope());
    let requested_role_entity_type = role_info.get_entity_type();
    let max_from_scope_and_entity =
        cmp::max(requested_entity_from_role_scope, requested_role_entity_type);

    if user_role_info.get_entity_type() < max_from_scope_and_entity {
        return Err(report!(UserErrors::InvalidRoleOperation)).attach_printable(format!(
            "{} is trying to update of scope {} and of type {}",
            user_role_info.get_entity_type(),
            requested_entity_from_role_scope,
            requested_role_entity_type
        ));
    }

    if let Some(ref role_name) = role_name {
        utils::user_role::validate_role_name(
            &state,
            role_name,
            &user_from_token.merchant_id,
            &user_from_token.org_id,
            user_from_token
                .tenant_id
                .as_ref()
                .unwrap_or(&state.tenant.tenant_id),
            &user_from_token.profile_id,
            &role_info.get_entity_type(),
        )
        .await?;
    }

    if let Some(ref groups) = req.groups {
        utils::user_role::validate_role_groups(groups)?;
    }

    let updated_role = state
        .global_store
        .update_role_by_role_id(
            role_id,
            RoleUpdate::UpdateDetails {
                groups: req.groups,
                role_name: role_name.map(RoleName::get_role_name),
                last_modified_at: common_utils::date_time::now(),
                last_modified_by: user_from_token.user_id,
            },
        )
        .await
        .to_duplicate_response(UserErrors::RoleNameAlreadyExists)?;

    blacklist::insert_role_in_blacklist(&state, role_id).await?;

    Ok(ApplicationResponse::Json(
        role_api::RoleInfoWithGroupsResponse {
            groups: updated_role.groups,
            role_id: updated_role.role_id,
            role_name: updated_role.role_name,
            role_scope: updated_role.scope,
            entity_type: updated_role.entity_type,
        },
    ))
}

pub async fn list_roles_with_info(
    state: SessionState,
    user_from_token: UserFromToken,
    request: role_api::ListRolesQueryParams,
) -> UserResponse<role_api::ListRolesResponse> {
    let user_role_info = user_from_token
        .get_role_info_from_db(&state)
        .await
        .attach_printable("Invalid role_id in JWT")?;

    if user_role_info.is_internal() {
        return Err(UserErrors::InvalidRoleOperationWithMessage(
            "Internal roles are not allowed for this operation".to_string(),
        )
        .into());
    }

    let mut role_info_vec = PREDEFINED_ROLES
        .values()
        .filter(|role| role.is_internal().not())
        .cloned()
        .collect::<Vec<_>>();

    let user_role_entity = user_role_info.get_entity_type();
    let is_lineage_data_required = request.entity_type.is_none();
    let tenant_id = user_from_token
        .tenant_id
        .as_ref()
        .unwrap_or(&state.tenant.tenant_id)
        .to_owned();
    let custom_roles =
        match utils::user_role::get_min_entity(user_role_entity, request.entity_type)? {
            EntityType::Tenant | EntityType::Organization => state
                .global_store
                .generic_list_roles_by_entity_type(
                    ListRolesByEntityPayload::Organization,
                    is_lineage_data_required,
                    tenant_id,
                    user_from_token.org_id,
                )
                .await
                .change_context(UserErrors::InternalServerError)
                .attach_printable("Failed to get roles")?,
            EntityType::Merchant => state
                .global_store
                .generic_list_roles_by_entity_type(
                    ListRolesByEntityPayload::Merchant(user_from_token.merchant_id),
                    is_lineage_data_required,
                    tenant_id,
                    user_from_token.org_id,
                )
                .await
                .change_context(UserErrors::InternalServerError)
                .attach_printable("Failed to get roles")?,

            EntityType::Profile => state
                .global_store
                .generic_list_roles_by_entity_type(
                    ListRolesByEntityPayload::Profile(
                        user_from_token.merchant_id,
                        user_from_token.profile_id,
                    ),
                    is_lineage_data_required,
                    tenant_id,
                    user_from_token.org_id,
                )
                .await
                .change_context(UserErrors::InternalServerError)
                .attach_printable("Failed to get roles")?,
        };

    role_info_vec.extend(custom_roles.into_iter().map(roles::RoleInfo::from));

    if request.groups == Some(true) {
        let list_role_info_response = role_info_vec
            .into_iter()
            .filter_map(|role_info| {
                let is_lower_entity = user_role_entity >= role_info.get_entity_type();
                let request_filter = request
                    .entity_type
                    .is_none_or(|entity_type| entity_type == role_info.get_entity_type());

                (is_lower_entity && request_filter).then_some({
                    let permission_groups = role_info.get_permission_groups();
                    let parent_groups = utils::user_role::permission_groups_to_parent_group_info(
                        &permission_groups,
                        role_info.get_entity_type(),
                    );

                    role_api::RoleInfoResponseWithParentsGroup {
                        role_id: role_info.get_role_id().to_string(),
                        role_name: role_info.get_role_name().to_string(),
                        entity_type: role_info.get_entity_type(),
                        parent_groups,
                        role_scope: role_info.get_scope(),
                    }
                })
            })
            .collect::<Vec<_>>();

        Ok(ApplicationResponse::Json(
            role_api::ListRolesResponse::WithParentGroups(list_role_info_response),
        ))
    }
    // TODO: To be deprecated
    else {
        let list_role_info_response = role_info_vec
            .into_iter()
            .filter_map(|role_info| {
                let is_lower_entity = user_role_entity >= role_info.get_entity_type();
                let request_filter = request
                    .entity_type
                    .is_none_or(|entity_type| entity_type == role_info.get_entity_type());

                (is_lower_entity && request_filter).then_some(role_api::RoleInfoResponseNew {
                    role_id: role_info.get_role_id().to_string(),
                    role_name: role_info.get_role_name().to_string(),
                    groups: role_info.get_permission_groups().to_vec(),
                    entity_type: role_info.get_entity_type(),
                    scope: role_info.get_scope(),
                })
            })
            .collect::<Vec<_>>();

        Ok(ApplicationResponse::Json(
            role_api::ListRolesResponse::WithGroups(list_role_info_response),
        ))
    }
}

pub async fn list_roles_at_entity_level(
    state: SessionState,
    user_from_token: UserFromToken,
    req: role_api::ListRolesAtEntityLevelRequest,
    check_type: role_api::RoleCheckType,
) -> UserResponse<Vec<role_api::MinimalRoleInfo>> {
    let user_entity_type = user_from_token
        .get_role_info_from_db(&state)
        .await
        .attach_printable("Invalid role_id in JWT")?
        .get_entity_type();

    if req.entity_type > user_entity_type {
        return Err(UserErrors::InvalidRoleOperationWithMessage(
            "User is attempting to request list roles above the current entity level".to_string(),
        )
        .into());
    }
    let mut role_info_vec = PREDEFINED_ROLES.values().cloned().collect::<Vec<_>>();

    let tenant_id = user_from_token
        .tenant_id
        .as_ref()
        .unwrap_or(&state.tenant.tenant_id)
        .to_owned();

    let is_lineage_data_required = false;
    let custom_roles = match req.entity_type {
        EntityType::Tenant | EntityType::Organization => state
            .global_store
            .generic_list_roles_by_entity_type(
                ListRolesByEntityPayload::Organization,
                is_lineage_data_required,
                tenant_id,
                user_from_token.org_id,
            )
            .await
            .change_context(UserErrors::InternalServerError)
            .attach_printable("Failed to get roles")?,

        EntityType::Merchant => state
            .global_store
            .generic_list_roles_by_entity_type(
                ListRolesByEntityPayload::Merchant(user_from_token.merchant_id),
                is_lineage_data_required,
                tenant_id,
                user_from_token.org_id,
            )
            .await
            .change_context(UserErrors::InternalServerError)
            .attach_printable("Failed to get roles")?,

        EntityType::Profile => state
            .global_store
            .generic_list_roles_by_entity_type(
                ListRolesByEntityPayload::Profile(
                    user_from_token.merchant_id,
                    user_from_token.profile_id,
                ),
                is_lineage_data_required,
                tenant_id,
                user_from_token.org_id,
            )
            .await
            .change_context(UserErrors::InternalServerError)
            .attach_printable("Failed to get roles")?,
    };

    role_info_vec.extend(custom_roles.into_iter().map(roles::RoleInfo::from));

    let list_minimal_role_info = role_info_vec
        .into_iter()
        .filter_map(|role_info| {
            let check_type = match check_type {
                role_api::RoleCheckType::Invite => role_info.is_invitable(),
                role_api::RoleCheckType::Update => role_info.is_updatable(),
            };
            if check_type && role_info.get_entity_type() == req.entity_type {
                Some(role_api::MinimalRoleInfo {
                    role_id: role_info.get_role_id().to_string(),
                    role_name: role_info.get_role_name().to_string(),
                })
            } else {
                None
            }
        })
        .collect::<Vec<_>>();

    Ok(ApplicationResponse::Json(list_minimal_role_info))
}


// Function: get_drainer_stream_name
// File: crates/drainer/src/stream.rs
// Module: drainer

pub fn get_drainer_stream_name(&self, stream_index: u8) -> String


// Implementation: impl utils::MultipleCaptureSyncResponse for for HelcimPaymentsResponse
// File: crates/hyperswitch_connectors/src/connectors/helcim/transformers.rs
// Module: hyperswitch_connectors
// Methods: 5 total (0 public)

impl utils::MultipleCaptureSyncResponse for for HelcimPaymentsResponse


// Function: get_metrics
// File: crates/analytics/src/sdk_events/core.rs
// Module: analytics

pub fn get_metrics(
    pool: &AnalyticsProvider,
    publishable_key: &String,
    req: GetSdkEventMetricRequest,
) -> AnalyticsResult<MetricsResponse<MetricsBucketResponse>>


// Function: retrieve_connector
// File: crates/router/src/core/admin.rs
// Module: router

pub fn retrieve_connector(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    id: id_type::MerchantConnectorAccountId,
) -> RouterResponse<api_models::admin::MerchantConnectorResponse>


// Implementation: impl ApiEventMetric for for ToggleBlocklistQuery
// File: crates/api_models/src/blocklist.rs
// Module: api_models
// Methods: 0 total (0 public)

impl ApiEventMetric for for ToggleBlocklistQuery


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

pub fn decide_connector_for_normal_or_recurring_payment<F: Clone, D>(
    state: &SessionState,
    payment_data: &mut D,
    routing_data: &mut storage::RoutingData,
    connectors: Vec<api::ConnectorRoutingData>,
    is_connector_agnostic_mit_enabled: Option<bool>,
    payment_method_info: &domain::PaymentMethod,
) -> RouterResult<ConnectorCallType>
where
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,


// Function: new
// File: crates/hyperswitch_connectors/src/connectors/peachpayments.rs
// Module: hyperswitch_connectors

pub fn new() -> &'static Self


// Implementation: impl Args
// File: crates/test_utils/src/newman_runner.rs
// Module: test_utils
// Methods: 1 total (1 public)

impl Args


// Struct: UserName
// File: crates/router/src/types/domain/user.rs
// Module: router
// Implementations: 1

pub struct UserName


// Function: get_additional_payout_method_data
// File: crates/hyperswitch_domain_models/src/payment_method_data.rs
// Module: hyperswitch_domain_models

pub fn get_additional_payout_method_data(
        &self,
    ) -> Option<payout_method_utils::AdditionalPayoutMethodData>


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

pub fn retrieve_payment_token_data(
    state: &SessionState,
    token: String,
    payment_method: Option<&storage_enums::PaymentMethod>,
) -> errors::RouterResult<storage::PaymentTokenData>


// Struct: PayRequest
// File: crates/hyperswitch_connectors/src/connectors/payme/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PayRequest


// Struct: PlacetopayPsyncRequest
// File: crates/hyperswitch_connectors/src/connectors/placetopay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PlacetopayPsyncRequest


// Struct: TaxjarPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/taxjar/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TaxjarPaymentsRequest


// Function: customers_delete
// File: crates/router/src/routes/customers.rs
// Module: router

pub fn customers_delete(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<id_type::CustomerId>,
) -> impl Responder


// Struct: JpmorganAuthUpdateResponse
// File: crates/hyperswitch_connectors/src/connectors/jpmorgan/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct JpmorganAuthUpdateResponse


// Function: get_payment_method_type
// File: crates/hyperswitch_domain_models/src/payment_method_data.rs
// Module: hyperswitch_domain_models

pub fn get_payment_method_type(&self) -> Option<api_enums::PaymentMethodType>


// Struct: MandateReference
// File: crates/hyperswitch_domain_models/src/router_response_types.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct MandateReference


// Implementation: impl EuclidParsable for for DummyOutput
// File: crates/euclid/src/frontend/ast/parser.rs
// Module: euclid
// Methods: 1 total (0 public)

impl EuclidParsable for for DummyOutput


// Implementation: impl api::RefundExecute for for Amazonpay
// File: crates/hyperswitch_connectors/src/connectors/amazonpay.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::RefundExecute for for Amazonpay


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

pub mod payout_attempt;
#[allow(clippy::module_inception)]
pub mod payouts;

use diesel_models::{payout_attempt::PayoutAttempt, payouts::Payouts};

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

impl KvStorePartition for Payouts {}
impl KvStorePartition for PayoutAttempt {}


// Implementation: impl Iterator for for Keys
// File: crates/hyperswitch_constraint_graph/src/dense_map.rs
// Module: hyperswitch_constraint_graph
// Methods: 1 total (0 public)

impl Iterator for for Keys


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

impl api::PaymentToken for for Noon


// Struct: SantanderCalendar
// File: crates/hyperswitch_connectors/src/connectors/santander/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct SantanderCalendar


// Function: new
// File: crates/hyperswitch_domain_models/src/router_flow_types/webhooks.rs
// Module: hyperswitch_domain_models

pub fn new(txn_id: masking::Secret<String>) -> Self


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

use std::str::FromStr;

use masking::Secret;
use router::types::{self, domain, storage::enums};

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

#[derive(Clone, Copy)]
struct OpayoTest;
impl ConnectorActions for OpayoTest {}
impl utils::Connector for OpayoTest {
    fn get_data(&self) -> types::api::ConnectorData {
        use router::connector::Opayo;
        utils::construct_connector_data_old(
            Box::new(Opayo::new()),
            // Remove `dummy_connector` feature gate from module in `main.rs` when updating this to use actual connector variant
            types::Connector::DummyConnector1,
            types::api::GetToken::Connector,
            None,
        )
    }

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

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

static CONNECTOR: OpayoTest = OpayoTest {};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// Cards Negative scenarios
// Creates a payment with incorrect 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: cards::CardNumber::from_str("1234567891011").unwrap(),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card number is incorrect.".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
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's security code is invalid.".to_string(),
    );
}

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

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

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

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

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

// Connector dependent test cases goes here

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


// Struct: FacilitapayWebhookNotification
// File: crates/hyperswitch_connectors/src/connectors/facilitapay/responses.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct FacilitapayWebhookNotification


// Implementation: impl Serialize for for FlatMapEvent
// File: crates/events/src/lib.rs
// Module: events
// Methods: 1 total (0 public)

impl Serialize for for FlatMapEvent


// Struct: PlacetopayInstrument
// File: crates/hyperswitch_connectors/src/connectors/placetopay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PlacetopayInstrument


// Struct: Tokenex
// File: crates/hyperswitch_connectors/src/connectors/tokenex.rs
// Module: hyperswitch_connectors
// Implementations: 19
// Traits: api::Payment, api::PaymentSession, api::ConnectorAccessToken, api::MandateSetup, api::PaymentAuthorize, api::PaymentSync, api::PaymentCapture, api::PaymentVoid, api::Refund, api::RefundExecute, api::RefundSync, api::PaymentToken, api::ExternalVaultInsert, api::ExternalVault, api::ExternalVaultRetrieve, ConnectorCommon, ConnectorValidation, webhooks::IncomingWebhook, ConnectorSpecifications

pub struct Tokenex

api::Payment api::PaymentSession api::ConnectorAccessToken api::MandateSetup api::PaymentAuthorize api::PaymentSync api::PaymentCapture api::PaymentVoid api::Refund api::RefundExecute api::RefundSync api::PaymentToken api::ExternalVaultInsert api::ExternalVault api::ExternalVaultRetrieve ConnectorCommon ConnectorValidation webhooks::IncomingWebhook ConnectorSpecifications


// Function: get_payment_distribution
// File: crates/analytics/src/lib.rs
// Module: analytics

pub fn get_payment_distribution(
        &self,
        distribution: &PaymentDistributionBody,
        dimensions: &[PaymentDimensions],
        auth: &AuthInfo,
        filters: &PaymentFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
    ) -> types::MetricsResult<Vec<(PaymentMetricsBucketIdentifier, PaymentDistributionRow)>>


// File: crates/router_env/tests/logger.rs
// Module: router_env

#![allow(clippy::unwrap_used)]

mod test_module;

use ::config::ConfigError;
use router_env::TelemetryGuard;

use self::test_module::fn_with_colon;

fn logger() -> error_stack::Result<&'static TelemetryGuard, ConfigError> {
    use std::sync::OnceLock;

    static INSTANCE: OnceLock<TelemetryGuard> = OnceLock::new();
    Ok(INSTANCE.get_or_init(|| {
        let config = router_env::Config::new().unwrap();

        router_env::setup(&config.log, "router_env_test", []).unwrap()
    }))
}

#[tokio::test]
async fn basic() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    logger()?;

    fn_with_colon(13).await;

    Ok(())
}


// Function: get_feature_metadata
// File: crates/hyperswitch_domain_models/src/payments.rs
// Module: hyperswitch_domain_models

pub fn get_feature_metadata(&self) -> Option<FeatureMetadata>


// Struct: NoonSubscriptionData
// File: crates/hyperswitch_connectors/src/connectors/noon/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct NoonSubscriptionData


// Trait: VaultingInterface
// File: crates/router/src/types/payment_methods.rs
// Module: router

pub trait VaultingInterface


// Implementation: impl PaymentMetricAccumulator for for ProcessedAmountAccumulator
// File: crates/analytics/src/payments/accumulator.rs
// Module: analytics
// Methods: 2 total (0 public)

impl PaymentMetricAccumulator for for ProcessedAmountAccumulator


// Struct: PaymentAccountInformation
// File: crates/hyperswitch_connectors/src/connectors/bankofamerica/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentAccountInformation


// Struct: AciPaymentWebhookPayload
// File: crates/hyperswitch_connectors/src/connectors/aci/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AciPaymentWebhookPayload


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

pub fn mock_delete_card<'a>(
    db: &dyn db::StorageInterface,
    card_id: &'a str,
) -> errors::CustomResult<payment_methods::DeleteCardResponse, errors::VaultError>


// File: crates/router/src/routes/relay.rs
// Module: router
// Public functions: 2

use actix_web::{web, Responder};
use router_env::{instrument, tracing, Flow};

use crate::{
    self as app,
    core::{api_locking, relay},
    services::{api, authentication as auth},
};

#[instrument(skip_all, fields(flow = ?Flow::Relay))]
#[cfg(feature = "oltp")]
pub async fn relay(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    payload: web::Json<api_models::relay::RelayRequest>,
) -> impl Responder {
    let flow = Flow::Relay;
    let payload = payload.into_inner();
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = crate::types::domain::MerchantContext::NormalMerchant(Box::new(
                crate::types::domain::Context(auth.merchant_account, auth.key_store),
            ));
            relay::relay_flow_decider(
                state,
                merchant_context,
                #[cfg(feature = "v1")]
                auth.profile_id,
                #[cfg(feature = "v2")]
                Some(auth.profile.get_id().clone()),
                req,
            )
        },
        &auth::HeaderAuth(auth::ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        }),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[instrument(skip_all, fields(flow = ?Flow::RelayRetrieve))]
#[cfg(feature = "oltp")]
pub async fn relay_retrieve(
    state: web::Data<app::AppState>,
    path: web::Path<common_utils::id_type::RelayId>,
    req: actix_web::HttpRequest,
    query_params: web::Query<api_models::relay::RelayRetrieveBody>,
) -> impl Responder {
    let flow = Flow::RelayRetrieve;
    let relay_retrieve_request = api_models::relay::RelayRetrieveRequest {
        force_sync: query_params.force_sync,
        id: path.into_inner(),
    };
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        relay_retrieve_request,
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = crate::types::domain::MerchantContext::NormalMerchant(Box::new(
                crate::types::domain::Context(auth.merchant_account, auth.key_store),
            ));
            relay::relay_retrieve(
                state,
                merchant_context,
                #[cfg(feature = "v1")]
                auth.profile_id,
                #[cfg(feature = "v2")]
                Some(auth.profile.get_id().clone()),
                req,
            )
        },
        &auth::HeaderAuth(auth::ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        }),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


// Function: two_digits
// File: crates/cards/src/lib.rs
// Module: cards

pub fn two_digits(&self) -> String


// Implementation: impl EmailData for for VerifyEmail
// File: crates/router/src/services/email/types.rs
// Module: router
// Methods: 1 total (0 public)

impl EmailData for for VerifyEmail


// Struct: TokenexRouterData
// File: crates/hyperswitch_connectors/src/connectors/tokenex/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TokenexRouterData<T>


// Function: get_masked_keys
// File: crates/hyperswitch_domain_models/src/router_data.rs
// Module: hyperswitch_domain_models

pub fn get_masked_keys(&self) -> Self