pub struct EphemeralKeyCreateResponse {
    /// customer_id to which this ephemeral key belongs to
    #[schema(value_type = String, max_length = 64, min_length = 1, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub customer_id: id_type::CustomerId,
    /// time at which this ephemeral key was created
    pub created_at: i64,
    /// time at which this ephemeral key would expire
    pub expires: i64,
    /// ephemeral key
    pub secret: String,
}


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

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


impl api::PaymentAuthorize for Amazonpay {}

impl api::PaymentAuthorize for for Amazonpay


impl NuveiAuthorizePreprocessingCommon for PaymentsPreProcessingData {
    fn get_browser_info(&self) -> Option<BrowserInformation> {
        self.browser_info.clone()
    }

    fn get_related_transaction_id(&self) -> Option<String> {
        self.related_transaction_id.clone()
    }

    fn get_is_moto(&self) -> Option<bool> {
        None
    }

    fn get_customer_id_required(&self) -> Option<CustomerId> {
        None
    }
    fn get_email_required(&self) -> Result<Email, error_stack::Report<errors::ConnectorError>> {
        self.get_email()
    }
    fn is_customer_initiated_mandate_payment(&self) -> bool {
        (self.customer_acceptance.is_some() || self.setup_mandate_details.is_some())
            && self.setup_future_usage == Some(FutureUsage::OffSession)
    }

    fn get_complete_authorize_url(&self) -> Option<String> {
        self.complete_authorize_url.clone()
    }

    fn get_connector_mandate_id(&self) -> Option<String> {
        self.connector_mandate_id()
    }

    fn get_return_url_required(
        &self,
    ) -> Result<String, error_stack::Report<errors::ConnectorError>> {
        self.get_router_return_url()
    }

    fn get_capture_method(&self) -> Option<CaptureMethod> {
        self.capture_method
    }

    fn get_minor_amount_required(
        &self,
    ) -> Result<MinorUnit, error_stack::Report<errors::ConnectorError>> {
        self.get_minor_amount()
    }

    fn get_currency_required(
        &self,
    ) -> Result<enums::Currency, error_stack::Report<errors::ConnectorError>> {
        self.get_currency()
    }
    fn get_payment_method_data_required(
        &self,
    ) -> Result<PaymentMethodData, error_stack::Report<errors::ConnectorError>> {
        self.payment_method_data.clone().ok_or(
            errors::ConnectorError::MissingRequiredField {
                field_name: "payment_method_data",
            }
            .into(),
        )
    }
    fn get_order_tax_amount(
        &self,
    ) -> Result<Option<MinorUnit>, error_stack::Report<errors::ConnectorError>> {
        Ok(None)
    }

    fn get_is_partial_approval(&self) -> Option<PartialApprovalFlag> {
        None
    }

    fn get_ntid(&self) -> Option<String> {
        None
    }
}

impl NuveiAuthorizePreprocessingCommon for for PaymentsPreProcessingData


/// Returns the most verbose [`tracing::Level`]
    pub fn into_level(self) -> tracing::Level {
        self.0
    }


File: crates/diesel_models/src/customers.rs
 Public functions: 4
 Public structs: 6

use common_enums::ApiVersion;
use common_utils::{encryption::Encryption, pii, types::Description};
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
use time::PrimitiveDateTime;

#[cfg(feature = "v1")]
use crate::schema::customers;
#[cfg(feature = "v2")]
use crate::{
    diesel_impl::RequiredFromNullableWithDefault, enums::DeleteStatus, schema_v2::customers,
};

#[cfg(feature = "v1")]
#[derive(
    Clone, Debug, router_derive::DebugAsDisplay, serde::Deserialize, serde::Serialize, Insertable,
)]
#[diesel(table_name = customers)]
pub struct CustomerNew {
    pub customer_id: common_utils::id_type::CustomerId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub name: Option<Encryption>,
    pub email: Option<Encryption>,
    pub phone: Option<Encryption>,
    pub description: Option<Description>,
    pub phone_country_code: Option<String>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub connector_customer: Option<pii::SecretSerdeValue>,
    pub created_at: PrimitiveDateTime,
    pub modified_at: PrimitiveDateTime,
    pub address_id: Option<String>,
    pub updated_by: Option<String>,
    pub version: ApiVersion,
    pub tax_registration_id: Option<Encryption>,
}

#[cfg(feature = "v1")]
impl CustomerNew {
    pub fn update_storage_scheme(&mut self, storage_scheme: common_enums::MerchantStorageScheme) {
        self.updated_by = Some(storage_scheme.to_string());
    }
}

#[cfg(feature = "v1")]
impl From<CustomerNew> for Customer {
    fn from(customer_new: CustomerNew) -> Self {
        Self {
            customer_id: customer_new.customer_id,
            merchant_id: customer_new.merchant_id,
            name: customer_new.name,
            email: customer_new.email,
            phone: customer_new.phone,
            phone_country_code: customer_new.phone_country_code,
            description: customer_new.description,
            created_at: customer_new.created_at,
            metadata: customer_new.metadata,
            connector_customer: customer_new.connector_customer,
            modified_at: customer_new.modified_at,
            address_id: customer_new.address_id,
            default_payment_method_id: None,
            updated_by: customer_new.updated_by,
            version: customer_new.version,
            tax_registration_id: customer_new.tax_registration_id,
        }
    }
}

#[cfg(feature = "v2")]
#[derive(
    Clone, Debug, Insertable, router_derive::DebugAsDisplay, serde::Deserialize, serde::Serialize,
)]
#[diesel(table_name = customers, primary_key(id))]
pub struct CustomerNew {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub name: Option<Encryption>,
    pub email: Option<Encryption>,
    pub phone: Option<Encryption>,
    pub phone_country_code: Option<String>,
    pub description: Option<Description>,
    pub created_at: PrimitiveDateTime,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub connector_customer: Option<common_types::customers::ConnectorCustomerMap>,
    pub modified_at: PrimitiveDateTime,
    pub default_payment_method_id: Option<common_utils::id_type::GlobalPaymentMethodId>,
    pub updated_by: Option<String>,
    pub version: ApiVersion,
    pub tax_registration_id: Option<Encryption>,
    pub merchant_reference_id: Option<common_utils::id_type::CustomerId>,
    pub default_billing_address: Option<Encryption>,
    pub default_shipping_address: Option<Encryption>,
    pub status: DeleteStatus,
    pub id: common_utils::id_type::GlobalCustomerId,
}

#[cfg(feature = "v2")]
impl CustomerNew {
    pub fn update_storage_scheme(&mut self, storage_scheme: common_enums::MerchantStorageScheme) {
        self.updated_by = Some(storage_scheme.to_string());
    }
}

#[cfg(feature = "v2")]
impl From<CustomerNew> for Customer {
    fn from(customer_new: CustomerNew) -> Self {
        Self {
            merchant_id: customer_new.merchant_id,
            name: customer_new.name,
            email: customer_new.email,
            phone: customer_new.phone,
            phone_country_code: customer_new.phone_country_code,
            description: customer_new.description,
            created_at: customer_new.created_at,
            metadata: customer_new.metadata,
            connector_customer: customer_new.connector_customer,
            modified_at: customer_new.modified_at,
            default_payment_method_id: None,
            updated_by: customer_new.updated_by,
            tax_registration_id: customer_new.tax_registration_id,
            merchant_reference_id: customer_new.merchant_reference_id,
            default_billing_address: customer_new.default_billing_address,
            default_shipping_address: customer_new.default_shipping_address,
            id: customer_new.id,
            version: customer_new.version,
            status: customer_new.status,
        }
    }
}

