// File: crates/router/src/services/authentication/detached.rs
// Module: router
// Public functions: 2
// Public structs: 1

use std::{borrow::Cow, string::ToString};

use actix_web::http::header::HeaderMap;
use common_utils::{
    crypto::VerifySignature,
    id_type::{ApiKeyId, MerchantId},
};
use error_stack::ResultExt;
use hyperswitch_domain_models::errors::api_error_response::ApiErrorResponse;

use crate::core::errors::RouterResult;

const HEADER_AUTH_TYPE: &str = "x-auth-type";
const HEADER_MERCHANT_ID: &str = "x-merchant-id";
const HEADER_KEY_ID: &str = "x-key-id";
const HEADER_CHECKSUM: &str = "x-checksum";

#[derive(Debug)]
pub struct ExtractedPayload {
    pub payload_type: PayloadType,
    pub merchant_id: Option<MerchantId>,
    pub key_id: Option<ApiKeyId>,
}

#[derive(strum::EnumString, strum::Display, PartialEq, Debug)]
#[strum(serialize_all = "snake_case")]
pub enum PayloadType {
    ApiKey,
    PublishableKey,
}

pub trait GetAuthType {
    fn get_auth_type(&self) -> PayloadType;
}

impl ExtractedPayload {
    pub fn from_headers(headers: &HeaderMap) -> RouterResult<Self> {
        let merchant_id = headers
            .get(HEADER_MERCHANT_ID)
            .and_then(|value| value.to_str().ok())
            .ok_or_else(|| ApiErrorResponse::InvalidRequestData {
                message: format!("`{HEADER_MERCHANT_ID}` header is invalid or not present"),
            })
            .map_err(error_stack::Report::from)
            .and_then(|merchant_id| {
                MerchantId::try_from(Cow::from(merchant_id.to_string())).change_context(
                    ApiErrorResponse::InvalidRequestData {
                        message: format!(
                            "`{HEADER_MERCHANT_ID}` header is invalid or not present",

                        ),
                    },
                )
            })?;

        let auth_type: PayloadType = headers
            .get(HEADER_AUTH_TYPE)
            .and_then(|inner| inner.to_str().ok())
            .ok_or_else(|| ApiErrorResponse::InvalidRequestData {
                message: format!("`{HEADER_AUTH_TYPE}` header not present"),
            })?
            .parse::<PayloadType>()
            .change_context(ApiErrorResponse::InvalidRequestData {
                message: format!("`{HEADER_AUTH_TYPE}` header not present"),
            })?;

        let key_id = headers
            .get(HEADER_KEY_ID)
            .and_then(|value| value.to_str().ok())
            .map(|key_id| ApiKeyId::try_from(Cow::from(key_id.to_string())))
            .transpose()
            .change_context(ApiErrorResponse::InvalidRequestData {
                message: format!("`{HEADER_KEY_ID}` header is invalid or not present"),
            })?;

        Ok(Self {
            payload_type: auth_type,
            merchant_id: Some(merchant_id),
            key_id,
        })
    }

    pub fn verify_checksum(
        &self,
        headers: &HeaderMap,
        algo: impl VerifySignature,
        secret: &[u8],
    ) -> bool {
        let output = || {
            let checksum = headers.get(HEADER_CHECKSUM)?.to_str().ok()?;
            let payload = self.generate_payload();

            algo.verify_signature(secret, &hex::decode(checksum).ok()?, payload.as_bytes())
                .ok()
        };

        output().unwrap_or(false)
    }

    // The payload should be `:` separated strings of all the fields
    fn generate_payload(&self) -> String {
        append_option(
            &self.payload_type.to_string(),
            &self
                .merchant_id
                .as_ref()
                .map(|inner| append_api_key(inner.get_string_repr(), &self.key_id)),
        )
    }
}

#[inline]
fn append_option(prefix: &str, data: &Option<String>) -> String {
    match data {
        Some(inner) => format!("{prefix}:{inner}"),
        None => prefix.to_string(),
    }
}

#[inline]
fn append_api_key(prefix: &str, data: &Option<ApiKeyId>) -> String {
    match data {
        Some(inner) => format!("{}:{}", prefix, inner.get_string_repr()),
        None => prefix.to_string(),
    }
}


// Struct: CountryCurrencyFilter
// File: crates/kgraph_utils/src/types.rs
// Module: kgraph_utils
// Implementations: 0

pub struct CountryCurrencyFilter


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

impl Responder


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

pub fn new() -> &'static Self


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

impl ConnectorSpecifications for for Amazonpay


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

pub fn update_payment_method_record(
    state: &SessionState,
    req: pm_api::UpdatePaymentMethodRecord,
    merchant_id: &id_type::MerchantId,
    merchant_context: &merchant_context::MerchantContext,
) -> CustomResult<
    ApplicationResponse<pm_api::PaymentMethodRecordUpdateResponse>,
    errors::ApiErrorResponse,
>


// Struct: PaysafeApplePayBillingContact
// File: crates/hyperswitch_connectors/src/connectors/paysafe/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaysafeApplePayBillingContact


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

impl ConnectorCommon for for Sift


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

impl api::PaymentVoid for for Powertranz


// Module Structure
// File: crates/storage_impl/src/mock_db.rs
// Module: storage_impl

// Public submodules:
pub mod payment_attempt;
pub mod payment_intent;
pub mod payout_attempt;
pub mod payouts;
pub mod redis_conn;


// File: crates/router/src/core/payments/operations/payment_attempt_list.rs
// Module: router
// Public structs: 1

use std::marker::PhantomData;

#[cfg(feature = "v2")]
use api_models::{enums::FrmSuggestion, payments::PaymentAttemptListRequest};
use async_trait::async_trait;
use common_utils::errors::CustomResult;
use router_env::{instrument, tracing};

use super::{BoxedOperation, Domain, GetTracker, Operation, UpdateTracker, ValidateRequest};
use crate::{
    core::{
        errors::{self, RouterResult},
        payments::{self, operations},
    },
    db::errors::StorageErrorExt,
    routes::{app::ReqState, SessionState},
    types::{
        api, domain,
        storage::{self, enums},
    },
};

#[derive(Debug, Clone, Copy)]
pub struct PaymentGetListAttempts;

impl<F: Send + Clone + Sync> Operation<F, PaymentAttemptListRequest> for &PaymentGetListAttempts {
    type Data = payments::PaymentAttemptListData<F>;
    fn to_validate_request(
        &self,
    ) -> RouterResult<&(dyn ValidateRequest<F, PaymentAttemptListRequest, Self::Data> + Send + Sync)>
    {
        Ok(*self)
    }
    fn to_get_tracker(
        &self,
    ) -> RouterResult<&(dyn GetTracker<F, Self::Data, PaymentAttemptListRequest> + Send + Sync)>
    {
        Ok(*self)
    }
    fn to_domain(&self) -> RouterResult<&(dyn Domain<F, PaymentAttemptListRequest, Self::Data>)> {
        Ok(*self)
    }
    fn to_update_tracker(
        &self,
    ) -> RouterResult<&(dyn UpdateTracker<F, Self::Data, PaymentAttemptListRequest> + Send + Sync)>
    {
        Ok(*self)
    }
}

impl<F: Send + Clone + Sync> Operation<F, PaymentAttemptListRequest> for PaymentGetListAttempts {
    type Data = payments::PaymentAttemptListData<F>;
    fn to_validate_request(
        &self,
    ) -> RouterResult<&(dyn ValidateRequest<F, PaymentAttemptListRequest, Self::Data> + Send + Sync)>
    {
        Ok(self)
    }
    fn to_get_tracker(
        &self,
    ) -> RouterResult<&(dyn GetTracker<F, Self::Data, PaymentAttemptListRequest> + Send + Sync)>
    {
        Ok(self)
    }
    fn to_domain(&self) -> RouterResult<&(dyn Domain<F, PaymentAttemptListRequest, Self::Data>)> {
        Ok(self)
    }
    fn to_update_tracker(
        &self,
    ) -> RouterResult<&(dyn UpdateTracker<F, Self::Data, PaymentAttemptListRequest> + Send + Sync)>
    {
        Ok(self)
    }
}