#[cfg(feature = "v1")]
#[derive(
    Clone, Debug, Identifiable, Queryable, Selectable, serde::Deserialize, serde::Serialize,
)]
#[diesel(table_name = customers, primary_key(customer_id, merchant_id), check_for_backend(diesel::pg::Pg))]
pub struct Customer {
    pub customer_id: common_utils::id_type::CustomerId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub name: Option<Encryption>,
    pub email: Option<Encryption>,
    pub phone: Option<Encryption>,
    pub phone_country_code: Option<String>,
    pub description: Option<Description>,
    pub created_at: PrimitiveDateTime,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub connector_customer: Option<pii::SecretSerdeValue>,
    pub modified_at: PrimitiveDateTime,
    pub address_id: Option<String>,
    pub default_payment_method_id: Option<String>,
    pub updated_by: Option<String>,
    pub version: ApiVersion,
    pub tax_registration_id: Option<Encryption>,
}

#[cfg(feature = "v2")]
#[derive(
    Clone, Debug, Identifiable, Queryable, Selectable, serde::Serialize, serde::Deserialize,
)]
#[diesel(table_name = customers, primary_key(id))]
pub struct Customer {
    pub merchant_id: common_utils::id_type::MerchantId,
    pub name: Option<Encryption>,
    pub email: Option<Encryption>,
    pub phone: Option<Encryption>,
    pub phone_country_code: Option<String>,
    pub description: Option<Description>,
    pub created_at: PrimitiveDateTime,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub connector_customer: Option<common_types::customers::ConnectorCustomerMap>,
    pub modified_at: PrimitiveDateTime,
    pub default_payment_method_id: Option<common_utils::id_type::GlobalPaymentMethodId>,
    pub updated_by: Option<String>,
    pub version: ApiVersion,
    pub tax_registration_id: Option<Encryption>,
    pub merchant_reference_id: Option<common_utils::id_type::CustomerId>,
    pub default_billing_address: Option<Encryption>,
    pub default_shipping_address: Option<Encryption>,
    #[diesel(deserialize_as = RequiredFromNullableWithDefault<DeleteStatus>)]
    pub status: DeleteStatus,
    pub id: common_utils::id_type::GlobalCustomerId,
}

#[cfg(feature = "v1")]
#[derive(
    Clone, Debug, AsChangeset, router_derive::DebugAsDisplay, serde::Deserialize, serde::Serialize,
)]
#[diesel(table_name = customers)]
pub struct CustomerUpdateInternal {
    pub name: Option<Encryption>,
    pub email: Option<Encryption>,
    pub phone: Option<Encryption>,
    pub description: Option<Description>,
    pub phone_country_code: Option<String>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub modified_at: PrimitiveDateTime,
    pub connector_customer: Option<pii::SecretSerdeValue>,
    pub address_id: Option<String>,
    pub default_payment_method_id: Option<Option<String>>,
    pub updated_by: Option<String>,
    pub tax_registration_id: Option<Encryption>,
}

#[cfg(feature = "v1")]
impl CustomerUpdateInternal {
    pub fn apply_changeset(self, source: Customer) -> Customer {
        let Self {
            name,
            email,
            phone,
            description,
            phone_country_code,
            metadata,
            connector_customer,
            address_id,
            default_payment_method_id,
            tax_registration_id,
            ..
        } = self;

        Customer {
            name: name.map_or(source.name, Some),
            email: email.map_or(source.email, Some),
            phone: phone.map_or(source.phone, Some),
            description: description.map_or(source.description, Some),
            phone_country_code: phone_country_code.map_or(source.phone_country_code, Some),
            metadata: metadata.map_or(source.metadata, Some),
            modified_at: common_utils::date_time::now(),
            connector_customer: connector_customer.map_or(source.connector_customer, Some),
            address_id: address_id.map_or(source.address_id, Some),
            default_payment_method_id: default_payment_method_id
                .flatten()
                .map_or(source.default_payment_method_id, Some),
            tax_registration_id: tax_registration_id.map_or(source.tax_registration_id, Some),
            ..source
        }
    }
}

#[cfg(feature = "v2")]
#[derive(
    Clone, Debug, AsChangeset, router_derive::DebugAsDisplay, serde::Deserialize, serde::Serialize,
)]
#[diesel(table_name = customers)]
pub struct CustomerUpdateInternal {
    pub name: Option<Encryption>,
    pub email: Option<Encryption>,
    pub phone: Option<Encryption>,
    pub description: Option<Description>,
    pub phone_country_code: Option<String>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub modified_at: PrimitiveDateTime,
    pub connector_customer: Option<common_types::customers::ConnectorCustomerMap>,
    pub default_payment_method_id: Option<Option<common_utils::id_type::GlobalPaymentMethodId>>,
    pub updated_by: Option<String>,
    pub default_billing_address: Option<Encryption>,
    pub default_shipping_address: Option<Encryption>,
    pub status: Option<DeleteStatus>,
    pub tax_registration_id: Option<Encryption>,
}

#[cfg(feature = "v2")]
impl CustomerUpdateInternal {
    pub fn apply_changeset(self, source: Customer) -> Customer {
        let Self {
            name,
            email,
            phone,
            description,
            phone_country_code,
            metadata,
            connector_customer,
            default_payment_method_id,
            default_billing_address,
            default_shipping_address,
            status,
            tax_registration_id,
            ..
        } = self;

        Customer {
            name: name.map_or(source.name, Some),
            email: email.map_or(source.email, Some),
            phone: phone.map_or(source.phone, Some),
            description: description.map_or(source.description, Some),
            phone_country_code: phone_country_code.map_or(source.phone_country_code, Some),
            metadata: metadata.map_or(source.metadata, Some),
            modified_at: common_utils::date_time::now(),
            connector_customer: connector_customer.map_or(source.connector_customer, Some),
            default_payment_method_id: default_payment_method_id
                .flatten()
                .map_or(source.default_payment_method_id, Some),
            default_billing_address: default_billing_address
                .map_or(source.default_billing_address, Some),
            default_shipping_address: default_shipping_address
                .map_or(source.default_shipping_address, Some),
            status: status.unwrap_or(source.status),
            tax_registration_id: tax_registration_id.map_or(source.tax_registration_id, Some),
            ..source
        }
    }
}


/// Generates different schemas with the ability to mark few fields as mandatory for certain schema
/// Usage
/// ```
/// use router_derive::PolymorphicSchema;
///
/// #[derive(PolymorphicSchema)]
/// #[generate_schemas(PaymentsCreateRequest, PaymentsConfirmRequest)]
/// struct PaymentsRequest {
///     #[mandatory_in(PaymentsCreateRequest = u64)]
///     amount: Option<u64>,
///     #[mandatory_in(PaymentsCreateRequest = String)]
///     currency: Option<String>,
///     payment_method: String,
/// }
/// ```
///
/// This will create two structs `PaymentsCreateRequest` and `PaymentsConfirmRequest` as follows
/// It will retain all the other attributes that are used in the original struct, and only consume
/// the #[mandatory_in] attribute to generate schemas
///
/// ```
/// #[derive(utoipa::ToSchema)]
/// struct PaymentsCreateRequest {
///     #[schema(required = true)]
///     amount: Option<u64>,
///
///     #[schema(required = true)]
///     currency: Option<String>,
///
///     payment_method: String,
/// }
///
/// #[derive(utoipa::ToSchema)]
/// struct PaymentsConfirmRequest {
///     amount: Option<u64>,
///     currency: Option<String>,
///     payment_method: String,
/// }
/// ```
#[proc_macro_derive(
    PolymorphicSchema,
    attributes(mandatory_in, generate_schemas, remove_in)
)]
pub fn polymorphic_schema(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = syn::parse_macro_input!(input as syn::DeriveInput);

    macros::polymorphic_macro_derive_inner(input)
        .unwrap_or_else(|error| error.into_compile_error())
        .into()
}


pub struct Relay;


pub fn new_list(value: Vec<T>) -> Self {
        Self::List(value)
    }


impl api::RefundSync for Stripe {}


pub struct RefundResponse {
    id: String,
    status: RefundStatus,
}


pub struct BankTransferTypes {
    /// The list of eligible connectors for a given payment experience
    #[schema(example = json!(["stripe", "adyen"]))]
    pub eligible_connectors: Vec<String>,
}


pub struct RevolutPayData {}


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

impl std::ops::DerefMut for for PayoutsMandateReference


File: crates/router/src/services/authentication.rs
 Public functions: 27
 Public structs: 43

use std::str::FromStr;

use actix_web::http::header::HeaderMap;
#[cfg(feature = "v2")]
use api_models::payment_methods::PaymentMethodIntentConfirm;
#[cfg(feature = "v1")]
use api_models::payment_methods::{PaymentMethodCreate, PaymentMethodListRequest};
use api_models::payments;
#[cfg(feature = "payouts")]
use api_models::payouts;
use async_trait::async_trait;
use common_enums::TokenPurpose;
use common_utils::{date_time, fp_utils, id_type};
#[cfg(feature = "v2")]
use diesel_models::ephemeral_key;
use error_stack::{report, ResultExt};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
#[cfg(feature = "v2")]
use masking::ExposeInterface;
use masking::PeekInterface;
use router_env::logger;
use serde::Serialize;

use self::blacklist::BlackList;
#[cfg(all(feature = "partial-auth", feature = "v1"))]
use self::detached::ExtractedPayload;
#[cfg(feature = "partial-auth")]
use self::detached::GetAuthType;
use super::authorization::{self, permissions::Permission};
#[cfg(feature = "olap")]
use super::jwt;
#[cfg(feature = "olap")]
use crate::configs::Settings;
#[cfg(feature = "olap")]
use crate::consts;
#[cfg(feature = "olap")]
use crate::core::errors::UserResult;
#[cfg(all(feature = "partial-auth", feature = "v1"))]
use crate::core::metrics;
use crate::{
    core::{
        api_keys,
        errors::{self, utils::StorageErrorExt, RouterResult},
    },
    headers,
    routes::app::SessionStateInfo,
    services::api,
    types::{domain, storage},
    utils::OptionExt,
};

pub mod blacklist;
pub mod cookies;
pub mod decision;

#[cfg(feature = "partial-auth")]
mod detached;

#[cfg(feature = "v1")]
#[derive(Clone, Debug)]
pub struct AuthenticationData {
    pub merchant_account: domain::MerchantAccount,
    pub platform_merchant_account: Option<domain::MerchantAccount>,
    pub key_store: domain::MerchantKeyStore,
    pub profile_id: Option<id_type::ProfileId>,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug)]
pub struct AuthenticationData {
    pub merchant_account: domain::MerchantAccount,
    pub key_store: domain::MerchantKeyStore,
    pub profile: domain::Profile,
    pub platform_merchant_account: Option<domain::MerchantAccount>,
}

#[derive(Clone, Debug)]
pub struct AuthenticationDataWithoutProfile {
    pub merchant_account: domain::MerchantAccount,
    pub key_store: domain::MerchantKeyStore,
}

#[derive(Clone, Debug)]
pub struct AuthenticationDataWithMultipleProfiles {
    pub merchant_account: domain::MerchantAccount,
    pub key_store: domain::MerchantKeyStore,
    pub profile_id_list: Option<Vec<id_type::ProfileId>>,
}

#[derive(Clone, Debug)]
pub struct AuthenticationDataWithUser {
    pub merchant_account: domain::MerchantAccount,
    pub key_store: domain::MerchantKeyStore,
    pub user: storage::User,
    pub profile_id: id_type::ProfileId,
}

#[derive(Clone, Debug)]
pub struct AuthenticationDataWithOrg {
    pub organization_id: id_type::OrganizationId,
}

#[derive(Clone)]
pub struct UserFromTokenWithRoleInfo {
    pub user: UserFromToken,
    pub role_info: authorization::roles::RoleInfo,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[serde(
    tag = "api_auth_type",
    content = "authentication_data",
    rename_all = "snake_case"
)]
pub enum AuthenticationType {
    ApiKey {
        merchant_id: id_type::MerchantId,
        key_id: id_type::ApiKeyId,
    },
    AdminApiKey,
    AdminApiAuthWithMerchantId {
        merchant_id: id_type::MerchantId,
    },
    OrganizationJwt {
        org_id: id_type::OrganizationId,
        user_id: String,
    },
    MerchantJwt {
        merchant_id: id_type::MerchantId,
        user_id: Option<String>,
    },
    MerchantJwtWithProfileId {
        merchant_id: id_type::MerchantId,
        profile_id: Option<id_type::ProfileId>,
        user_id: String,
    },
    UserJwt {
        user_id: String,
    },
    SinglePurposeJwt {
        user_id: String,
        purpose: TokenPurpose,
    },
    SinglePurposeOrLoginJwt {
        user_id: String,
        purpose: Option<TokenPurpose>,
        role_id: Option<String>,
    },
    MerchantId {
        merchant_id: id_type::MerchantId,
    },
    PublishableKey {
        merchant_id: id_type::MerchantId,
    },
    WebhookAuth {
        merchant_id: id_type::MerchantId,
    },
    NoAuth,
}

impl events::EventInfo for AuthenticationType {
    type Data = Self;
    fn data(&self) -> error_stack::Result<Self::Data, events::EventsError> {
        Ok(self.clone())
    }