type PaymentAttemptsListOperation<'b, F> =
    BoxedOperation<'b, F, PaymentAttemptListRequest, payments::PaymentAttemptListData<F>>;

#[async_trait]
impl<F: Send + Clone + Sync>
    GetTracker<F, payments::PaymentAttemptListData<F>, PaymentAttemptListRequest>
    for PaymentGetListAttempts
{
    #[instrument(skip_all)]
    async fn get_trackers<'a>(
        &'a self,
        state: &'a SessionState,
        _payment_id: &common_utils::id_type::GlobalPaymentId,
        request: &PaymentAttemptListRequest,
        merchant_context: &domain::MerchantContext,
        _profile: &domain::Profile,
        _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
    ) -> RouterResult<operations::GetTrackerResponse<payments::PaymentAttemptListData<F>>> {
        let db = &*state.store;
        let key_manager_state = &state.into();
        let storage_scheme = merchant_context.get_merchant_account().storage_scheme;
        let payment_attempt_list = db
            .find_payment_attempts_by_payment_intent_id(
                key_manager_state,
                &request.payment_intent_id,
                merchant_context.get_merchant_key_store(),
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

        let payment_data = payments::PaymentAttemptListData {
            flow: PhantomData,
            payment_attempt_list,
        };

        let get_trackers_response = operations::GetTrackerResponse { payment_data };

        Ok(get_trackers_response)
    }
}

#[async_trait]
impl<F: Clone + Sync>
    UpdateTracker<F, payments::PaymentAttemptListData<F>, PaymentAttemptListRequest>
    for PaymentGetListAttempts
{
    #[instrument(skip_all)]
    async fn update_trackers<'b>(
        &'b self,
        _state: &'b SessionState,
        _req_state: ReqState,
        payment_data: payments::PaymentAttemptListData<F>,
        _customer: Option<domain::Customer>,
        _storage_scheme: enums::MerchantStorageScheme,
        _updated_customer: Option<storage::CustomerUpdate>,
        _key_store: &domain::MerchantKeyStore,
        _frm_suggestion: Option<FrmSuggestion>,
        _header_payload: hyperswitch_domain_models::payments::HeaderPayload,
    ) -> RouterResult<(
        PaymentAttemptsListOperation<'b, F>,
        payments::PaymentAttemptListData<F>,
    )>
    where
        F: 'b + Send,
    {
        Ok((Box::new(self), payment_data))
    }
}

impl<F: Send + Clone + Sync>
    ValidateRequest<F, PaymentAttemptListRequest, payments::PaymentAttemptListData<F>>
    for PaymentGetListAttempts
{
    #[instrument(skip_all)]
    fn validate_request<'a, 'b>(
        &'b self,
        _request: &PaymentAttemptListRequest,
        merchant_context: &'a domain::MerchantContext,
    ) -> RouterResult<operations::ValidateResult> {
        Ok(operations::ValidateResult {
            merchant_id: merchant_context.get_merchant_account().get_id().to_owned(),
            storage_scheme: merchant_context.get_merchant_account().storage_scheme,
            requeue: false,
        })
    }
}

#[async_trait]
impl<F: Clone + Send + Sync>
    Domain<F, PaymentAttemptListRequest, payments::PaymentAttemptListData<F>>
    for PaymentGetListAttempts
{
    #[instrument(skip_all)]
    async fn get_customer_details<'a>(
        &'a self,
        _state: &SessionState,
        _payment_data: &mut payments::PaymentAttemptListData<F>,
        _merchant_key_store: &domain::MerchantKeyStore,
        _storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<
        (
            BoxedOperation<'a, F, PaymentAttemptListRequest, payments::PaymentAttemptListData<F>>,
            Option<domain::Customer>,
        ),
        errors::StorageError,
    > {
        Ok((Box::new(self), None))
    }

    #[instrument(skip_all)]
    async fn make_pm_data<'a>(
        &'a self,
        _state: &'a SessionState,
        _payment_data: &mut payments::PaymentAttemptListData<F>,
        _storage_scheme: enums::MerchantStorageScheme,
        _merchant_key_store: &domain::MerchantKeyStore,
        _customer: &Option<domain::Customer>,
        _business_profile: &domain::Profile,
        _should_retry_with_pan: bool,
    ) -> RouterResult<(
        PaymentAttemptsListOperation<'a, F>,
        Option<domain::PaymentMethodData>,
        Option<String>,
    )> {
        Ok((Box::new(self), None, None))
    }

    #[instrument(skip_all)]
    async fn perform_routing<'a>(
        &'a self,
        _merchant_context: &domain::MerchantContext,
        _business_profile: &domain::Profile,
        _state: &SessionState,
        _payment_data: &mut payments::PaymentAttemptListData<F>,
    ) -> CustomResult<api::ConnectorCallType, errors::ApiErrorResponse> {
        Ok(api::ConnectorCallType::Skip)
    }

    #[instrument(skip_all)]
    async fn guard_payment_against_blocklist<'a>(
        &'a self,
        _state: &SessionState,
        _merchant_context: &domain::MerchantContext,
        _payment_data: &mut payments::PaymentAttemptListData<F>,
    ) -> CustomResult<bool, errors::ApiErrorResponse> {
        Ok(false)
    }
}


// Struct: VgsRouterData
// File: crates/hyperswitch_connectors/src/connectors/vgs/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct VgsRouterData<T>


// Struct: PaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/worldline/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaymentsRequest


// Function: payment_link_retrieve
// File: crates/openapi/src/routes/payment_link.rs
// Module: openapi

pub fn payment_link_retrieve()


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

impl TotalEventsResponse


// File: crates/hyperswitch_connectors/src/connectors/nordea/requests.rs
// Module: hyperswitch_connectors
// Public structs: 14

use common_utils::types::StringMajorUnit;
use masking::Secret;
use serde::{Deserialize, Serialize};

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

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct NordeaOAuthRequest {
    /// Country is a mandatory parameter with possible values FI, DK, NO or SE
    pub country: api_models::enums::CountryAlpha2,
    /// Duration of access authorization in minutes. range: 1 to 259200 minutes (180 days).
    /// Duration should be left empty if the request includes PAYMENTS_SINGLE_SCA scope.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub duration: Option<i32>,
    /// Maximum transaction history in months. Optional if ACCOUNTS_TRANSACTIONS scope is requested. Default=2 months. range: 1 to 18 months
    #[serde(rename = "max_tx_history")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub maximum_transaction_history: Option<i32>,
    /// Redirect URI you used when this application was registered with Nordea.
    pub redirect_uri: String,
    pub scope: Vec<AccessScope>,
    /// The OAuth2 state parameter. This is a nonce and should be used to prevent CSRF attacks.
    pub state: Secret<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "snake_case")]
pub enum GrantType {
    AuthorizationCode,
    RefreshToken,
}

// To be passed in query parameters for OAuth scopes
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum AccessScope {
    AccountsBasic,
    AccountsBalances,
    AccountsDetails,
    AccountsTransactions,
    PaymentsMultiple,
    PaymentsSingleSca,
    CardsInformation,
    CardsTransactions,
}