    fn key(&self) -> String {
        "auth_info".to_string()
    }
}

impl AuthenticationType {
    pub fn get_merchant_id(&self) -> Option<&id_type::MerchantId> {
        match self {
            Self::ApiKey {
                merchant_id,
                key_id: _,
            }
            | Self::AdminApiAuthWithMerchantId { merchant_id }
            | Self::MerchantId { merchant_id }
            | Self::PublishableKey { merchant_id }
            | Self::MerchantJwt {
                merchant_id,
                user_id: _,
            }
            | Self::MerchantJwtWithProfileId { merchant_id, .. }
            | Self::WebhookAuth { merchant_id } => Some(merchant_id),
            Self::AdminApiKey
            | Self::OrganizationJwt { .. }
            | Self::UserJwt { .. }
            | Self::SinglePurposeJwt { .. }
            | Self::SinglePurposeOrLoginJwt { .. }
            | Self::NoAuth => None,
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize, serde::Deserialize, strum::Display)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum ExternalServiceType {
    Hypersense,
}

#[cfg(feature = "olap")]
#[derive(Clone, Debug)]
pub struct UserFromSinglePurposeToken {
    pub user_id: String,
    pub origin: domain::Origin,
    pub path: Vec<TokenPurpose>,
    pub tenant_id: Option<id_type::TenantId>,
}

#[cfg(feature = "olap")]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct SinglePurposeToken {
    pub user_id: String,
    pub purpose: TokenPurpose,
    pub origin: domain::Origin,
    pub path: Vec<TokenPurpose>,
    pub exp: u64,
    pub tenant_id: Option<id_type::TenantId>,
}

#[cfg(feature = "olap")]
impl SinglePurposeToken {
    pub async fn new_token(
        user_id: String,
        purpose: TokenPurpose,
        origin: domain::Origin,
        settings: &Settings,
        path: Vec<TokenPurpose>,
        tenant_id: Option<id_type::TenantId>,
    ) -> UserResult<String> {
        let exp_duration =
            std::time::Duration::from_secs(consts::SINGLE_PURPOSE_TOKEN_TIME_IN_SECS);
        let exp = jwt::generate_exp(exp_duration)?.as_secs();
        let token_payload = Self {
            user_id,
            purpose,
            origin,
            exp,
            path,
            tenant_id,
        };
        jwt::generate_jwt(&token_payload, settings).await
    }
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct AuthToken {
    pub user_id: String,
    pub merchant_id: id_type::MerchantId,
    pub role_id: String,
    pub exp: u64,
    pub org_id: id_type::OrganizationId,
    pub profile_id: id_type::ProfileId,
    pub tenant_id: Option<id_type::TenantId>,
}

#[cfg(feature = "olap")]
impl AuthToken {
    pub async fn new_token(
        user_id: String,
        merchant_id: id_type::MerchantId,
        role_id: String,
        settings: &Settings,
        org_id: id_type::OrganizationId,
        profile_id: id_type::ProfileId,
        tenant_id: Option<id_type::TenantId>,
    ) -> UserResult<String> {
        let exp_duration = std::time::Duration::from_secs(consts::JWT_TOKEN_TIME_IN_SECS);
        let exp = jwt::generate_exp(exp_duration)?.as_secs();
        let token_payload = Self {
            user_id,
            merchant_id,
            role_id,
            exp,
            org_id,
            profile_id,
            tenant_id,
        };
        jwt::generate_jwt(&token_payload, settings).await
    }
}

#[derive(Clone)]
pub struct UserFromToken {
    pub user_id: String,
    pub merchant_id: id_type::MerchantId,
    pub role_id: String,
    pub org_id: id_type::OrganizationId,
    pub profile_id: id_type::ProfileId,
    pub tenant_id: Option<id_type::TenantId>,
}

pub struct UserIdFromAuth {
    pub user_id: String,
    pub tenant_id: Option<id_type::TenantId>,
}

#[cfg(feature = "olap")]
#[derive(serde::Serialize, serde::Deserialize)]
pub struct SinglePurposeOrLoginToken {
    pub user_id: String,
    pub role_id: Option<String>,
    pub purpose: Option<TokenPurpose>,
    pub exp: u64,
    pub tenant_id: Option<id_type::TenantId>,
}

pub trait AuthInfo {
    fn get_merchant_id(&self) -> Option<&id_type::MerchantId>;
}

impl AuthInfo for () {
    fn get_merchant_id(&self) -> Option<&id_type::MerchantId> {
        None
    }
}

#[cfg(feature = "v1")]
impl AuthInfo for AuthenticationData {
    fn get_merchant_id(&self) -> Option<&id_type::MerchantId> {
        Some(self.merchant_account.get_id())
    }
}

#[cfg(feature = "v2")]
impl AuthInfo for AuthenticationData {
    fn get_merchant_id(&self) -> Option<&id_type::MerchantId> {
        Some(self.merchant_account.get_id())
    }
}

impl AuthInfo for AuthenticationDataWithMultipleProfiles {
    fn get_merchant_id(&self) -> Option<&id_type::MerchantId> {
        Some(self.merchant_account.get_id())
    }
}

#[async_trait]
pub trait AuthenticateAndFetch<T, A>
where
    A: SessionStateInfo,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(T, AuthenticationType)>;
}

#[derive(Debug, Default)]
pub struct ApiKeyAuth {
    pub is_connected_allowed: bool,
    pub is_platform_allowed: bool,
}

pub struct NoAuth;

#[cfg(feature = "partial-auth")]
impl GetAuthType for ApiKeyAuth {
    fn get_auth_type(&self) -> detached::PayloadType {
        detached::PayloadType::ApiKey
    }
}

//
// # Header Auth
//
// Header Auth is a feature that allows you to authenticate requests using custom headers. This is
// done by checking whether the request contains the specified headers.
// - `x-merchant-id` header is used to authenticate the merchant.
//
// ## Checksum
// - `x-auth-checksum` header is used to authenticate the request. The checksum is calculated using the
// above mentioned headers is generated by hashing the headers mentioned above concatenated with `:` and then hashed with the detached authentication key.
//
// When the [`partial-auth`] feature is disabled the implementation for [`AuthenticateAndFetch`]
// changes where the authentication is done by the [`I`] implementation.
//
pub struct HeaderAuth<I>(pub I);

#[async_trait]
impl<A> AuthenticateAndFetch<(), A> for NoAuth
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        _request_headers: &HeaderMap,
        _state: &A,
    ) -> RouterResult<((), AuthenticationType)> {
        Ok(((), AuthenticationType::NoAuth))
    }
}

#[async_trait]
impl<A, T> AuthenticateAndFetch<Option<T>, A> for NoAuth
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        _request_headers: &HeaderMap,
        _state: &A,
    ) -> RouterResult<(Option<T>, AuthenticationType)> {
        Ok((None, AuthenticationType::NoAuth))
    }
}

#[cfg(feature = "v2")]
#[async_trait]
impl<A> AuthenticateAndFetch<AuthenticationData, A> for ApiKeyAuth
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        let api_key = get_api_key(request_headers)
            .change_context(errors::ApiErrorResponse::Unauthorized)?
            .trim();
        if api_key.is_empty() {
            return Err(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("API key is empty");
        }

        let profile_id = HeaderMapStruct::new(request_headers)
            .get_id_type_from_header::<id_type::ProfileId>(headers::X_PROFILE_ID)?;

        let api_key = api_keys::PlaintextApiKey::from(api_key);
        let hash_key = {
            let config = state.conf();
            config.api_keys.get_inner().get_hash_key()?
        };
        let hashed_api_key = api_key.keyed_hash(hash_key.peek());

        let stored_api_key = state
            .store()
            .find_api_key_by_hash_optional(hashed_api_key.into())
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError) // If retrieve failed
            .attach_printable("Failed to retrieve API key")?
            .ok_or(report!(errors::ApiErrorResponse::Unauthorized)) // If retrieve returned `None`
            .attach_printable("Merchant not authenticated")?;

        if stored_api_key
            .expires_at
            .map(|expires_at| expires_at < date_time::now())
            .unwrap_or(false)
        {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("API key has expired");
        }

        let key_manager_state = &(&state.session_state()).into();

        let key_store = state
            .store()
            .get_merchant_key_store_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &state.store().get_master_key().to_vec().into(),
            )
            .await
            .change_context(errors::ApiErrorResponse::Unauthorized)
            .attach_printable("Failed to fetch merchant key store for the merchant id")?;

        let merchant = state
            .store()
            .find_merchant_account_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &key_store,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

        // Get connected merchant account if API call is done by Platform merchant account on behalf of connected merchant account
        let (merchant, platform_merchant_account) = if state.conf().platform.enabled {
            get_platform_merchant_account(state, request_headers, merchant).await?
        } else {
            (merchant, None)
        };

        if platform_merchant_account.is_some() && !self.is_platform_allowed {
            return Err(report!(
                errors::ApiErrorResponse::PlatformAccountAuthNotSupported
            ))
            .attach_printable("Platform not authorized to access the resource");
        }

        let key_store = if platform_merchant_account.is_some() {
            state
                .store()
                .get_merchant_key_store_by_merchant_id(
                    key_manager_state,
                    merchant.get_id(),
                    &state.store().get_master_key().to_vec().into(),
                )
                .await
                .change_context(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("Failed to fetch merchant key store for the merchant id")?
        } else {
            key_store
        };

        let profile = state
            .store()
            .find_business_profile_by_profile_id(key_manager_state, &key_store, &profile_id)
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

        let auth = AuthenticationData {
            merchant_account: merchant,
            platform_merchant_account,
            key_store,
            profile,
        };
        Ok((
            auth.clone(),
            AuthenticationType::ApiKey {
                merchant_id: auth.merchant_account.get_id().clone(),
                key_id: stored_api_key.key_id,
            },
        ))
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<A> AuthenticateAndFetch<AuthenticationData, A> for ApiKeyAuth
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        let api_key = get_api_key(request_headers)
            .change_context(errors::ApiErrorResponse::Unauthorized)?
            .trim();
        if api_key.is_empty() {
            return Err(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("API key is empty");
        }

        let api_key = api_keys::PlaintextApiKey::from(api_key);
        let hash_key = {
            let config = state.conf();
            config.api_keys.get_inner().get_hash_key()?
        };
        let hashed_api_key = api_key.keyed_hash(hash_key.peek());

        let stored_api_key = state
            .store()
            .find_api_key_by_hash_optional(hashed_api_key.into())
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError) // If retrieve failed
            .attach_printable("Failed to retrieve API key")?
            .ok_or(report!(errors::ApiErrorResponse::Unauthorized)) // If retrieve returned `None`
            .attach_printable("Merchant not authenticated")?;

        if stored_api_key
            .expires_at
            .map(|expires_at| expires_at < date_time::now())
            .unwrap_or(false)
        {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("API key has expired");
        }

        let key_manager_state = &(&state.session_state()).into();

        let key_store = state
            .store()
            .get_merchant_key_store_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &state.store().get_master_key().to_vec().into(),
            )
            .await
            .change_context(errors::ApiErrorResponse::Unauthorized)
            .attach_printable("Failed to fetch merchant key store for the merchant id")?;

        let profile_id =
            get_header_value_by_key(headers::X_PROFILE_ID.to_string(), request_headers)?
                .map(id_type::ProfileId::from_str)
                .transpose()
                .change_context(errors::ValidationError::IncorrectValueProvided {
                    field_name: "X-Profile-Id",
                })
                .change_context(errors::ApiErrorResponse::Unauthorized)?;

        let merchant = state
            .store()
            .find_merchant_account_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &key_store,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

        let (merchant, platform_merchant_account) = if state.conf().platform.enabled {
            get_platform_merchant_account(state, request_headers, merchant).await?
        } else {
            (merchant, None)
        };

        if platform_merchant_account.is_some() && !self.is_platform_allowed {
            return Err(report!(
                errors::ApiErrorResponse::PlatformAccountAuthNotSupported
            ))
            .attach_printable("Platform not authorized to access the resource");
        }

        let key_store = if platform_merchant_account.is_some() {
            state
                .store()
                .get_merchant_key_store_by_merchant_id(
                    key_manager_state,
                    merchant.get_id(),
                    &state.store().get_master_key().to_vec().into(),
                )
                .await
                .change_context(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("Failed to fetch merchant key store for the merchant id")?
        } else {
            key_store
        };

        let auth = AuthenticationData {
            merchant_account: merchant,
            platform_merchant_account,
            key_store,
            profile_id,
        };
        Ok((
            auth.clone(),
            AuthenticationType::ApiKey {
                merchant_id: auth.merchant_account.get_id().clone(),
                key_id: stored_api_key.key_id,
            },
        ))
    }
}

#[derive(Debug)]
pub struct ApiKeyAuthWithMerchantIdFromRoute(pub id_type::MerchantId);

#[cfg(feature = "partial-auth")]
impl GetAuthType for ApiKeyAuthWithMerchantIdFromRoute {
    fn get_auth_type(&self) -> detached::PayloadType {
        detached::PayloadType::ApiKey
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<A> AuthenticateAndFetch<AuthenticationData, A> for ApiKeyAuthWithMerchantIdFromRoute
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        let api_auth = ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        };
        let (auth_data, auth_type) = api_auth
            .authenticate_and_fetch(request_headers, state)
            .await?;

        let merchant_id_from_route = self.0.clone();
        let merchant_id_from_api_key = auth_data.merchant_account.get_id();

        if merchant_id_from_route != *merchant_id_from_api_key {
            return Err(report!(errors::ApiErrorResponse::Unauthorized)).attach_printable(
                "Merchant ID from route and Merchant ID from api-key in header do not match",
            );
        }

        Ok((auth_data, auth_type))
    }
}

#[derive(Debug, Default)]
pub struct PlatformOrgAdminAuth {
    pub is_admin_auth_allowed: bool,
    pub organization_id: Option<id_type::OrganizationId>,
}

#[cfg(feature = "v1")]
#[async_trait]
impl<A> AuthenticateAndFetch<Option<AuthenticationDataWithOrg>, A> for PlatformOrgAdminAuth
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(Option<AuthenticationDataWithOrg>, AuthenticationType)> {
        // Step 1: Admin API Key and API Key Fallback (if allowed)
        if self.is_admin_auth_allowed {
            let admin_auth = AdminApiAuthWithApiKeyFallback {
                organization_id: self.organization_id.clone(),
            };
            match admin_auth
                .authenticate_and_fetch(request_headers, state)
                .await
            {
                Ok((auth, auth_type)) => {
                    return Ok((auth, auth_type));
                }
                Err(e) => {
                    logger::warn!("Admin API Auth failed: {:?}", e);
                }
            }
        }

        // Step 2: Try Platform Auth
        let api_key = get_api_key(request_headers)
            .change_context(errors::ApiErrorResponse::Unauthorized)?
            .trim();
        if api_key.is_empty() {
            return Err(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("API key is empty");
        }

        let api_key_plaintext = api_keys::PlaintextApiKey::from(api_key);
        let hash_key = state.conf().api_keys.get_inner().get_hash_key()?;
        let hashed_api_key = api_key_plaintext.keyed_hash(hash_key.peek());

        let stored_api_key = state
            .store()
            .find_api_key_by_hash_optional(hashed_api_key.into())
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to retrieve API key")?
            .ok_or_else(|| report!(errors::ApiErrorResponse::Unauthorized))
            .attach_printable("Merchant not authenticated via API key")?;

        if stored_api_key
            .expires_at
            .map(|expires_at| expires_at < date_time::now())
            .unwrap_or(false)
        {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("API key has expired");
        }

        let key_manager_state = &(&state.session_state()).into();

        let key_store = state
            .store()
            .get_merchant_key_store_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &state.store().get_master_key().to_vec().into(),
            )
            .await
            .change_context(errors::ApiErrorResponse::Unauthorized)
            .attach_printable("Failed to fetch merchant key store for the merchant id")?;

        let merchant_account = state
            .store()
            .find_merchant_account_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &key_store,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)
            .attach_printable("Merchant account not found")?;

        if !(state.conf().platform.enabled && merchant_account.is_platform_account()) {
            return Err(report!(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("Platform authentication check failed"));
        }

        if let Some(ref organization_id) = self.organization_id {
            if organization_id != merchant_account.get_org_id() {
                return Err(report!(errors::ApiErrorResponse::Unauthorized))
                    .attach_printable("Organization ID does not match");
            }
        }

        Ok((
            Some(AuthenticationDataWithOrg {
                organization_id: merchant_account.get_org_id().clone(),
            }),
            AuthenticationType::ApiKey {
                merchant_id: merchant_account.get_id().clone(),
                key_id: stored_api_key.key_id,
            },
        ))
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<A> AuthenticateAndFetch<AuthenticationData, A> for PlatformOrgAdminAuth
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        let api_key = get_api_key(request_headers)
            .change_context(errors::ApiErrorResponse::Unauthorized)?
            .trim();
        if api_key.is_empty() {
            return Err(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("API key is empty");
        }

        let api_key_plaintext = api_keys::PlaintextApiKey::from(api_key);
        let hash_key = state.conf().api_keys.get_inner().get_hash_key()?;
        let hashed_api_key = api_key_plaintext.keyed_hash(hash_key.peek());

        let stored_api_key = state
            .store()
            .find_api_key_by_hash_optional(hashed_api_key.into())
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to retrieve API key")?
            .ok_or_else(|| report!(errors::ApiErrorResponse::Unauthorized))
            .attach_printable("Merchant not authenticated via API key")?;

        if stored_api_key
            .expires_at
            .map(|expires_at| expires_at < date_time::now())
            .unwrap_or(false)
        {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("API key has expired");
        }

        let key_manager_state = &(&state.session_state()).into();

        let key_store = state
            .store()
            .get_merchant_key_store_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &state.store().get_master_key().to_vec().into(),
            )
            .await
            .change_context(errors::ApiErrorResponse::Unauthorized)
            .attach_printable("Failed to fetch merchant key store for the merchant id")?;

        let merchant_account = state
            .store()
            .find_merchant_account_by_merchant_id(
                key_manager_state,
                &stored_api_key.merchant_id,
                &key_store,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)
            .attach_printable("Merchant account not found")?;

        if !(state.conf().platform.enabled && merchant_account.is_platform_account()) {
            return Err(report!(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("Platform authentication check failed"));
        }

        if let Some(ref organization_id) = self.organization_id {
            if organization_id != merchant_account.get_org_id() {
                return Err(report!(errors::ApiErrorResponse::Unauthorized))
                    .attach_printable("Organization ID does not match");
            }
        }

        let auth = AuthenticationData {
            merchant_account: merchant_account.clone(),
            platform_merchant_account: Some(merchant_account.clone()),
            key_store,
            profile_id: None,
        };

        Ok((
            auth.clone(),
            AuthenticationType::ApiKey {
                merchant_id: auth.merchant_account.get_id().clone(),
                key_id: stored_api_key.key_id,
            },
        ))
    }
}