#[derive(Debug, Clone, Serialize)]
pub struct NordeaOAuthExchangeRequest {
    /// authorization_code flow
    #[serde(skip_serializing_if = "Option::is_none")]
    pub code: Option<Secret<String>>,
    pub grant_type: GrantType,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub redirect_uri: Option<String>,
    /// refresh_token flow
    #[serde(skip_serializing_if = "Option::is_none")]
    pub refresh_token: Option<Secret<String>>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum AccountType {
    /// International bank account number
    Iban,
    /// National bank account number of Sweden
    BbanSe,
    /// National bank account number of Denmark
    BbanDk,
    /// National bank account number of Norway
    BbanNo,
    /// Bankgiro number
    Bgnr,
    /// Plusgiro number
    Pgnr,
    /// Creditor number (Giro) Denmark
    GiroDk,
    /// Any bank account number without any check-digit validations
    BbanOther,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct AccountNumber {
    /// Type of account number
    #[serde(rename = "_type")]
    pub account_type: AccountType,
    /// Currency of the account (Mandatory for debtor, Optional for creditor)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub currency: Option<api_models::enums::Currency>,
    /// Actual account number
    pub value: Secret<String>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct CreditorAccountReference {
    /// RF or Invoice for FI Sepa payments, OCR for NO Kid payments and 01, 04, 15, 71, 73 or 75 for Danish Transfer Form payments.
    #[serde(rename = "_type")]
    pub creditor_reference_type: String,
    /// Actual reference number
    #[serde(skip_serializing_if = "Option::is_none")]
    pub value: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct NordeaAddress {
    /// First line of the address. e.g. Street address
    pub line1: Option<Secret<String>>,
    /// Second line of the address (optional). e.g. Postal address
    pub line2: Option<Secret<String>>,
    /// Third line of the address (optional). e.g. Country
    pub line3: Option<Secret<String>>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct CreditorBank {
    /// Address
    pub address: Option<NordeaAddress>,
    /// Bank code
    pub bank_code: Option<String>,
    /// Business identifier code (BIC) of the creditor bank.
    /// This information is required, if the creditor account number is not in IBAN format.
    #[serde(rename = "bic")]
    pub business_identifier_code: Option<Secret<String>>,
    /// Country of the creditor bank. Only ISO 3166 alpha-2 codes are used.
    pub country: api_models::enums::CountryAlpha2,
    /// Name of the creditor bank.
    #[serde(rename = "name")]
    pub bank_name: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct CreditorAccount {
    /// Account number
    pub account: AccountNumber,
    /// Creditor bank information.
    pub bank: Option<CreditorBank>,
    /// Country of the creditor
    pub country: Option<api_models::enums::CountryAlpha2>,
    /// Address
    pub creditor_address: Option<NordeaAddress>,
    /// Message for the creditor to appear on their transaction.
    /// Max length: FI SEPA:140; SE:12; PGNR:25; BGNR:150; DK: 40 (Instant/Express: 140); NO: 140
    #[serde(skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
    /// Name of the creditor.
    /// Max length: FI SEPA: 30; SE: 35; DK: Not use (Mandatory for Instant/Express payments: 70);
    /// NO: 30 (mandatory for Straksbetaling/Express payments).
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<Secret<String>>,
    /// Creditor reference number.
    /// Either Reference or Message has to be passed in the Request
    pub reference: Option<CreditorAccountReference>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct DebitorAccount {
    /// Account number
    pub account: AccountNumber,
    /// Own message to be on the debtor's transaction.
    /// Max length 20. NB: This field is not supported for SEPA and Norwegian payments and will be ignored.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct InstructedAmount {
    /// Monetary amount of the payment. Max (digits+decimals): FI SEPA: (9+2); SE:(11+2); DK:(7+2); NO:(7+2)
    pub amount: StringMajorUnit,
    /// Currency code according to ISO 4217.
    /// NB: Possible value depends on the type of the payment.
    /// For domestic payment it should be same as debtor local currency,
    /// for SEPA it must be EUR,
    /// for cross border it can be Currency code according to ISO 4217.
    pub currency: api_models::enums::Currency,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum RecurrenceType {
    Daily,
    Weekly,
    Biweekly,
    MonthlySameDay,
    MonthlyEom,
    QuartelySameDay,
    QuartelyEom,
    SemiAnnuallySameDay,
    SemiAnnuallyEom,
    TriAnnuallySameDay,
    YearlySameDay,
    YearlyEom,
    EveryMinuteSandboxOnly,
}

#[derive(Debug, Serialize, PartialEq)]
#[serde(rename_all = "snake_case")]
#[allow(dead_code)] // This is an optional field and not having it is fine
pub enum FundsAvailabilityRequest {
    True,
    False,
}

#[derive(Debug, Serialize, PartialEq, Clone)]
pub enum PaymentsUrgency {
    Standard,
    Express,
    Sameday,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct RecurringInformation {
    /// Number of occurrences. Not applicable for NO (use end_date instead). Format: int32.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub count: Option<i32>,
    /// Date on which the recurrence will end. Format: YYYY-MM-DD. Applicable only for Norway. Format: date
    #[serde(skip_serializing_if = "Option::is_none")]
    pub end_date: Option<String>,
    /// Repeats every interval
    #[serde(skip_serializing_if = "Option::is_none")]
    pub recurrence_type: Option<RecurrenceType>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum TppCategory {
    Error,
    Warning,
    Info,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum TppCode {
    Ds0a,
    Narr,
    Am21,
    Am04,
    Tm01,
    Am12,
    Rc06,
    Rc07,
    Rc04,
    Ag06,
    Bg06,
    Be22,
    Be20,
    Ff06,
    Be19,
    Am03,
    Am11,
    Ch04,
    Dt01,
    Ch03,
    Ff08,
    Ac10,
    Ac02,
    Ag08,
    Rr09,
    Rc11,
    Ff10,
    Rr10,
    Ff05,
    Ch15,
    Ff04,
    Ac11,
    Ac03,
    Ac13,
    Ac14,
    Ac05,
    Ac06,
    Rr07,
    Dt03,
    Am13,
    Ds24,
    Fr01,
    Am02,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct ThirdPartyMessages {
    /// Category of the TPP message, INFO is further information, WARNING is something can be fixed, ERROR possibly non fixable issue
    #[serde(skip_serializing_if = "Option::is_none")]
    pub category: Option<TppCategory>,
    /// Additional code that is combined with the text
    #[serde(skip_serializing_if = "Option::is_none")]
    pub code: Option<TppCode>,
    /// Additional explaining text to the TPP
    #[serde(skip_serializing_if = "Option::is_none")]
    pub text: Option<String>,
}

#[derive(Debug, Serialize, PartialEq)]
pub struct NordeaPaymentsRequest {
    /// Creditor of the payment
    #[serde(rename = "creditor")]
    pub creditor_account: CreditorAccount,
    /// Debtor of the payment
    #[serde(rename = "debtor")]
    pub debitor_account: DebitorAccount,
    /// Free text reference that can be provided by the PSU.
    /// This identification is passed on throughout the entire end-to-end chain.
    /// Only in scope for Nordea Business DK.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub end_to_end_identification: Option<String>,
    /// Unique identification as assigned by a partner to identify the payment.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub external_id: Option<String>,
    /// Monetary amount
    pub instructed_amount: InstructedAmount,
    /// Recurring information
    #[serde(skip_serializing_if = "Option::is_none")]
    pub recurring: Option<RecurringInformation>,
    /// Use as an indicator that the supplied payment (amount, currency and debtor account)
    /// should be used to check whether the funds are available for further processing - at this moment.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub request_availability_of_funds: Option<FundsAvailabilityRequest>,
    /// Choose a preferred execution date (or leave blank for today's date).
    /// This should be a valid bank day, and depending on the country the date will either be
    /// pushed to the next valid bank day, or return an error if a non-banking day date was
    /// supplied (all dates accepted in sandbox). SEPA: max +5 years from yesterday,
    /// Domestic: max. +1 year from yesterday. NB: Not supported for Own transfer Non-Recurring Norway.
    /// Format:date.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub requested_execution_date: Option<String>,
    /// Additional messages for third parties
    #[serde(rename = "tpp_messages")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tpp_messages: Option<Vec<ThirdPartyMessages>>,
    /// Urgency of the payment. NB: This field is supported for
    /// DK Domestic ('standard' and 'express')
    /// NO Domestic bank transfer payments ('standard'). Use 'express' for Straksbetaling (Instant payment).
    /// FI Sepa ('standard' and 'express') All other payment types ignore this input.
    /// For further details on urgencies and cut-offs, refer to the Nordea website. Value 'sameday' is marked as deprecated and will be removed in the future.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub urgency: Option<PaymentsUrgency>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum NordeaAuthenticationMethod {
    Mta,
    #[serde(rename = "CCALC (Deprecated)")]
    Ccalc,
    Qrt,
    CardRdr,
    BankidSe,
    QrtSe,
    BankidNo,
    BankidmNo,
    MtaNo,
    #[serde(rename = "NEMID_2F")]
    Nemid2f,
    Mitid,
    MtaDk,
    QrtDk,
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(rename_all = "snake_case")]
pub enum NordeaConfirmLanguage {
    Fi,
    Da,
    Sv,
    En,
    No,
}

#[derive(Debug, Serialize, PartialEq)]
pub struct NordeaPaymentsConfirmRequest {
    /// Authentication method to use for the signing of payment.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub authentication_method: Option<NordeaAuthenticationMethod>,
    /// Language of the signing page that will be displayed to client, ISO639-1 and 639-2, default=en
    #[serde(skip_serializing_if = "Option::is_none")]
    pub language: Option<NordeaConfirmLanguage>,
    pub payments_ids: Vec<String>,
    pub redirect_url: Option<String>,
    pub state: Option<String>,
}


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

impl api::PaymentToken for for Coinbase


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

pub fn get_credentials(
        &self,
    ) -> CustomResult<&PaypalConnectorCredentials, errors::ConnectorError>


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

impl MandateInterface for for KafkaStore


// Function: delete_gsm_rule
// File: crates/router/src/routes/gsm.rs
// Module: router

pub fn delete_gsm_rule(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<gsm_api_types::GsmDeleteRequest>,
) -> impl Responder


// Implementation: impl SdkEventMetricAccumulator for for CountAccumulator
// File: crates/analytics/src/sdk_events/accumulator.rs
// Module: analytics
// Methods: 2 total (0 public)

impl SdkEventMetricAccumulator for for CountAccumulator


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

pub struct RequiredFieldFinal


// Struct: Mifinity
// File: crates/hyperswitch_connectors/src/connectors/mifinity.rs
// Module: hyperswitch_connectors
// Implementations: 17
// 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, ConnectorCommon, ConnectorValidation, IncomingWebhook, ConnectorSpecifications

pub struct Mifinity

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


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

pub struct SaleQuery


// Function: map_notification_to_event_for_payout
// File: crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs
// Module: hyperswitch_connectors

pub fn map_notification_to_event_for_payout(
    status: DmnStatus,
    transaction_type: NuveiTransactionType,
) -> Result<api_models::webhooks::IncomingWebhookEvent, error_stack::Report<errors::ConnectorError>>


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

pub fn retrieve_surcharge_decision_manager_config(
    state: web::Data<AppState>,
    req: HttpRequest,
) -> impl Responder


// Function: backward_conversion
// File: crates/currency_conversion/src/types.rs
// Module: currency_conversion

// Documentation: from base_currency -> to_currency

pub fn backward_conversion(
        &self,
        amt: Decimal,
        to_currency: Currency,
    ) -> Result<Decimal, CurrencyConversionError>


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

impl Responder


// Function: add_two
// File: crates/euclid_wasm/src/lib.rs
// Module: euclid_wasm

pub fn add_two(n1: i64, n2: i64) -> i64


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

impl api::PaymentVoid for for Wellsfargo


// Implementation: impl RequestIdStore for for Store
// File: crates/router/src/db.rs
// Module: router
// Methods: 2 total (0 public)

impl RequestIdStore for for Store


// File: crates/router/src/routes/app.rs
// Module: router
// Public functions: 79
// Public structs: 53

use std::{collections::HashMap, sync::Arc};

use actix_web::{web, Scope};
#[cfg(all(feature = "olap", feature = "v1"))]
use api_models::routing::RoutingRetrieveQuery;
use api_models::routing::RuleMigrationQuery;
#[cfg(feature = "olap")]
use common_enums::TransactionType;
#[cfg(feature = "partial-auth")]
use common_utils::crypto::Blake3;
use common_utils::id_type;
#[cfg(feature = "email")]
use external_services::email::{
    no_email::NoEmailClient, ses::AwsSes, smtp::SmtpServer, EmailClientConfigs, EmailService,
};
#[cfg(all(feature = "revenue_recovery", feature = "v2"))]
use external_services::grpc_client::revenue_recovery::GrpcRecoveryHeaders;
use external_services::{
    file_storage::FileStorageInterface,
    grpc_client::{GrpcClients, GrpcHeaders, GrpcHeadersUcs, GrpcHeadersUcsBuilderInitial},
};
use hyperswitch_interfaces::{
    crm::CrmInterface,
    encryption_interface::EncryptionManagementInterface,
    secrets_interface::secret_state::{RawSecret, SecuredSecret},
};
use router_env::tracing_actix_web::RequestId;
use scheduler::SchedulerInterface;
use storage_impl::{config::TenantConfig, redis::RedisStore, MockDb};
use tokio::sync::oneshot;

use self::settings::Tenant;
#[cfg(any(feature = "olap", feature = "oltp"))]
use super::currency;
#[cfg(feature = "dummy_connector")]
use super::dummy_connector::*;
#[cfg(all(any(feature = "v1", feature = "v2"), feature = "oltp"))]
use super::ephemeral_key::*;
#[cfg(any(feature = "olap", feature = "oltp"))]
use super::payment_methods;
#[cfg(feature = "payouts")]
use super::payout_link::*;
#[cfg(feature = "payouts")]
use super::payouts::*;
#[cfg(all(feature = "oltp", feature = "v1"))]
use super::pm_auth;
#[cfg(feature = "oltp")]
use super::poll;
#[cfg(feature = "v2")]
use super::proxy;
#[cfg(all(feature = "v2", feature = "revenue_recovery", feature = "oltp"))]
use super::recovery_webhooks::*;
#[cfg(all(feature = "oltp", feature = "v2"))]
use super::refunds;
#[cfg(feature = "olap")]
use super::routing;
#[cfg(all(feature = "oltp", feature = "v2"))]
use super::tokenization as tokenization_routes;
#[cfg(all(feature = "olap", any(feature = "v1", feature = "v2")))]
use super::verification::{apple_pay_merchant_registration, retrieve_apple_pay_verified_domains};
#[cfg(feature = "oltp")]
use super::webhooks::*;
use super::{
    admin, api_keys, cache::*, chat, connector_onboarding, disputes, files, gsm, health::*,
    profiles, relay, user, user_role,
};
#[cfg(feature = "v1")]
use super::{
    apple_pay_certificates_migration, blocklist, payment_link, subscription, webhook_events,
};
#[cfg(any(feature = "olap", feature = "oltp"))]
use super::{configs::*, customers, payments};
#[cfg(all(any(feature = "olap", feature = "oltp"), feature = "v1"))]
use super::{mandates::*, refunds::*};
#[cfg(feature = "olap")]
pub use crate::analytics::opensearch::OpenSearchClient;
#[cfg(feature = "olap")]
use crate::analytics::AnalyticsProvider;
#[cfg(feature = "partial-auth")]
use crate::errors::RouterResult;
#[cfg(feature = "oltp")]
use crate::routes::authentication;
#[cfg(feature = "v1")]
use crate::routes::cards_info::{
    card_iin_info, create_cards_info, migrate_cards_info, update_cards_info,
};
#[cfg(all(feature = "olap", feature = "v1"))]
use crate::routes::feature_matrix;
#[cfg(all(feature = "frm", feature = "oltp"))]
use crate::routes::fraud_check as frm_routes;
#[cfg(all(feature = "olap", feature = "v1"))]
use crate::routes::profile_acquirer;
#[cfg(all(feature = "recon", feature = "olap"))]
use crate::routes::recon as recon_routes;
pub use crate::{
    configs::settings,
    db::{
        AccountsStorageInterface, CommonStorageInterface, GlobalStorageInterface, StorageImpl,
        StorageInterface,
    },
    events::EventsHandler,
    services::{get_cache_store, get_store},
};
use crate::{
    configs::{secrets_transformers, Settings},
    db::kafka_store::{KafkaStore, TenantID},
    routes::{hypersense as hypersense_routes, three_ds_decision_rule},
};

#[derive(Clone)]
pub struct ReqState {
    pub event_context: events::EventContext<crate::events::EventType, EventsHandler>,
}

#[derive(Clone)]
pub struct SessionState {
    pub store: Box<dyn StorageInterface>,
    /// Global store is used for global schema operations in tables like Users and Tenants
    pub global_store: Box<dyn GlobalStorageInterface>,
    pub accounts_store: Box<dyn AccountsStorageInterface>,
    pub conf: Arc<settings::Settings<RawSecret>>,
    pub api_client: Box<dyn crate::services::ApiClient>,
    pub event_handler: EventsHandler,
    #[cfg(feature = "email")]
    pub email_client: Arc<Box<dyn EmailService>>,
    #[cfg(feature = "olap")]
    pub pool: AnalyticsProvider,
    pub file_storage_client: Arc<dyn FileStorageInterface>,
    pub request_id: Option<RequestId>,
    pub base_url: String,
    pub tenant: Tenant,
    #[cfg(feature = "olap")]
    pub opensearch_client: Option<Arc<OpenSearchClient>>,
    pub grpc_client: Arc<GrpcClients>,
    pub theme_storage_client: Arc<dyn FileStorageInterface>,
    pub locale: String,
    pub crm_client: Arc<dyn CrmInterface>,
    pub infra_components: Option<serde_json::Value>,
    pub enhancement: Option<HashMap<String, String>>,
}
impl scheduler::SchedulerSessionState for SessionState {
    fn get_db(&self) -> Box<dyn SchedulerInterface> {
        self.store.get_scheduler_db()
    }
}
impl SessionState {
    pub fn get_req_state(&self) -> ReqState {
        ReqState {
            event_context: events::EventContext::new(self.event_handler.clone()),
        }
    }
    pub fn get_grpc_headers(&self) -> GrpcHeaders {
        GrpcHeaders {
            tenant_id: self.tenant.tenant_id.get_string_repr().to_string(),
            request_id: self.request_id.map(|req_id| (*req_id).to_string()),
        }
    }
    pub fn get_grpc_headers_ucs(&self) -> GrpcHeadersUcsBuilderInitial {
        let tenant_id = self.tenant.tenant_id.get_string_repr().to_string();
        GrpcHeadersUcs::builder().tenant_id(tenant_id)
    }
    #[cfg(all(feature = "revenue_recovery", feature = "v2"))]
    pub fn get_recovery_grpc_headers(&self) -> GrpcRecoveryHeaders {
        GrpcRecoveryHeaders {
            request_id: self.request_id.map(|req_id| (*req_id).to_string()),
        }
    }
}

pub trait SessionStateInfo {
    fn conf(&self) -> settings::Settings<RawSecret>;
    fn store(&self) -> Box<dyn StorageInterface>;
    fn event_handler(&self) -> EventsHandler;
    fn get_request_id(&self) -> Option<String>;
    fn add_request_id(&mut self, request_id: RequestId);
    #[cfg(feature = "partial-auth")]
    fn get_detached_auth(&self) -> RouterResult<(Blake3, &[u8])>;
    fn session_state(&self) -> SessionState;
    fn global_store(&self) -> Box<dyn GlobalStorageInterface>;
}

impl SessionStateInfo for SessionState {
    fn store(&self) -> Box<dyn StorageInterface> {
        self.store.to_owned()
    }
    fn conf(&self) -> settings::Settings<RawSecret> {
        self.conf.as_ref().to_owned()
    }
    fn event_handler(&self) -> EventsHandler {
        self.event_handler.clone()
    }
    fn get_request_id(&self) -> Option<String> {
        self.api_client.get_request_id()
    }
    fn add_request_id(&mut self, request_id: RequestId) {
        self.api_client.add_request_id(request_id);
        self.store.add_request_id(request_id.to_string());
        self.request_id.replace(request_id);
    }

    #[cfg(feature = "partial-auth")]
    fn get_detached_auth(&self) -> RouterResult<(Blake3, &[u8])> {
        use error_stack::ResultExt;
        use hyperswitch_domain_models::errors::api_error_response as errors;
        use masking::prelude::PeekInterface as _;
        use router_env::logger;

        let output = CHECKSUM_KEY.get_or_try_init(|| {
            let conf = self.conf();
            let context = conf
                .api_keys
                .get_inner()
                .checksum_auth_context
                .peek()
                .clone();
            let key = conf.api_keys.get_inner().checksum_auth_key.peek();
            hex::decode(key).map(|key| {
                (
                    masking::StrongSecret::new(context),
                    masking::StrongSecret::new(key),
                )
            })
        });

        match output {
            Ok((context, key)) => Ok((Blake3::new(context.peek().clone()), key.peek())),
            Err(err) => {
                logger::error!("Failed to get checksum key");
                Err(err).change_context(errors::ApiErrorResponse::InternalServerError)
            }
        }
    }
    fn session_state(&self) -> SessionState {
        self.clone()
    }
    fn global_store(&self) -> Box<dyn GlobalStorageInterface> {
        self.global_store.to_owned()
    }
}
#[derive(Clone)]
pub struct AppState {
    pub flow_name: String,
    pub global_store: Box<dyn GlobalStorageInterface>,
    // TODO: use a separate schema for accounts_store
    pub accounts_store: HashMap<id_type::TenantId, Box<dyn AccountsStorageInterface>>,
    pub stores: HashMap<id_type::TenantId, Box<dyn StorageInterface>>,
    pub conf: Arc<settings::Settings<RawSecret>>,
    pub event_handler: EventsHandler,
    #[cfg(feature = "email")]
    pub email_client: Arc<Box<dyn EmailService>>,
    pub api_client: Box<dyn crate::services::ApiClient>,
    #[cfg(feature = "olap")]
    pub pools: HashMap<id_type::TenantId, AnalyticsProvider>,
    #[cfg(feature = "olap")]
    pub opensearch_client: Option<Arc<OpenSearchClient>>,
    pub request_id: Option<RequestId>,
    pub file_storage_client: Arc<dyn FileStorageInterface>,
    pub encryption_client: Arc<dyn EncryptionManagementInterface>,
    pub grpc_client: Arc<GrpcClients>,
    pub theme_storage_client: Arc<dyn FileStorageInterface>,
    pub crm_client: Arc<dyn CrmInterface>,
    pub infra_components: Option<serde_json::Value>,
    pub enhancement: Option<HashMap<String, String>>,
}
impl scheduler::SchedulerAppState for AppState {
    fn get_tenants(&self) -> Vec<id_type::TenantId> {
        self.conf.multitenancy.get_tenant_ids()
    }
}
pub trait AppStateInfo {
    fn conf(&self) -> settings::Settings<RawSecret>;
    fn event_handler(&self) -> EventsHandler;
    #[cfg(feature = "email")]
    fn email_client(&self) -> Arc<Box<dyn EmailService>>;
    fn add_request_id(&mut self, request_id: RequestId);
    fn add_flow_name(&mut self, flow_name: String);
    fn get_request_id(&self) -> Option<String>;
}

#[cfg(feature = "partial-auth")]
static CHECKSUM_KEY: once_cell::sync::OnceCell<(
    masking::StrongSecret<String>,
    masking::StrongSecret<Vec<u8>>,
)> = once_cell::sync::OnceCell::new();

impl AppStateInfo for AppState {
    fn conf(&self) -> settings::Settings<RawSecret> {
        self.conf.as_ref().to_owned()
    }
    #[cfg(feature = "email")]
    fn email_client(&self) -> Arc<Box<dyn EmailService>> {
        self.email_client.to_owned()
    }
    fn event_handler(&self) -> EventsHandler {
        self.event_handler.clone()
    }
    fn add_request_id(&mut self, request_id: RequestId) {
        self.api_client.add_request_id(request_id);
        self.request_id.replace(request_id);
    }

    fn add_flow_name(&mut self, flow_name: String) {
        self.api_client.add_flow_name(flow_name);
    }
    fn get_request_id(&self) -> Option<String> {
        self.api_client.get_request_id()
    }
}

impl AsRef<Self> for AppState {
    fn as_ref(&self) -> &Self {
        self
    }
}

#[cfg(feature = "email")]
pub async fn create_email_client(
    settings: &settings::Settings<RawSecret>,
) -> Box<dyn EmailService> {
    match &settings.email.client_config {
        EmailClientConfigs::Ses { aws_ses } => Box::new(
            AwsSes::create(
                &settings.email,
                aws_ses,
                settings.proxy.https_url.to_owned(),
            )
            .await,
        ),
        EmailClientConfigs::Smtp { smtp } => {
            Box::new(SmtpServer::create(&settings.email, smtp.clone()).await)
        }
        EmailClientConfigs::NoEmailClient => Box::new(NoEmailClient::create().await),
    }
}

impl AppState {
    /// # Panics
    ///
    /// Panics if Store can't be created or JWE decryption fails
    pub async fn with_storage(
        conf: settings::Settings<SecuredSecret>,
        storage_impl: StorageImpl,
        shut_down_signal: oneshot::Sender<()>,
        api_client: Box<dyn crate::services::ApiClient>,
    ) -> Self {
        #[allow(clippy::expect_used)]
        let secret_management_client = conf
            .secrets_management
            .get_secret_management_client()
            .await
            .expect("Failed to create secret management client");

        let conf = Box::pin(secrets_transformers::fetch_raw_secrets(
            conf,
            &*secret_management_client,
        ))
        .await;

        #[allow(clippy::expect_used)]
        let encryption_client = conf
            .encryption_management
            .get_encryption_management_client()
            .await
            .expect("Failed to create encryption client");

        Box::pin(async move {
            let testable = storage_impl == StorageImpl::PostgresqlTest;
            #[allow(clippy::expect_used)]
            let event_handler = conf
                .events
                .get_event_handler()
                .await
                .expect("Failed to create event handler");

            #[allow(clippy::expect_used)]
            #[cfg(feature = "olap")]
            let opensearch_client = conf
                .opensearch
                .get_opensearch_client()
                .await
                .expect("Failed to initialize OpenSearch client.")
                .map(Arc::new);

            #[allow(clippy::expect_used)]
            let cache_store = get_cache_store(&conf.clone(), shut_down_signal, testable)
                .await
                .expect("Failed to create store");
            let global_store: Box<dyn GlobalStorageInterface> = Self::get_store_interface(
                &storage_impl,
                &event_handler,
                &conf,
                &conf.multitenancy.global_tenant,
                Arc::clone(&cache_store),
                testable,
            )
            .await
            .get_global_storage_interface();
            #[cfg(feature = "olap")]
            let pools = conf
                .multitenancy
                .tenants
                .get_pools_map(conf.analytics.get_inner())
                .await;
            let stores = conf
                .multitenancy
                .tenants
                .get_store_interface_map(&storage_impl, &conf, Arc::clone(&cache_store), testable)
                .await;
            let accounts_store = conf
                .multitenancy
                .tenants
                .get_accounts_store_interface_map(
                    &storage_impl,
                    &conf,
                    Arc::clone(&cache_store),
                    testable,
                )
                .await;

            #[cfg(feature = "email")]
            let email_client = Arc::new(create_email_client(&conf).await);

            let file_storage_client = conf.file_storage.get_file_storage_client().await;
            let theme_storage_client = conf.theme.storage.get_file_storage_client().await;
            let crm_client = conf.crm.get_crm_client().await;

            let grpc_client = conf.grpc_client.get_grpc_client_interface().await;
            let infra_component_values = Self::process_env_mappings(conf.infra_values.clone());
            let enhancement = conf.enhancement.clone();
            Self {
                flow_name: String::from("default"),
                stores,
                global_store,
                accounts_store,
                conf: Arc::new(conf),
                #[cfg(feature = "email")]
                email_client,
                api_client,
                event_handler,
                #[cfg(feature = "olap")]
                pools,
                #[cfg(feature = "olap")]
                opensearch_client,
                request_id: None,
                file_storage_client,
                encryption_client,
                grpc_client,
                theme_storage_client,
                crm_client,
                infra_components: infra_component_values,
                enhancement,
            }
        })
        .await
    }

    /// # Panics
    ///
    /// Panics if Failed to create store
    pub async fn get_store_interface(
        storage_impl: &StorageImpl,
        event_handler: &EventsHandler,
        conf: &Settings,
        tenant: &dyn TenantConfig,
        cache_store: Arc<RedisStore>,
        testable: bool,
    ) -> Box<dyn CommonStorageInterface> {
        match storage_impl {
            StorageImpl::Postgresql | StorageImpl::PostgresqlTest => match event_handler {
                EventsHandler::Kafka(kafka_client) => Box::new(
                    KafkaStore::new(
                        #[allow(clippy::expect_used)]
                        get_store(&conf.clone(), tenant, Arc::clone(&cache_store), testable)
                            .await
                            .expect("Failed to create store"),
                        kafka_client.clone(),
                        TenantID(tenant.get_tenant_id().get_string_repr().to_owned()),
                        tenant,
                    )
                    .await,
                ),
                EventsHandler::Logs(_) => Box::new(
                    #[allow(clippy::expect_used)]
                    get_store(conf, tenant, Arc::clone(&cache_store), testable)
                        .await
                        .expect("Failed to create store"),
                ),
            },
            #[allow(clippy::expect_used)]
            StorageImpl::Mock => Box::new(
                MockDb::new(&conf.redis)
                    .await
                    .expect("Failed to create mock store"),
            ),
        }
    }

    pub async fn new(
        conf: settings::Settings<SecuredSecret>,
        shut_down_signal: oneshot::Sender<()>,
        api_client: Box<dyn crate::services::ApiClient>,
    ) -> Self {
        Box::pin(Self::with_storage(
            conf,
            StorageImpl::Postgresql,
            shut_down_signal,
            api_client,
        ))
        .await
    }

    pub fn get_session_state<E, F>(
        self: Arc<Self>,
        tenant: &id_type::TenantId,
        locale: Option<String>,
        err: F,
    ) -> Result<SessionState, E>
    where
        F: FnOnce() -> E + Copy,
    {
        let tenant_conf = self.conf.multitenancy.get_tenant(tenant).ok_or_else(err)?;
        let mut event_handler = self.event_handler.clone();
        event_handler.add_tenant(tenant_conf);
        let store = self.stores.get(tenant).ok_or_else(err)?.clone();
        Ok(SessionState {
            store,
            global_store: self.global_store.clone(),
            accounts_store: self.accounts_store.get(tenant).ok_or_else(err)?.clone(),
            conf: Arc::clone(&self.conf),
            api_client: self.api_client.clone(),
            event_handler,
            #[cfg(feature = "olap")]
            pool: self.pools.get(tenant).ok_or_else(err)?.clone(),
            file_storage_client: self.file_storage_client.clone(),
            request_id: self.request_id,
            base_url: tenant_conf.base_url.clone(),
            tenant: tenant_conf.clone(),
            #[cfg(feature = "email")]
            email_client: Arc::clone(&self.email_client),
            #[cfg(feature = "olap")]
            opensearch_client: self.opensearch_client.clone(),
            grpc_client: Arc::clone(&self.grpc_client),
            theme_storage_client: self.theme_storage_client.clone(),
            locale: locale.unwrap_or(common_utils::consts::DEFAULT_LOCALE.to_string()),
            crm_client: self.crm_client.clone(),
            infra_components: self.infra_components.clone(),
            enhancement: self.enhancement.clone(),
        })
    }

    pub fn process_env_mappings(
        mappings: Option<HashMap<String, String>>,
    ) -> Option<serde_json::Value> {
        let result: HashMap<String, String> = mappings?
            .into_iter()
            .filter_map(|(key, env_var)| std::env::var(&env_var).ok().map(|value| (key, value)))
            .collect();

        if result.is_empty() {
            None
        } else {
            Some(serde_json::Value::Object(
                result
                    .into_iter()
                    .map(|(k, v)| (k, serde_json::Value::String(v)))
                    .collect(),
            ))
        }
    }
}

pub struct Health;

#[cfg(feature = "v1")]
impl Health {
    pub fn server(state: AppState) -> Scope {
        web::scope("health")
            .app_data(web::Data::new(state))
            .service(web::resource("").route(web::get().to(health)))
            .service(web::resource("/ready").route(web::get().to(deep_health_check)))
    }
}

#[cfg(feature = "v2")]
impl Health {
    pub fn server(state: AppState) -> Scope {
        web::scope("/v2/health")
            .app_data(web::Data::new(state))
            .service(web::resource("").route(web::get().to(health)))
            .service(web::resource("/ready").route(web::get().to(deep_health_check)))
    }
}

#[cfg(feature = "dummy_connector")]
pub struct DummyConnector;

#[cfg(all(feature = "dummy_connector", feature = "v1"))]
impl DummyConnector {
    pub fn server(state: AppState) -> Scope {
        let mut routes_with_restricted_access = web::scope("");
        #[cfg(not(feature = "external_access_dc"))]
        {
            routes_with_restricted_access =
                routes_with_restricted_access.guard(actix_web::guard::Host("localhost"));
        }
        routes_with_restricted_access = routes_with_restricted_access
            .service(web::resource("/payment").route(web::post().to(dummy_connector_payment)))
            .service(
                web::resource("/payments/{payment_id}")
                    .route(web::get().to(dummy_connector_payment_data)),
            )
            .service(
                web::resource("/{payment_id}/refund").route(web::post().to(dummy_connector_refund)),
            )
            .service(
                web::resource("/refunds/{refund_id}")
                    .route(web::get().to(dummy_connector_refund_data)),
            );
        web::scope("/dummy-connector")
            .app_data(web::Data::new(state))
            .service(
                web::resource("/authorize/{attempt_id}")
                    .route(web::get().to(dummy_connector_authorize_payment)),
            )
            .service(
                web::resource("/complete/{attempt_id}")
                    .route(web::get().to(dummy_connector_complete_payment)),
            )
            .service(routes_with_restricted_access)
    }
}

#[cfg(all(feature = "dummy_connector", feature = "v2"))]
impl DummyConnector {
    pub fn server(state: AppState) -> Scope {
        let mut routes_with_restricted_access = web::scope("");
        #[cfg(not(feature = "external_access_dc"))]
        {
            routes_with_restricted_access =
                routes_with_restricted_access.guard(actix_web::guard::Host("localhost"));
        }
        routes_with_restricted_access = routes_with_restricted_access
            .service(web::resource("/payment").route(web::post().to(dummy_connector_payment)));
        web::scope("/dummy-connector")
            .app_data(web::Data::new(state))
            .service(routes_with_restricted_access)
    }
}
pub struct Payments;

#[cfg(all(any(feature = "olap", feature = "oltp"), feature = "v2"))]
impl Payments {
    pub fn server(state: AppState) -> Scope {
        let mut route = web::scope("/v2/payments").app_data(web::Data::new(state));
        route = route
            .service(
                web::resource("/create-intent")
                    .route(web::post().to(payments::payments_create_intent)),
            )
            .service(web::resource("/filter").route(web::get().to(payments::get_payment_filters)))
            .service(
                web::resource("/profile/filter")
                    .route(web::get().to(payments::get_payment_filters_profile)),
            )
            .service(
                web::resource("")
                    .route(web::post().to(payments::payments_create_and_confirm_intent)),
            )
            .service(web::resource("/list").route(web::get().to(payments::payments_list)))
            .service(
                web::resource("/aggregate").route(web::get().to(payments::get_payments_aggregates)),
            )
            .service(
                web::resource("/recovery")
                    .route(web::post().to(payments::recovery_payments_create)),
            )
            .service(
                web::resource("/profile/aggregate")
                    .route(web::get().to(payments::get_payments_aggregates_profile)),
            );

        route =
            route
                .service(web::resource("/ref/{merchant_reference_id}").route(
                    web::get().to(payments::payment_get_intent_using_merchant_reference_id),
                ));

        route = route.service(
            web::scope("/{payment_id}")
                .service(
                    web::resource("/confirm-intent")
                        .route(web::post().to(payments::payment_confirm_intent)),
                )
                // TODO: Deprecated. Remove this in favour of /list-attempts
                .service(
                    web::resource("/list_attempts")
                        .route(web::get().to(payments::list_payment_attempts)),
                )
                .service(
                    web::resource("/list-attempts")
                        .route(web::get().to(payments::list_payment_attempts)),
                )
                .service(
                    web::resource("/proxy-confirm-intent")
                        .route(web::post().to(payments::proxy_confirm_intent)),
                )
                .service(
                    web::resource("/confirm-intent/external-vault-proxy")
                        .route(web::post().to(payments::confirm_intent_with_external_vault_proxy)),
                )
                .service(
                    web::resource("/get-intent")
                        .route(web::get().to(payments::payments_get_intent)),
                )
                .service(
                    web::resource("/update-intent")
                        .route(web::put().to(payments::payments_update_intent)),
                )
                .service(
                    web::resource("/create-external-sdk-tokens")
                        .route(web::post().to(payments::payments_connector_session)),
                )
                .service(
                    web::resource("")
                        .route(web::get().to(payments::payment_status))
                        .route(web::post().to(payments::payments_status_with_gateway_creds)),
                )
                .service(
                    web::resource("/start-redirection")
                        .route(web::get().to(payments::payments_start_redirection)),
                )
                .service(
                    web::resource("/payment-methods")
                        .route(web::get().to(payments::list_payment_methods)),
                )
                .service(
                    web::resource("/finish-redirection/{publishable_key}/{profile_id}")
                        .route(web::get().to(payments::payments_finish_redirection)),
                )
                .service(
                    web::resource("/capture").route(web::post().to(payments::payments_capture)),
                )
                .service(
                    web::resource("/check-gift-card-balance")
                        .route(web::post().to(payments::payment_check_gift_card_balance)),
                )
                .service(web::resource("/cancel").route(web::post().to(payments::payments_cancel))),
        );

        route
    }
}

pub struct Relay;

#[cfg(feature = "oltp")]
impl Relay {
    pub fn server(state: AppState) -> Scope {
        web::scope("/relay")
            .app_data(web::Data::new(state))
            .service(web::resource("").route(web::post().to(relay::relay)))
            .service(web::resource("/{relay_id}").route(web::get().to(relay::relay_retrieve)))
    }
}

#[cfg(feature = "v2")]
pub struct Proxy;

#[cfg(all(feature = "oltp", feature = "v2"))]
impl Proxy {
    pub fn server(state: AppState) -> Scope {
        web::scope("/v2/proxy")
            .app_data(web::Data::new(state))
            .service(web::resource("").route(web::post().to(proxy::proxy)))
    }
}

#[cfg(feature = "v1")]
impl Payments {
    pub fn server(state: AppState) -> Scope {
        let mut route = web::scope("/payments").app_data(web::Data::new(state));

        #[cfg(feature = "olap")]
        {
            route = route
                .service(
                    web::resource("/list")
                        .route(web::get().to(payments::payments_list))
                        .route(web::post().to(payments::payments_list_by_filter)),
                )
                .service(
                    web::resource("/profile/list")
                        .route(web::get().to(payments::profile_payments_list))
                        .route(web::post().to(payments::profile_payments_list_by_filter)),
                )
                .service(
                    web::resource("/filter")
                        .route(web::post().to(payments::get_filters_for_payments)),
                )
                .service(
                    web::resource("/v2/filter").route(web::get().to(payments::get_payment_filters)),
                )
                .service(
                    web::resource("/aggregate")
                        .route(web::get().to(payments::get_payments_aggregates)),
                )
                .service(
                    web::resource("/profile/aggregate")
                        .route(web::get().to(payments::get_payments_aggregates_profile)),
                )
                .service(
                    web::resource("/v2/profile/filter")
                        .route(web::get().to(payments::get_payment_filters_profile)),
                )
                .service(
                    web::resource("/{payment_id}/manual-update")
                        .route(web::put().to(payments::payments_manual_update)),
                )
        }
        #[cfg(feature = "oltp")]
        {
            route = route
                .service(web::resource("").route(web::post().to(payments::payments_create)))
                .service(
                    web::resource("/session_tokens")
                        .route(web::post().to(payments::payments_connector_session)),
                )
                .service(
                    web::resource("/sync")
                        .route(web::post().to(payments::payments_retrieve_with_gateway_creds)),
                )
                .service(
                    web::resource("/{payment_id}")
                        .route(web::get().to(payments::payments_retrieve))
                        .route(web::post().to(payments::payments_update)),
                )
                .service(
                    web::resource("/{payment_id}/post_session_tokens").route(web::post().to(payments::payments_post_session_tokens)),
                )
                .service(
                    web::resource("/{payment_id}/confirm").route(web::post().to(payments::payments_confirm)),
                )
                .service(
                    web::resource("/{payment_id}/cancel").route(web::post().to(payments::payments_cancel)),
                )
                .service(
                    web::resource("/{payment_id}/cancel_post_capture").route(web::post().to(payments::payments_cancel_post_capture)),
                )
                .service(
                    web::resource("/{payment_id}/capture").route(web::post().to(payments::payments_capture)),
                )
                .service(
                    web::resource("/{payment_id}/approve")
                        .route(web::post().to(payments::payments_approve)),
                )
                .service(
                    web::resource("/{payment_id}/reject")
                        .route(web::post().to(payments::payments_reject)),
                )
                .service(
                    web::resource("/redirect/{payment_id}/{merchant_id}/{attempt_id}")
                        .route(web::get().to(payments::payments_start)),
                )
                .service(
                    web::resource(
                        "/{payment_id}/{merchant_id}/redirect/response/{connector}/{creds_identifier}",
                    )
                    .route(web::get().to(payments::payments_redirect_response_with_creds_identifier)),
                )
                .service(
                    web::resource("/{payment_id}/{merchant_id}/redirect/response/{connector}")
                        .route(web::get().to(payments::payments_redirect_response))
                        .route(web::post().to(payments::payments_redirect_response))
                )
                .service(
                    web::resource("/{payment_id}/{merchant_id}/redirect/complete/{connector}/{creds_identifier}")
                        .route(web::get().to(payments::payments_complete_authorize_redirect_with_creds_identifier))
                        .route(web::post().to(payments::payments_complete_authorize_redirect_with_creds_identifier))
                )
                .service(
                    web::resource("/{payment_id}/{merchant_id}/redirect/complete/{connector}")
                        .route(web::get().to(payments::payments_complete_authorize_redirect))
                        .route(web::post().to(payments::payments_complete_authorize_redirect)),
                )
                .service(
                    web::resource("/{payment_id}/complete_authorize")
                        .route(web::post().to(payments::payments_complete_authorize)),
                )
                .service(
                    web::resource("/{payment_id}/incremental_authorization").route(web::post().to(payments::payments_incremental_authorization)),
                )
                .service(
                    web::resource("/{payment_id}/{merchant_id}/authorize/{connector}")
                        .route(web::post().to(payments::post_3ds_payments_authorize))
                        .route(web::get().to(payments::post_3ds_payments_authorize))
                )
                .service(
                    web::resource("/{payment_id}/3ds/authentication").route(web::post().to(payments::payments_external_authentication)),
                )
                .service(
                    web::resource("/{payment_id}/extended_card_info").route(web::get().to(payments::retrieve_extended_card_info)),
                )
                .service(
                web::resource("{payment_id}/calculate_tax")
                    .route(web::post().to(payments::payments_dynamic_tax_calculation)),
                )
                .service(
                    web::resource("{payment_id}/update_metadata")
                        .route(web::post().to(payments::payments_update_metadata)),
                );
        }
        route
    }
}

#[cfg(any(feature = "olap", feature = "oltp"))]
pub struct Forex;

#[cfg(all(any(feature = "olap", feature = "oltp"), feature = "v1"))]
impl Forex {
    pub fn server(state: AppState) -> Scope {
        web::scope("/forex")
            .app_data(web::Data::new(state.clone()))
            .app_data(web::Data::new(state.clone()))
            .service(web::resource("/rates").route(web::get().to(currency::retrieve_forex)))
            .service(
                web::resource("/convert_from_minor").route(web::get().to(currency::convert_forex)),
            )
    }
}

#[cfg(feature = "olap")]
pub struct Routing;

#[cfg(all(feature = "olap", feature = "v2"))]
impl Routing {
    pub fn server(state: AppState) -> Scope {
        web::scope("/v2/routing-algorithms")
            .app_data(web::Data::new(state.clone()))
            .service(
                web::resource("").route(web::post().to(|state, req, payload| {
                    routing::routing_create_config(state, req, payload, TransactionType::Payment)
                })),
            )
            .service(
                web::resource("/{algorithm_id}")
                    .route(web::get().to(routing::routing_retrieve_config)),
            )
    }
}
#[cfg(all(feature = "olap", feature = "v1"))]
impl Routing {
    pub fn server(state: AppState) -> Scope {
        #[allow(unused_mut)]
        let mut route = web::scope("/routing")
            .app_data(web::Data::new(state.clone()))
            .service(
                web::resource("/active").route(web::get().to(|state, req, query_params| {
                    routing::routing_retrieve_linked_config(state, req, query_params, None)
                })),
            )
            .service(
                web::resource("")
                    .route(
                        web::get().to(|state, req, path: web::Query<RoutingRetrieveQuery>| {
                            routing::list_routing_configs(state, req, path, None)
                        }),
                    )
                    .route(web::post().to(|state, req, payload| {
                        routing::routing_create_config(state, req, payload, None)
                    })),
            )
            .service(web::resource("/list/profile").route(web::get().to(
                |state, req, query: web::Query<RoutingRetrieveQuery>| {
                    routing::list_routing_configs_for_profile(state, req, query, None)
                },
            )))
            .service(
                web::resource("/default").route(web::post().to(|state, req, payload| {
                    routing::routing_update_default_config(
                        state,
                        req,
                        payload,
                        &TransactionType::Payment,


// Function: get_cache_store
// File: crates/router/src/services.rs
// Module: router

pub fn get_cache_store(
    config: &Settings,
    shut_down_signal: oneshot::Sender<()


// Trait: SdkEventMetricAnalytics
// File: crates/analytics/src/sdk_events/metrics.rs
// Module: analytics

pub trait SdkEventMetricAnalytics: LoadRow<SdkEventMetricRow>


// Function: get_connector_payment_id
// File: crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
// Module: hyperswitch_domain_models

pub fn get_connector_payment_id(&self) -> Option<&str>


// Struct: AuthenticationResponse
// File: crates/api_models/src/authentication.rs
// Module: api_models
// Implementations: 1
// Traits: ApiEventMetric

pub struct AuthenticationResponse


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

impl Responder


// Struct: PaytmPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/paytm/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct PaytmPaymentsRequest


// Function: update_by_org_id
// File: crates/diesel_models/src/query/organization.rs
// Module: diesel_models

pub fn update_by_org_id(
        conn: &PgPooledConn,
        org_id: id_type::OrganizationId,
        update: OrganizationUpdate,
    ) -> StorageResult<Self>


// Function: perform_calculate_workflow
// File: crates/router/src/core/revenue_recovery.rs
// Module: router

pub fn perform_calculate_workflow(
    state: &SessionState,
    process: &storage::ProcessTracker,
    profile: &domain::Profile,
    merchant_context: domain::MerchantContext,
    tracking_data: &pcr::RevenueRecoveryWorkflowTrackingData,
    revenue_recovery_payment_data: &pcr::RevenueRecoveryPaymentData,
    payment_intent: &PaymentIntent,
) -> Result<(), sch_errors::ProcessTrackerError>


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

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

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

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

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

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

static CONNECTOR: ThunesTest = ThunesTest {};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// Cards Negative scenarios
// Creates a payment with incorrect CVC.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_cvc() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: types::api::PaymentMethodData::Card(api::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: api::PaymentMethodData::Card(api::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: api::PaymentMethodData::Card(api::Card {
                    card_exp_year: Secret::new("2000".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration year is invalid.".to_string(),
    );
}

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

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

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

// Connector dependent test cases goes here

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


// Function: new
// File: crates/router/src/types/domain/user.rs
// Module: router

pub fn new(merchant_id: String) -> UserResult<Self>


// Struct: PoFulfill
// File: crates/hyperswitch_domain_models/src/router_flow_types/payouts.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct PoFulfill