#[derive(Debug)]
pub struct PlatformOrgAdminAuthWithMerchantIdFromRoute {
    pub merchant_id_from_route: id_type::MerchantId,
    pub is_admin_auth_allowed: bool,
}

#[cfg(feature = "v1")]
impl PlatformOrgAdminAuthWithMerchantIdFromRoute {
    async fn fetch_key_store_and_account<A: SessionStateInfo + Sync>(
        merchant_id: &id_type::MerchantId,
        state: &A,
    ) -> RouterResult<(domain::MerchantKeyStore, domain::MerchantAccount)> {
        let key_manager_state = &(&state.session_state()).into();

        let key_store = state
            .store()
            .get_merchant_key_store_by_merchant_id(
                key_manager_state,
                merchant_id,
                &state.store().get_master_key().to_vec().into(),
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

        let merchant = state
            .store()
            .find_merchant_account_by_merchant_id(key_manager_state, merchant_id, &key_store)
            .await
            .to_not_found_response(errors::ApiErrorResponse::Unauthorized)?;

        Ok((key_store, merchant))
    }
}

#[cfg(feature = "v1")]
#[async_trait]
impl<A> AuthenticateAndFetch<AuthenticationData, A> for PlatformOrgAdminAuthWithMerchantIdFromRoute
where
    A: SessionStateInfo + Sync,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        let route_merchant_id = self.merchant_id_from_route.clone();

        // Step 1: Admin API Key and API Key Fallback (if allowed)
        if self.is_admin_auth_allowed {
            let admin_auth =
                AdminApiAuthWithApiKeyFallbackAndMerchantIdFromRoute(route_merchant_id.clone());

            match admin_auth
                .authenticate_and_fetch(request_headers, state)
                .await
            {
                Ok((auth_data, auth_type)) => return Ok((auth_data, auth_type)),
                Err(e) => {
                    logger::warn!("Admin API Auth failed: {:?}", e);
                }
            }
        }

        // Step 2: Platform authentication
        let api_key = get_api_key(request_headers)
            .change_context(errors::ApiErrorResponse::Unauthorized)?
            .trim();
        if api_key.is_empty() {
            return Err(errors::ApiErrorResponse::Unauthorized)
                .attach_printable("API key is empty");
        }

        let api_key_plaintext = api_keys::PlaintextApiKey::from(api_key);
        let hash_key = {
            let config = state.conf();
            config.api_keys.get_inner().get_hash_key()?
        };
        let hashed_api_key = api_key_plaintext.keyed_hash(hash_key.peek());

        let stored_api_key = state
            .store()
            .find_api_key_by_hash_optional(hashed_api_key.into())
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to retrieve API key")?
            .ok_or_else(|| report!(errors::ApiErrorResponse::Unauthorized))
            .attach_printable("Merchant not authenticated via API key")?;

        if stored_api_key
            .expires_at
            .map(|expires_at| expires_at < date_time::now())
            .unwrap_or(false)
        {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("API key has expired");
        }

        let (_, platform_merchant) =
            Self::fetch_key_store_and_account(&stored_api_key.merchant_id, state).await?;

        if !(state.conf().platform.enabled && platform_merchant.is_platform_account()) {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("Platform authentication check failed");
        }

        let (route_key_store, route_merchant) =
            Self::fetch_key_store_and_account(&route_merchant_id, state).await?;

        if platform_merchant.get_org_id() != route_merchant.get_org_id() {
            return Err(report!(errors::ApiErrorResponse::Unauthorized))
                .attach_printable("Route merchant not under same org as platform merchant");
        }

        let auth = AuthenticationData {
            merchant_account: route_merchant,
            platform_merchant_account: Some(platform_merchant.clone()),
            key_store: route_key_store,
            profile_id: None,
        };

        Ok((
            auth.clone(),
            AuthenticationType::ApiKey {
                merchant_id: platform_merchant.get_id().clone(),
                key_id: stored_api_key.key_id,
            },
        ))
    }
}

#[cfg(not(feature = "partial-auth"))]
#[async_trait]
impl<A, I> AuthenticateAndFetch<AuthenticationData, A> for HeaderAuth<I>
where
    A: SessionStateInfo + Send + Sync,
    I: AuthenticateAndFetch<AuthenticationData, A> + Sync + Send,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        self.0.authenticate_and_fetch(request_headers, state).await
    }
}

#[cfg(all(feature = "partial-auth", feature = "v1"))]
#[async_trait]
impl<A, I> AuthenticateAndFetch<AuthenticationData, A> for HeaderAuth<I>
where
    A: SessionStateInfo + Sync,
    I: AuthenticateAndFetch<AuthenticationData, A> + GetAuthType + Sync + Send,
{
    async fn authenticate_and_fetch(
        &self,
        request_headers: &HeaderMap,
        state: &A,
    ) -> RouterResult<(AuthenticationData, AuthenticationType)> {
        let enable_partial_auth = state.conf().api_keys.get_inner().enable_partial_auth;

        // This is a early return if partial auth is disabled
        // Preventing the need to go through the header extraction process
        if !enable_partial_auth {
            return self.0.authenticate_and_fetch(request_headers, state).await;
        }

        let report_failure = || {
            metrics::PARTIAL_AUTH_FAILURE.add(1, &[]);
        };

        let profile_id = HeaderMapStruct::new(request_headers)
            .get_id_type_from_header_if_present::<id_type::ProfileId>(headers::X_PROFILE_ID)
            .change_context(errors::ValidationError::IncorrectValueProvided {
                field_name: "X-Profile-Id",
            })
            .change_context(errors::ApiErrorResponse::Unauthorized)?;

        let payload = ExtractedPayload::from_headers(request_headers)
            .and_then(|value| {
                let (algo, secret) = state.get_detached_auth()?;

                Ok(value
                    .verify_checksum(request_headers, algo, secret)
                    .then_some(value))
            })
            .map(|inner_payload| {
                inner_payload.and_then(|inner| {
                    (inner.payload_type == self.0.get_auth_type()).then_some(inner)
                })
            });

        match payload {
            Ok(Some(data)) => match data {
                ExtractedPayload {
                    payload_type: detached::PayloadType::ApiKey,
                    merchant_id: Some(merchant_id),
                    key_id: Some(key_id),
                } => {
                    let auth = construct_authentication_data(
                        state,
                        &merchant_id,
                        request_headers,
                        profile_id,
                    )
                    .await?;
                    Ok((
                        auth.clone(),
                        AuthenticationType::ApiKey {
                            merchant_id: auth.merchant_account.get_id().clone(),
                            key_id,
                        },
                    ))
                }
                ExtractedPayload {
                    payload_type: detached::PayloadType::PublishableKey,
                    merchant_id: Some(merchant_id),
                    key_id: None,
                } => {
                    let auth = construct_authentication_data(
                        state,
                        &merchant_id,
                        request_headers,
                        profile_id,
                    )
                    .await?;
                    Ok((
                        auth.clone(),
                        AuthenticationType::PublishableKey {
                            merchant_id: auth.merchant_account.get_id().clone(),
                        },
                    ))
                }
                _ => {
                    report_failure();
                    self.0.authenticate_and_fetch(request_headers, state).await
                }
            },
            Ok(None) => {
                report_failure();
                self.0.authenticate_and_fetch(request_headers, state).await
            }
            Err(error) => {
                logger::error!(%error, "Failed to extract payload from headers");
                report_failure();
                self.0.authenticate_and_fetch(request_headers, state).await
            }
        }
    }
}

#[cfg(all(feature = "partial-auth", feature = "v2"))]
#[async_trait]
impl<A, I> AuthenticateAndFetch<AuthenticationData, A> for HeaderAuth<I>
where


impl api::PaymentSession for Authorizedotnet {}

impl api::PaymentSession for for Authorizedotnet


OpenAPI Block Path: components.schemas.BraintreeData
{
  "type": "object",
  "required": [
    "merchant_account_id",
    "merchant_config_currency"
  ],
  "properties": {
    "merchant_account_id": {
      "type": "string",
      "description": "Information about the merchant_account_id that merchant wants to specify at connector level."
    },
    "merchant_config_currency": {
      "type": "string",
      "description": "Information about the merchant_config_currency that merchant wants to specify at connector level."
    }
  }
}


pub struct MerchantConnectorListResponse {
    /// Type of the Connector for the financial use case. Could range from Payments to Accounting to Banking.
    #[schema(value_type = ConnectorType, example = "payment_processor")]
    pub connector_type: api_enums::ConnectorType,

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

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

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

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

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

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

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

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

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

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


pub async fn routing_link_config(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<common_utils::id_type::ProfileId>,
    json_payload: web::Json<routing_types::RoutingAlgorithmId>,
    transaction_type: &enums::TransactionType,
) -> impl Responder {
    let flow = Flow::RoutingLinkConfig;
    let wrapper = routing_types::RoutingLinkWrapper {
        profile_id: path.into_inner(),
        algorithm_id: json_payload.into_inner(),
    };

    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        wrapper.clone(),
        |state, auth: auth::AuthenticationData, wrapper, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            routing::link_routing_config_under_profile(
                state,
                merchant_context,
                wrapper.profile_id,
                wrapper.algorithm_id.routing_algorithm_id,
                transaction_type,
            )
        },
        #[cfg(not(feature = "release"))]
        auth::auth_type(
            &auth::V2ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            },
            &auth::JWTAuthProfileFromRoute {
                profile_id: wrapper.profile_id,
                required_permission: Permission::MerchantRoutingWrite,
            },
            req.headers(),
        ),
        #[cfg(feature = "release")]
        &auth::JWTAuthProfileFromRoute {
            profile_id: wrapper.profile_id,
            required_permission: Permission::MerchantRoutingWrite,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub struct DashboardNoPermissionAuth;


pub struct PayeezyRefundRequest {
    transaction_tag: String,
    transaction_type: PayeezyTransactionType,
    amount: String,
    currency_code: String,
}


pub struct CybersourceErrorInformation {
    reason: Option<String>,
    message: Option<String>,
    details: Option<Vec<Details>>,
}


OpenAPI Block Path: components.schemas.BusinessPaymentLinkConfig
{
  "allOf": [
    {
      "$ref": "#/components/schemas/PaymentLinkConfigRequest"
    },
    {
      "type": "object",
      "properties": {
        "domain_name": {
          "type": "string",
          "description": "Custom domain name to be used for hosting the link in your own domain",
          "nullable": true
        },
        "business_specific_configs": {
          "type": "object",
          "description": "list of configs for multi theme setup",
          "additionalProperties": {
            "$ref": "#/components/schemas/PaymentLinkConfigRequest"
          },
          "nullable": true
        },
        "allowed_domains": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "A list of allowed domains (glob patterns) where this link can be embedded / opened from",
          "uniqueItems": true,
          "nullable": true
        },
        "branding_visibility": {
          "type": "boolean",
          "description": "Toggle for HyperSwitch branding visibility",
          "nullable": true
        }
      }
    }
  ]
}


File: crates/analytics/src/refunds/metrics/refund_success_count.rs

use std::collections::HashSet;

use api_models::analytics::{
    refunds::{RefundDimensions, RefundFilters, RefundMetricsBucketIdentifier},
    Granularity, TimeRange,
};
use common_utils::errors::ReportSwitchExt;
use diesel_models::enums as storage_enums;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

use super::RefundMetricRow;
use crate::{
    enums::AuthInfo,
    query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
    types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
};

#[derive(Default)]
pub(super) struct RefundSuccessCount {}

#[async_trait::async_trait]
impl<T> super::RefundMetric<T> for RefundSuccessCount
where
    T: AnalyticsDataSource + super::RefundMetricAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    async fn load_metrics(
        &self,
        dimensions: &[RefundDimensions],
        auth: &AuthInfo,
        filters: &RefundFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<HashSet<(RefundMetricsBucketIdentifier, RefundMetricRow)>>
    where
        T: AnalyticsDataSource + super::RefundMetricAnalytics,
    {
        let mut query_builder = QueryBuilder::new(AnalyticsCollection::Refund);

        for dim in dimensions.iter() {
            query_builder.add_select_column(dim).switch()?;
        }

        query_builder
            .add_select_column(Aggregate::Count {
                field: None,
                alias: Some("count"),
            })
            .switch()?;
        query_builder
            .add_select_column(Aggregate::Min {
                field: "created_at",
                alias: Some("start_bucket"),
            })
            .switch()?;
        query_builder
            .add_select_column(Aggregate::Max {
                field: "created_at",
                alias: Some("end_bucket"),
            })
            .switch()?;

        filters.set_filter_clause(&mut query_builder).switch()?;

        auth.set_filter_clause(&mut query_builder).switch()?;

        time_range.set_filter_clause(&mut query_builder).switch()?;

        for dim in dimensions.iter() {
            query_builder.add_group_by_clause(dim).switch()?;
        }

        if let Some(granularity) = granularity {
            granularity
                .set_group_by_clause(&mut query_builder)
                .switch()?;
        }

        query_builder
            .add_filter_clause(
                RefundDimensions::RefundStatus,
                storage_enums::RefundStatus::Success,
            )
            .switch()?;
        query_builder
            .execute_query::<RefundMetricRow, _>(pool)
            .await
            .change_context(MetricsError::QueryBuildingError)?
            .change_context(MetricsError::QueryExecutionFailure)?
            .into_iter()
            .map(|i| {
                Ok((
                    RefundMetricsBucketIdentifier::new(
                        i.currency.as_ref().map(|i| i.0),
                        None,
                        i.connector.clone(),
                        i.refund_type.as_ref().map(|i| i.0.to_string()),
                        i.profile_id.clone(),
                        i.refund_reason.clone(),
                        i.refund_error_message.clone(),
                        TimeRange {
                            start_time: match (granularity, i.start_bucket) {
                                (Some(g), Some(st)) => g.clip_to_start(st)?,
                                _ => time_range.start_time,
                            },
                            end_time: granularity.as_ref().map_or_else(
                                || Ok(time_range.end_time),
                                |g| i.end_bucket.map(|et| g.clip_to_end(et)).transpose(),
                            )?,
                        },
                    ),
                    i,
                ))
            })
            .collect::<error_stack::Result<
                HashSet<(RefundMetricsBucketIdentifier, RefundMetricRow)>,
                crate::query::PostProcessingError,
            >>()
            .change_context(MetricsError::PostProcessingFailure)
    }
}


pub async fn authentication_sync(
    state: web::Data<app::AppState>,
    req: HttpRequest,
    path: web::Path<(
        common_utils::id_type::MerchantId,
        common_utils::id_type::AuthenticationId,
    )


pub async fn update_by_address_id(
        conn: &PgPooledConn,
        address_id: String,
        address: AddressUpdateInternal,
    ) -> StorageResult<Self> {
        match generics::generic_update_by_id::<<Self as HasTable>::Table, _, _, _>(
            conn,
            address_id.clone(),
            address,
        )
        .await
        {
            Err(error) => match error.current_context() {
                errors::DatabaseError::NotFound => {
                    Err(error.attach_printable("Address with the given ID doesn't exist"))
                }
                errors::DatabaseError::NoFieldsToUpdate => {
                    generics::generic_find_by_id::<<Self as HasTable>::Table, _, _>(
                        conn,
                        address_id.clone(),
                    )
                    .await
                }
                _ => Err(error),
            },
            result => result,
        }
    }


pub struct ResponseData {
    pub id: String,
    pub amount: i64,
    pub status: RapydPaymentStatus,
    pub next_action: NextAction,
    pub redirect_url: Option<String>,
    pub original_amount: Option<i64>,
    pub is_partial: Option<bool>,
    pub currency_code: Option<enums::Currency>,
    pub country_code: Option<String>,
    pub captured: Option<bool>,
    pub transaction_id: String,
    pub merchant_reference_id: Option<String>,
    pub paid: Option<bool>,
    pub failure_code: Option<String>,
    pub failure_message: Option<String>,
}


OpenAPI Block Path: paths."/account/{account_id}/connectors"
{
  "post": {
    "tags": [
      "Merchant Connector Account"
    ],
    "summary": "Merchant Connector - Create",
    "description": "Creates a new Merchant Connector for the merchant account. The connector could be a payment processor/facilitator/acquirer or a provider of specialized services like Fraud/Accounting etc.",
    "operationId": "Create a Merchant Connector",
    "parameters": [
      {
        "name": "account_id",
        "in": "path",
        "description": "The unique identifier for the merchant account",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    ],
    "requestBody": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/MerchantConnectorCreate"
          },
          "examples": {
            "Create a merchant account with custom connector label": {
              "value": {
                "connector_account_details": {
                  "api_key": "{{adyen-api-key}}",
                  "auth_type": "BodyKey",
                  "key1": "{{adyen_merchant_account}}"
                },
                "connector_label": "EU_adyen",
                "connector_name": "adyen",
                "connector_type": "payment_processor"
              }
            },
            "Create a merchant connector account under a specific profile": {
              "value": {
                "connector_account_details": {
                  "api_key": "{{adyen-api-key}}",
                  "auth_type": "BodyKey",
                  "key1": "{{adyen_merchant_account}}"
                },
                "connector_name": "adyen",
                "connector_type": "payment_processor",
                "profile_id": "{{profile_id}}"
              }
            },
            "Create a merchant connector account with minimal fields": {
              "value": {
                "connector_account_details": {
                  "api_key": "{{adyen-api-key}}",
                  "auth_type": "BodyKey",
                  "key1": "{{adyen_merchant_account}}"
                },
                "connector_name": "adyen",
                "connector_type": "payment_processor"
              }
            }
          }
        }
      },
      "required": true
    },
    "responses": {
      "200": {
        "description": "Merchant Connector Created",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MerchantConnectorResponse"
            }
          }
        }
      },
      "400": {
        "description": "Missing Mandatory fields"
      }
    },
    "security": [
      {
        "api_key": []
      }
    ]
  },
  "get": {
    "tags": [
      "Merchant Connector Account"
    ],
    "summary": "Merchant Connector - List",
    "description": "List Merchant Connector Details for the merchant",
    "operationId": "List all Merchant Connectors",
    "parameters": [
      {
        "name": "account_id",
        "in": "path",
        "description": "The unique identifier for the merchant account",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    ],
    "responses": {
      "200": {
        "description": "Merchant Connector list retrieved successfully",
        "content": {
          "application/json": {
            "schema": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/MerchantConnectorListResponse"
              }
            }
          }
        }
      },
      "401": {
        "description": "Unauthorized request"
      },
      "404": {
        "description": "Merchant Connector does not exist in records"
      }
    },
    "security": [
      {
        "api_key": []
      }
    ]
  }
}


pub struct Placetopay {
    amount_converter: &'static (dyn AmountConvertor<Output = MinorUnit> + Sync),
}


pub struct PaymentsPostSessionTokensData {
    // amount here would include amount, surcharge_amount and shipping_cost
    pub amount: MinorUnit,
    /// original amount sent by the merchant
    pub order_amount: MinorUnit,
    pub currency: storage_enums::Currency,
    pub capture_method: Option<storage_enums::CaptureMethod>,
    /// Merchant's identifier for the payment/invoice. This will be sent to the connector
    /// if the connector provides support to accept multiple reference ids.
    /// In case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.
    pub merchant_order_reference_id: Option<String>,
    pub shipping_cost: Option<MinorUnit>,
    pub setup_future_usage: Option<storage_enums::FutureUsage>,
    pub router_return_url: Option<String>,
}


/// Panics if `json_payload` array does not contain one `GetAuthEventMetricRequest` element.
    pub async fn get_org_auth_event_metrics(
        state: web::Data<AppState>,
        req: actix_web::HttpRequest,
        json_payload: web::Json<[GetAuthEventMetricRequest; 1]>,
    ) -> impl Responder {
        // safety: This shouldn't panic owing to the data type
        #[allow(clippy::expect_used)]
        let payload = json_payload
            .into_inner()
            .to_vec()
            .pop()
            .expect("Couldn't get GetAuthEventMetricRequest");
        let flow = AnalyticsFlow::GetAuthMetrics;
        Box::pin(api::server_wrap(
            flow,
            state,
            &req,
            payload,
            |state, auth: AuthenticationData, req, _| async move {
                let org_id = auth.merchant_account.get_org_id();
                let auth: AuthInfo = AuthInfo::OrgLevel {
                    org_id: org_id.clone(),
                };
                analytics::auth_events::get_metrics(&state.pool, &auth, req)
                    .await
                    .map(ApplicationResponse::Json)
            },
            auth::auth_type(
                &auth::PlatformOrgAdminAuth {
                    is_admin_auth_allowed: false,
                    organization_id: None,
                },
                &auth::JWTAuth {
                    permission: Permission::OrganizationAnalyticsRead,
                },
                req.headers(),
            ),
            api_locking::LockAction::NotApplicable,
        ))
        .await
    }


pub async fn api_key_revoke() {}


pub struct SiftCard {
    number: cards::CardNumber,
    expiry_month: Secret<String>,
    expiry_year: Secret<String>,
    cvc: Secret<String>,
    complete: bool,
}


impl Hash for PaymentMetricsBucketIdentifier {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.currency.hash(state);
        self.status.map(|i| i.to_string()).hash(state);
        self.connector.hash(state);
        self.auth_type.map(|i| i.to_string()).hash(state);
        self.payment_method.hash(state);
        self.payment_method_type.hash(state);
        self.client_source.hash(state);
        self.client_version.hash(state);
        self.profile_id.hash(state);
        self.card_network.hash(state);
        self.merchant_id.hash(state);
        self.card_last_4.hash(state);
        self.card_issuer.hash(state);
        self.error_reason.hash(state);
        self.routing_approach
            .clone()
            .map(|i| i.to_string())
            .hash(state);
        self.signature_network.hash(state);
        self.is_issuer_regulated.hash(state);
        self.is_debit_routed.hash(state);
        self.time_bucket.hash(state);
    }
}

impl Hash for for PaymentMetricsBucketIdentifier


impl api::RefundExecute for Billwerk {}

impl api::RefundExecute for for Billwerk


pub struct CryptopayRouterData<T> {
    pub amount: StringMajorUnit,
    pub router_data: T,
}


pub struct Bamboraapac {
    amount_converter: &'static (dyn AmountConvertor<Output = MinorUnit> + Sync),
}


pub struct ConnectorAuthTypeAndMetadataValidation<'a> {
    pub connector_name: &'a api_models::enums::Connector,
    pub auth_type: &'a types::ConnectorAuthType,
    pub connector_meta_data: &'a Option<pii::SecretSerdeValue>,
}


pub struct MpgsPaymentsRequest {
    amount: StringMinorUnit,
    card: MpgsCard,
}


pub struct ChargebeeWebhookBody {
    pub content: ChargebeeWebhookContent,
    pub event_type: ChargebeeEventType,
}