// File: crates/router/src/consts.rs
// Module: router

pub mod opensearch;
#[cfg(feature = "olap")]
pub mod user;
pub mod user_role;
use std::{collections::HashSet, str::FromStr, sync};

use api_models::enums::Country;
use common_utils::{consts, id_type};
pub use hyperswitch_domain_models::consts::{
    CONNECTOR_MANDATE_REQUEST_REFERENCE_ID_LENGTH, ROUTING_ENABLED_PAYMENT_METHODS,
    ROUTING_ENABLED_PAYMENT_METHOD_TYPES,
};
pub use hyperswitch_interfaces::consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE};

// ID generation
pub(crate) const ID_LENGTH: usize = 20;
pub(crate) const MAX_ID_LENGTH: usize = 64;
#[rustfmt::skip]
pub(crate) const ALPHABETS: [char; 62] = [
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
];
/// API client request timeout (in seconds)
pub const REQUEST_TIME_OUT: u64 = 30;
pub const REQUEST_TIMEOUT_ERROR_CODE: &str = "TIMEOUT";
pub const REQUEST_TIMEOUT_ERROR_MESSAGE: &str = "Connector did not respond in specified time";
pub const REQUEST_TIMEOUT_PAYMENT_NOT_FOUND: &str = "Timed out ,payment not found";
pub const REQUEST_TIMEOUT_ERROR_MESSAGE_FROM_PSYNC: &str =
    "This Payment has been moved to failed as there is no response from the connector";

///Payment intent fulfillment default timeout (in seconds)
pub const DEFAULT_FULFILLMENT_TIME: i64 = 15 * 60;

/// Payment intent default client secret expiry (in seconds)
pub const DEFAULT_SESSION_EXPIRY: i64 = 15 * 60;

/// The length of a merchant fingerprint secret
pub const FINGERPRINT_SECRET_LENGTH: usize = 64;

pub const DEFAULT_LIST_API_LIMIT: u16 = 10;

// String literals
pub(crate) const UNSUPPORTED_ERROR_MESSAGE: &str = "Unsupported response type";

// General purpose base64 engines

pub(crate) const BASE64_ENGINE: base64::engine::GeneralPurpose = consts::BASE64_ENGINE;

pub(crate) const API_KEY_LENGTH: usize = 64;

// OID (Object Identifier) for the merchant ID field extension.
pub(crate) const MERCHANT_ID_FIELD_EXTENSION_ID: &str = "1.2.840.113635.100.6.32";

pub const MAX_ROUTING_CONFIGS_PER_MERCHANT: usize = 100;
pub const ROUTING_CONFIG_ID_LENGTH: usize = 10;

pub const LOCKER_REDIS_PREFIX: &str = "LOCKER_PM_TOKEN";
pub const LOCKER_REDIS_EXPIRY_SECONDS: u32 = 60 * 15; // 15 minutes

pub const JWT_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24 * 2; // 2 days

// This should be one day, but it is causing issue while checking token in blacklist.
// TODO: This should be fixed in future.
pub const SINGLE_PURPOSE_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24 * 2; // 2 days

pub const JWT_TOKEN_COOKIE_NAME: &str = "login_token";

pub const USER_BLACKLIST_PREFIX: &str = "BU_";

pub const ROLE_BLACKLIST_PREFIX: &str = "BR_";

#[cfg(feature = "email")]
pub const EMAIL_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24; // 1 day

#[cfg(feature = "email")]
pub const EMAIL_TOKEN_BLACKLIST_PREFIX: &str = "BET_";

pub const EMAIL_SUBJECT_API_KEY_EXPIRY: &str = "API Key Expiry Notice";
pub const EMAIL_SUBJECT_DASHBOARD_FEATURE_REQUEST: &str = "Dashboard Pro Feature Request by";
pub const EMAIL_SUBJECT_APPROVAL_RECON_REQUEST: &str =
    "Approval of Recon Request - Access Granted to Recon Dashboard";

pub const ROLE_INFO_CACHE_PREFIX: &str = "CR_INFO_";

pub const CARD_IP_BLOCKING_CACHE_KEY_PREFIX: &str = "CARD_IP_BLOCKING";

pub const GUEST_USER_CARD_BLOCKING_CACHE_KEY_PREFIX: &str = "GUEST_USER_CARD_BLOCKING";

pub const CUSTOMER_ID_BLOCKING_PREFIX: &str = "CUSTOMER_ID_BLOCKING";

#[cfg(feature = "olap")]
pub const VERIFY_CONNECTOR_ID_PREFIX: &str = "conn_verify";
#[cfg(feature = "olap")]
pub const VERIFY_CONNECTOR_MERCHANT_ID: &str = "test_merchant";

#[cfg(feature = "olap")]
pub const CONNECTOR_ONBOARDING_CONFIG_PREFIX: &str = "onboarding";

/// Max payment session expiry
pub const MAX_SESSION_EXPIRY: u32 = 7890000;

/// Min payment session expiry
pub const MIN_SESSION_EXPIRY: u32 = 60;

/// Max payment intent fulfillment expiry
pub const MAX_INTENT_FULFILLMENT_EXPIRY: u32 = 1800;

/// Min payment intent fulfillment expiry
pub const MIN_INTENT_FULFILLMENT_EXPIRY: u32 = 60;

pub const LOCKER_HEALTH_CALL_PATH: &str = "/health";

pub const AUTHENTICATION_ID_PREFIX: &str = "authn";

// URL for checking the outgoing call
pub const OUTGOING_CALL_URL: &str = "https://api.stripe.com/healthcheck";

// 15 minutes = 900 seconds
pub const POLL_ID_TTL: i64 = 900;

// Default Poll Config
pub const DEFAULT_POLL_DELAY_IN_SECS: i8 = 2;
pub const DEFAULT_POLL_FREQUENCY: i8 = 5;

// Number of seconds to subtract from access token expiry
pub(crate) const REDUCE_ACCESS_TOKEN_EXPIRY_TIME: u8 = 15;
pub const CONNECTOR_CREDS_TOKEN_TTL: i64 = 900;

//max_amount allowed is 999999999 in minor units
pub const MAX_ALLOWED_AMOUNT: i64 = 999999999;

//payment attempt default unified error code and unified error message
pub const DEFAULT_UNIFIED_ERROR_CODE: &str = "UE_9000";
pub const DEFAULT_UNIFIED_ERROR_MESSAGE: &str = "Something went wrong";

// Recon's feature tag
pub const RECON_FEATURE_TAG: &str = "RECONCILIATION AND SETTLEMENT";

/// Default allowed domains for payment links
pub const DEFAULT_ALLOWED_DOMAINS: Option<HashSet<String>> = None;

/// Default hide card nickname field
pub const DEFAULT_HIDE_CARD_NICKNAME_FIELD: bool = false;

/// Show card form by default for payment links
pub const DEFAULT_SHOW_CARD_FORM: bool = true;

/// Default bool for Display sdk only
pub const DEFAULT_DISPLAY_SDK_ONLY: bool = false;

/// Default bool to enable saved payment method
pub const DEFAULT_ENABLE_SAVED_PAYMENT_METHOD: bool = false;

/// [PaymentLink] Default bool for enabling button only when form is ready
pub const DEFAULT_ENABLE_BUTTON_ONLY_ON_FORM_READY: bool = false;

/// Default Merchant Logo Link
pub const DEFAULT_MERCHANT_LOGO: &str =
    "https://live.hyperswitch.io/payment-link-assets/Merchant_placeholder.png";

/// Default Payment Link Background color
pub const DEFAULT_BACKGROUND_COLOR: &str = "#212E46";

/// Default product Img Link
pub const DEFAULT_PRODUCT_IMG: &str =
    "https://live.hyperswitch.io/payment-link-assets/cart_placeholder.png";

/// Default SDK Layout
pub const DEFAULT_SDK_LAYOUT: &str = "tabs";

/// Vault Add request url
#[cfg(feature = "v2")]
pub const ADD_VAULT_REQUEST_URL: &str = "/api/v2/vault/add";

/// Vault Get Fingerprint request url
#[cfg(feature = "v2")]
pub const VAULT_FINGERPRINT_REQUEST_URL: &str = "/api/v2/vault/fingerprint";

/// Vault Retrieve request url
#[cfg(feature = "v2")]
pub const VAULT_RETRIEVE_REQUEST_URL: &str = "/api/v2/vault/retrieve";

/// Vault Delete request url
#[cfg(feature = "v2")]
pub const VAULT_DELETE_REQUEST_URL: &str = "/api/v2/vault/delete";

/// Vault Header content type
#[cfg(feature = "v2")]
pub const VAULT_HEADER_CONTENT_TYPE: &str = "application/json";

/// Vault Add flow type
#[cfg(feature = "v2")]
pub const VAULT_ADD_FLOW_TYPE: &str = "add_to_vault";

/// Vault Retrieve flow type
#[cfg(feature = "v2")]
pub const VAULT_RETRIEVE_FLOW_TYPE: &str = "retrieve_from_vault";

/// Vault Delete flow type
#[cfg(feature = "v2")]
pub const VAULT_DELETE_FLOW_TYPE: &str = "delete_from_vault";

/// Vault Fingerprint fetch flow type
#[cfg(feature = "v2")]
pub const VAULT_GET_FINGERPRINT_FLOW_TYPE: &str = "get_fingerprint_vault";

/// Max volume split for Dynamic routing
pub const DYNAMIC_ROUTING_MAX_VOLUME: u8 = 100;

/// Click To Pay
pub const CLICK_TO_PAY: &str = "click_to_pay";

/// Merchant eligible for authentication service config
pub const AUTHENTICATION_SERVICE_ELIGIBLE_CONFIG: &str =
    "merchants_eligible_for_authentication_service";

/// Refund flow identifier used for performing GSM operations
pub const REFUND_FLOW_STR: &str = "refund_flow";

/// Minimum IBAN length (country-dependent), as per ISO 13616 standard
pub const IBAN_MIN_LENGTH: usize = 15;

/// Maximum IBAN length defined by the ISO 13616 standard (standard max)
pub const IBAN_MAX_LENGTH: usize = 34;

/// Minimum UK BACS account number length in digits
pub const BACS_MIN_ACCOUNT_NUMBER_LENGTH: usize = 6;

/// Maximum UK BACS account number length in digits
pub const BACS_MAX_ACCOUNT_NUMBER_LENGTH: usize = 8;

/// Fixed length of UK BACS sort code in digits (always 6)
pub const BACS_SORT_CODE_LENGTH: usize = 6;

/// Exact length of Polish Elixir system domestic account number (NRB) in digits
pub const ELIXIR_ACCOUNT_NUMBER_LENGTH: usize = 26;

/// Total length of Polish IBAN including country code and checksum (28 characters)
pub const ELIXIR_IBAN_LENGTH: usize = 28;

/// Minimum length of Swedish Bankgiro number in digits
pub const BANKGIRO_MIN_LENGTH: usize = 7;

/// Maximum length of Swedish Bankgiro number in digits
pub const BANKGIRO_MAX_LENGTH: usize = 8;

/// Minimum length of Swedish Plusgiro number in digits
pub const PLUSGIRO_MIN_LENGTH: usize = 2;

/// Maximum length of Swedish Plusgiro number in digits
pub const PLUSGIRO_MAX_LENGTH: usize = 8;

/// Default payment method session expiry
pub const DEFAULT_PAYMENT_METHOD_SESSION_EXPIRY: u32 = 15 * 60; // 15 minutes

/// Authorize flow identifier used for performing GSM operations
pub const AUTHORIZE_FLOW_STR: &str = "Authorize";

/// Protocol Version for encrypted Google Pay Token
pub(crate) const PROTOCOL: &str = "ECv2";

/// Sender ID for Google Pay Decryption
pub(crate) const SENDER_ID: &[u8] = b"Google";

/// Default value for the number of attempts to retry fetching forex rates
pub const DEFAULT_ANALYTICS_FOREX_RETRY_ATTEMPTS: u64 = 3;

/// Default payment intent id
pub const IRRELEVANT_PAYMENT_INTENT_ID: &str = "irrelevant_payment_intent_id";

/// Default payment attempt id
pub const IRRELEVANT_PAYMENT_ATTEMPT_ID: &str = "irrelevant_payment_attempt_id";

pub static PROFILE_ID_UNAVAILABLE: sync::LazyLock<id_type::ProfileId> = sync::LazyLock::new(|| {
    #[allow(clippy::expect_used)]
    id_type::ProfileId::from_str("PROFILE_ID_UNAVAIABLE")
        .expect("Failed to parse PROFILE_ID_UNAVAIABLE")
});

/// Default payment attempt id
pub const IRRELEVANT_CONNECTOR_REQUEST_REFERENCE_ID: &str =
    "irrelevant_connector_request_reference_id";

// Default payment method storing TTL in redis in seconds
pub const DEFAULT_PAYMENT_METHOD_STORE_TTL: i64 = 86400; // 1 day

// List of countries that are part of the PSD2 region
pub const PSD2_COUNTRIES: [Country; 27] = [
    Country::Austria,
    Country::Belgium,
    Country::Bulgaria,
    Country::Croatia,
    Country::Cyprus,
    Country::Czechia,
    Country::Denmark,
    Country::Estonia,
    Country::Finland,
    Country::France,
    Country::Germany,
    Country::Greece,
    Country::Hungary,
    Country::Ireland,
    Country::Italy,
    Country::Latvia,
    Country::Lithuania,
    Country::Luxembourg,
    Country::Malta,
    Country::Netherlands,
    Country::Poland,
    Country::Portugal,
    Country::Romania,
    Country::Slovakia,
    Country::Slovenia,
    Country::Spain,
    Country::Sweden,
];

// Rollout percentage config prefix
pub const UCS_ROLLOUT_PERCENT_CONFIG_PREFIX: &str = "ucs_rollout_config";

// UCS feature enabled config
pub const UCS_ENABLED: &str = "ucs_enabled";

/// Header value indicating that signature-key-based authentication is used.
pub const UCS_AUTH_SIGNATURE_KEY: &str = "signature-key";

/// Header value indicating that body-key-based authentication is used.
pub const UCS_AUTH_BODY_KEY: &str = "body-key";

/// Header value indicating that header-key-based authentication is used.
pub const UCS_AUTH_HEADER_KEY: &str = "header-key";

/// Header value indicating that currency-auth-key-based authentication is used.
pub const UCS_AUTH_CURRENCY_AUTH_KEY: &str = "currency-auth-key";

/// Form field name for challenge request during creq submission
pub const CREQ_CHALLENGE_REQUEST_KEY: &str = "creq";

#[cfg(test)]
mod tests {
    #![allow(clippy::expect_used)]

    #[test]
    fn test_profile_id_unavailable_initialization() {
        // Just access the lazy static to ensure it doesn't panic during initialization
        let _profile_id = super::PROFILE_ID_UNAVAILABLE.clone();
        // If we get here without panicking, the test passes
    }
}


// Trait: ValidateStatusForOperation
// File: crates/router/src/core/payments/operations.rs
// Module: router

// Documentation: Validate if a particular operation can be performed for the given intent status

pub trait ValidateStatusForOperation


// Struct: CardThreeDsData
// File: crates/hyperswitch_connectors/src/connectors/nmi/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CardThreeDsData


// Implementation: impl Deref for for ShouldCollectCvvDuringPayment
// File: crates/common_types/src/primitive_wrappers.rs
// Module: common_types
// Methods: 1 total (0 public)

impl Deref for for ShouldCollectCvvDuringPayment


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

impl Refund for for Threedsecureio


// Struct: BillwerkTokenResponse
// File: crates/hyperswitch_connectors/src/connectors/billwerk/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BillwerkTokenResponse


// Function: get_tracking_id_from_configs
// File: crates/router/src/utils/connector_onboarding.rs
// Module: router

pub fn get_tracking_id_from_configs(
    state: &SessionState,
    connector_id: &common_utils::id_type::MerchantConnectorAccountId,
    connector: enums::Connector,
) -> RouterResult<String>


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

impl Responder


// Struct: Node
// File: crates/hyperswitch_constraint_graph/src/types.rs
// Module: hyperswitch_constraint_graph
// Implementations: 1

pub struct Node<V: ValueNode>


// Function: from_storage
// File: crates/router/src/services/kafka/payment_attempt_event.rs
// Module: router

pub fn from_storage(attempt: &'a PaymentAttempt) -> Self


// Struct: RiskifiedFulfilmentResponse
// File: crates/hyperswitch_connectors/src/connectors/riskified/transformers/api.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RiskifiedFulfilmentResponse


// Struct: MigrateCardDetail
// File: crates/api_models/src/payment_methods.rs
// Module: api_models
// Implementations: 0

pub struct MigrateCardDetail


// Struct: TrustpaymentsPaymentRequestData
// File: crates/hyperswitch_connectors/src/connectors/trustpayments/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TrustpaymentsPaymentRequestData


// Function: record_operation_time
// File: crates/common_utils/src/metrics/utils.rs
// Module: common_utils

pub fn record_operation_time<F, R>(
    future: F,
    metric: &opentelemetry::metrics::Histogram<f64>,
    key_value: &[opentelemetry::KeyValue],
) -> R
where
    F: futures::Future<Output = R>,


// Struct: UserAuthenticationMethodNew
// File: crates/diesel_models/src/user_authentication_method.rs
// Module: diesel_models
// Implementations: 0

pub struct UserAuthenticationMethodNew


// Struct: MigrateNetworkTokenDetail
// File: crates/api_models/src/payment_methods.rs
// Module: api_models
// Implementations: 0

pub struct MigrateNetworkTokenDetail


// Function: get_internal_error
// File: crates/api_models/src/errors/types.rs
// Module: api_models

pub fn get_internal_error(&self) -> &ApiError


// Struct: Riskified
// File: crates/hyperswitch_connectors/src/connectors/riskified.rs
// Module: hyperswitch_connectors
// Implementations: 23
// Traits: ConnectorCommon, Payment, PaymentAuthorize, PaymentSync, PaymentVoid, PaymentCapture, MandateSetup, ConnectorAccessToken, PaymentToken, Refund, RefundExecute, RefundSync, ConnectorValidation, PaymentSession, FraudCheck, FraudCheckSale, FraudCheckCheckout, FraudCheckTransaction, FraudCheckFulfillment, FraudCheckRecordReturn, IncomingWebhook, ConnectorSpecifications

pub struct Riskified

ConnectorCommon Payment PaymentAuthorize PaymentSync PaymentVoid PaymentCapture MandateSetup ConnectorAccessToken PaymentToken Refund RefundExecute RefundSync ConnectorValidation PaymentSession FraudCheck FraudCheckSale FraudCheckCheckout FraudCheckTransaction FraudCheckFulfillment FraudCheckRecordReturn IncomingWebhook ConnectorSpecifications


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

pub fn create_merchant_in_decision_engine_if_not_exists(
    state: &SessionState,
    profile_id: &id_type::ProfileId,
    dynamic_routing_algo_ref: &mut routing_types::DynamicRoutingAlgorithmRef,
)


// Implementation: impl ApiClient for for MockApiClient
// File: crates/router/src/services/api/client.rs
// Module: router
// Methods: 6 total (0 public)

impl ApiClient for for MockApiClient


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

pub fn config_should_call_gsm(
    db: &dyn StorageInterface,
    merchant_id: &common_utils::id_type::MerchantId,
    profile: &domain::Profile,
) -> bool


// Struct: InespayPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/inespay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct InespayPaymentsRequest


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

impl api::MandateSetup for for Bitpay


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

impl ConnectorSpecifications for for Opennode


// Struct: TransactionEvent
// File: crates/hyperswitch_connectors/src/connectors/affirm/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TransactionEvent


// Module Structure
// File: crates/router/src/types/api/fraud_check.rs
// Module: router

// Public exports:
pub use hyperswitch_domain_models::router_flow_types::fraud_check::{
    Checkout, Fulfillment, RecordReturn, Sale, Transaction,
};
pub use hyperswitch_interfaces::api::fraud_check::{
    FraudCheckCheckout, FraudCheckFulfillment, FraudCheckRecordReturn, FraudCheckSale,
    FraudCheckTransaction,
};
pub use super::fraud_check_v2::{
    FraudCheckCheckoutV2, FraudCheckFulfillmentV2, FraudCheckRecordReturnV2, FraudCheckSaleV2,
    FraudCheckTransactionV2, FraudCheckV2,
};


// Struct: Facilitapay
// File: crates/hyperswitch_connectors/src/connectors/facilitapay.rs
// Module: hyperswitch_connectors
// Implementations: 18
// Traits: api::ConnectorCustomer, 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, webhooks::IncomingWebhook, ConnectorSpecifications

pub struct Facilitapay

api::ConnectorCustomer 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 webhooks::IncomingWebhook ConnectorSpecifications


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

pub fn new(
        tenant_id: id_type::TenantId,
        request_id: Option<RequestId>,
        payment_id: String,
        profile_id: id_type::ProfileId,
        merchant_id: id_type::MerchantId,
        flow: String,
        request: Option<Req>,
        parse_response: bool,
        log_event: bool,
    ) -> Self


// Function: to_merchant_connector_info
// File: crates/api_models/src/admin.rs
// Module: api_models

pub fn to_merchant_connector_info(&self, connector_label: &String) -> MerchantConnectorInfo


// Struct: PmTokenStored
// File: crates/router/src/core/payment_methods/tokenize/payment_method_executor.rs
// Module: router
// Implementations: 1
// Traits: State

pub struct PmTokenStored


// Function: delete_recovery_code_attempts_from_redis
// File: crates/router/src/utils/user/two_factor_auth.rs
// Module: router

pub fn delete_recovery_code_attempts_from_redis(
    state: &SessionState,
    user_id: &str,
) -> UserResult<()>


// Struct: CustombillingPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/custombilling/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CustombillingPaymentsRequest


// Function: get_list_of_accept_languages
// File: crates/hyperswitch_connectors/src/connectors/netcetera/netcetera_types.rs
// Module: hyperswitch_connectors

pub fn get_list_of_accept_languages(accept_language: String) -> Vec<String>


// Implementation: impl api::PaymentAuthorize for for Fiservemea
// File: crates/hyperswitch_connectors/src/connectors/fiservemea.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl api::PaymentAuthorize for for Fiservemea


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

pub struct GetDisputeFilterRequest


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

pub struct TransactionQuery


// Function: payments_create_and_confirm_intent
// File: crates/router/src/routes/payments.rs
// Module: router

pub fn payments_create_and_confirm_intent(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    json_payload: web::Json<payment_types::PaymentsRequest>,
) -> impl Responder


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

pub fn make_dsl_input(
    payments_dsl_input: &routing::PaymentsDslInput<'_>,
) -> RoutingResult<dsl_inputs::BackendInput>


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

pub struct BankOfAmericaErrorInformationResponse


// Struct: GpaymentsPreAuthVersionCallResponse
// File: crates/hyperswitch_connectors/src/connectors/gpayments/gpayments_types.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct GpaymentsPreAuthVersionCallResponse


// Function: config_should_call_gsm_payout
// File: crates/router/src/core/payouts/retry.rs
// Module: router

pub fn config_should_call_gsm_payout(
    db: &dyn StorageInterface,
    merchant_id: &common_utils::id_type::MerchantId,
    retry_type: PayoutRetryType,
) -> bool


// Implementation: impl ConnectorApiIntegrationPayload
// File: crates/connector_configs/src/response_modifier.rs
// Module: connector_configs
// Methods: 1 total (1 public)

impl ConnectorApiIntegrationPayload


// File: crates/api_models/src/analytics/auth_events.rs
// Module: api_models
// Public functions: 1
// Public structs: 14

use std::{
    collections::hash_map::DefaultHasher,
    hash::{Hash, Hasher},
};

use common_enums::{
    AuthenticationConnectors, AuthenticationStatus, Currency, DecoupledAuthenticationType,
    TransactionStatus,
};

use super::{NameDescription, TimeRange};

#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
pub struct AuthEventFilters {
    #[serde(default)]
    pub authentication_status: Vec<AuthenticationStatus>,
    #[serde(default)]
    pub trans_status: Vec<TransactionStatus>,
    #[serde(default)]
    pub authentication_type: Vec<DecoupledAuthenticationType>,
    #[serde(default)]
    pub error_message: Vec<String>,
    #[serde(default)]
    pub authentication_connector: Vec<AuthenticationConnectors>,
    #[serde(default)]
    pub message_version: Vec<String>,
    #[serde(default)]
    pub platform: Vec<String>,
    #[serde(default)]
    pub acs_reference_number: Vec<String>,
    #[serde(default)]
    pub mcc: Vec<String>,
    #[serde(default)]
    pub currency: Vec<Currency>,
    #[serde(default)]
    pub merchant_country: Vec<String>,
    #[serde(default)]
    pub billing_country: Vec<String>,
    #[serde(default)]
    pub shipping_country: Vec<String>,
    #[serde(default)]
    pub issuer_country: Vec<String>,
    #[serde(default)]
    pub earliest_supported_version: Vec<String>,
    #[serde(default)]
    pub latest_supported_version: Vec<String>,
    #[serde(default)]
    pub whitelist_decision: Vec<bool>,
    #[serde(default)]
    pub device_manufacturer: Vec<String>,
    #[serde(default)]
    pub device_type: Vec<String>,
    #[serde(default)]
    pub device_brand: Vec<String>,
    #[serde(default)]
    pub device_os: Vec<String>,
    #[serde(default)]
    pub device_display: Vec<String>,
    #[serde(default)]
    pub browser_name: Vec<String>,
    #[serde(default)]
    pub browser_version: Vec<String>,
    #[serde(default)]
    pub issuer_id: Vec<String>,
    #[serde(default)]
    pub scheme_name: Vec<String>,
    #[serde(default)]
    pub exemption_requested: Vec<bool>,
    #[serde(default)]
    pub exemption_accepted: Vec<bool>,
}

#[derive(
    Debug,
    serde::Serialize,
    serde::Deserialize,
    strum::AsRefStr,
    PartialEq,
    PartialOrd,
    Eq,
    Ord,
    strum::Display,
    strum::EnumIter,
    Clone,
    Copy,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum AuthEventDimensions {
    AuthenticationStatus,
    #[strum(serialize = "trans_status")]
    #[serde(rename = "trans_status")]
    TransactionStatus,
    AuthenticationType,
    ErrorMessage,
    AuthenticationConnector,
    MessageVersion,
    AcsReferenceNumber,
    Platform,
    Mcc,
    Currency,
    MerchantCountry,
    BillingCountry,
    ShippingCountry,
    IssuerCountry,
    EarliestSupportedVersion,
    LatestSupportedVersion,
    WhitelistDecision,
    DeviceManufacturer,
    DeviceType,
    DeviceBrand,
    DeviceOs,
    DeviceDisplay,
    BrowserName,
    BrowserVersion,
    IssuerId,
    SchemeName,
    ExemptionRequested,
    ExemptionAccepted,
}

#[derive(
    Clone,
    Debug,
    Hash,
    PartialEq,
    Eq,
    serde::Serialize,
    serde::Deserialize,
    strum::Display,
    strum::EnumIter,
    strum::AsRefStr,
)]
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum AuthEventMetrics {
    AuthenticationCount,
    AuthenticationAttemptCount,
    AuthenticationSuccessCount,
    ChallengeFlowCount,
    FrictionlessFlowCount,
    FrictionlessSuccessCount,
    ChallengeAttemptCount,
    ChallengeSuccessCount,
    AuthenticationErrorMessage,
    AuthenticationFunnel,
    AuthenticationExemptionApprovedCount,
    AuthenticationExemptionRequestedCount,
}

#[derive(
    Clone,
    Debug,
    Hash,
    PartialEq,
    Eq,
    serde::Serialize,
    serde::Deserialize,
    strum::Display,
    strum::EnumIter,
    strum::AsRefStr,
)]
pub enum AuthEventFlows {
    IncomingWebhookReceive,
    PaymentsExternalAuthentication,
}

pub mod metric_behaviour {
    pub struct AuthenticationCount;
    pub struct AuthenticationAttemptCount;
    pub struct AuthenticationSuccessCount;
    pub struct ChallengeFlowCount;
    pub struct FrictionlessFlowCount;
    pub struct FrictionlessSuccessCount;
    pub struct ChallengeAttemptCount;
    pub struct ChallengeSuccessCount;
    pub struct AuthenticationErrorMessage;
    pub struct AuthenticationFunnel;
}

impl From<AuthEventMetrics> for NameDescription {
    fn from(value: AuthEventMetrics) -> Self {
        Self {
            name: value.to_string(),
            desc: String::new(),
        }
    }
}

impl From<AuthEventDimensions> for NameDescription {
    fn from(value: AuthEventDimensions) -> Self {
        Self {
            name: value.to_string(),
            desc: String::new(),
        }
    }
}

#[derive(Debug, serde::Serialize, Eq)]
pub struct AuthEventMetricsBucketIdentifier {
    pub authentication_status: Option<AuthenticationStatus>,
    pub trans_status: Option<TransactionStatus>,
    pub authentication_type: Option<DecoupledAuthenticationType>,
    pub error_message: Option<String>,
    pub authentication_connector: Option<AuthenticationConnectors>,
    pub message_version: Option<String>,
    pub acs_reference_number: Option<String>,
    pub mcc: Option<String>,
    pub currency: Option<Currency>,
    pub merchant_country: Option<String>,
    pub billing_country: Option<String>,
    pub shipping_country: Option<String>,
    pub issuer_country: Option<String>,
    pub earliest_supported_version: Option<String>,
    pub latest_supported_version: Option<String>,
    pub whitelist_decision: Option<bool>,
    pub device_manufacturer: Option<String>,
    pub device_type: Option<String>,
    pub device_brand: Option<String>,
    pub device_os: Option<String>,
    pub device_display: Option<String>,
    pub browser_name: Option<String>,
    pub browser_version: Option<String>,
    pub issuer_id: Option<String>,
    pub scheme_name: Option<String>,
    pub exemption_requested: Option<bool>,
    pub exemption_accepted: Option<bool>,
    #[serde(rename = "time_range")]
    pub time_bucket: TimeRange,
    #[serde(rename = "time_bucket")]
    #[serde(with = "common_utils::custom_serde::iso8601custom")]
    pub start_time: time::PrimitiveDateTime,
}

impl AuthEventMetricsBucketIdentifier {
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        authentication_status: Option<AuthenticationStatus>,
        trans_status: Option<TransactionStatus>,
        authentication_type: Option<DecoupledAuthenticationType>,
        error_message: Option<String>,
        authentication_connector: Option<AuthenticationConnectors>,
        message_version: Option<String>,
        acs_reference_number: Option<String>,
        mcc: Option<String>,
        currency: Option<Currency>,
        merchant_country: Option<String>,
        billing_country: Option<String>,
        shipping_country: Option<String>,
        issuer_country: Option<String>,
        earliest_supported_version: Option<String>,
        latest_supported_version: Option<String>,
        whitelist_decision: Option<bool>,
        device_manufacturer: Option<String>,
        device_type: Option<String>,
        device_brand: Option<String>,
        device_os: Option<String>,
        device_display: Option<String>,
        browser_name: Option<String>,
        browser_version: Option<String>,
        issuer_id: Option<String>,
        scheme_name: Option<String>,
        exemption_requested: Option<bool>,
        exemption_accepted: Option<bool>,
        normalized_time_range: TimeRange,
    ) -> Self {
        Self {
            authentication_status,
            trans_status,
            authentication_type,
            error_message,
            authentication_connector,
            message_version,
            acs_reference_number,
            mcc,
            currency,
            merchant_country,
            billing_country,
            shipping_country,
            issuer_country,
            earliest_supported_version,
            latest_supported_version,
            whitelist_decision,
            device_manufacturer,
            device_type,
            device_brand,
            device_os,
            device_display,
            browser_name,
            browser_version,
            issuer_id,
            scheme_name,
            exemption_requested,
            exemption_accepted,
            time_bucket: normalized_time_range,
            start_time: normalized_time_range.start_time,
        }
    }
}

impl Hash for AuthEventMetricsBucketIdentifier {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.authentication_status.hash(state);
        self.trans_status.hash(state);
        self.authentication_type.hash(state);
        self.authentication_connector.hash(state);
        self.message_version.hash(state);
        self.acs_reference_number.hash(state);
        self.error_message.hash(state);
        self.mcc.hash(state);
        self.currency.hash(state);
        self.merchant_country.hash(state);
        self.billing_country.hash(state);
        self.shipping_country.hash(state);
        self.issuer_country.hash(state);
        self.earliest_supported_version.hash(state);
        self.latest_supported_version.hash(state);
        self.whitelist_decision.hash(state);
        self.device_manufacturer.hash(state);
        self.device_type.hash(state);
        self.device_brand.hash(state);
        self.device_os.hash(state);
        self.device_display.hash(state);
        self.browser_name.hash(state);
        self.browser_version.hash(state);
        self.issuer_id.hash(state);
        self.scheme_name.hash(state);
        self.exemption_requested.hash(state);
        self.exemption_accepted.hash(state);
        self.time_bucket.hash(state);
    }
}

impl PartialEq for AuthEventMetricsBucketIdentifier {
    fn eq(&self, other: &Self) -> bool {
        let mut left = DefaultHasher::new();
        self.hash(&mut left);
        let mut right = DefaultHasher::new();
        other.hash(&mut right);
        left.finish() == right.finish()
    }
}

#[derive(Debug, serde::Serialize)]
pub struct AuthEventMetricsBucketValue {
    pub authentication_count: Option<u64>,
    pub authentication_attempt_count: Option<u64>,
    pub authentication_success_count: Option<u64>,
    pub challenge_flow_count: Option<u64>,
    pub challenge_attempt_count: Option<u64>,
    pub challenge_success_count: Option<u64>,
    pub frictionless_flow_count: Option<u64>,
    pub frictionless_success_count: Option<u64>,
    pub error_message_count: Option<u64>,
    pub authentication_funnel: Option<u64>,
    pub authentication_exemption_approved_count: Option<u64>,
    pub authentication_exemption_requested_count: Option<u64>,
}

#[derive(Debug, serde::Serialize)]
pub struct MetricsBucketResponse {
    #[serde(flatten)]
    pub values: AuthEventMetricsBucketValue,
    #[serde(flatten)]
    pub dimensions: AuthEventMetricsBucketIdentifier,
}


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

impl api::PaymentSession for for Paypal


// Struct: LineItemData
// File: crates/hyperswitch_connectors/src/connectors/worldpayvantiv/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct LineItemData


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

impl api::RefundExecute for for Archipel


// Struct: ThreeDsResponse
// File: crates/hyperswitch_connectors/src/connectors/worldpay/response.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct ThreeDsResponse


// Implementation: impl RefundSync for for Payone
// File: crates/hyperswitch_connectors/src/connectors/payone.rs
// Module: hyperswitch_connectors
// Methods: 0 total (0 public)

impl RefundSync for for Payone


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

pub struct ErrorResponse


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

pub struct PaymentCount


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

pub struct AuthipayPaymentReceipt


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

impl ConnectorSpecifications for for Vgs


// Struct: CustomerAgreement
// File: crates/hyperswitch_connectors/src/connectors/worldpay/requests.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CustomerAgreement


// Function: identifier
// File: crates/euclid/src/frontend/ast/parser.rs
// Module: euclid

pub fn identifier(input: &str) -> ParseResult<&str, String>


// Function: into_inner
// File: crates/masking/src/maskable.rs
// Module: masking

// Documentation: Get the inner data while consuming self

pub fn into_inner(self) -> T


// Struct: AdyenRawCardIdentification
// File: crates/hyperswitch_connectors/src/connectors/adyenplatform/transformers/payouts.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct AdyenRawCardIdentification


// Struct: SchemaMeta
// File: crates/router_derive/src/macros/generate_schema.rs
// Module: router_derive
// Implementations: 2
// Traits: Parse, quote::ToTokens

pub struct SchemaMeta


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

pub fn call_connector_service_prerequisites<F, RouterDReq, ApiRequest, D>(
    state: &SessionState,
    req_state: ReqState,
    merchant_context: &domain::MerchantContext,
    connector: api::ConnectorData,
    operation: &BoxedOperation<'_, F, ApiRequest, D>,
    payment_data: &mut D,
    customer: &Option<domain::Customer>,
    call_connector_action: CallConnectorAction,
    schedule_time: Option<time::PrimitiveDateTime>,
    header_payload: HeaderPayload,
    frm_suggestion: Option<storage_enums::FrmSuggestion>,
    business_profile: &domain::Profile,
    is_retry_payment: bool,
    should_retry_with_pan: bool,
    all_keys_required: Option<bool>,
) -> RouterResult<(
    domain::MerchantConnectorAccountTypeDetails,
    Option<storage::CustomerUpdate>,
    RouterData<F, RouterDReq, router_types::PaymentsResponseData>,
    TokenizationAction,
)>
where
    F: Send + Clone + Sync,
    RouterDReq: Send + Sync,

    // To create connector flow specific interface data
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
    D: ConstructFlowSpecificData<F, RouterDReq, router_types::PaymentsResponseData>,
    RouterData<F, RouterDReq, router_types::PaymentsResponseData>: Feature<F, RouterDReq> + Send,
    // To construct connector flow specific api
    dyn api::Connector:
        services::api::ConnectorIntegration<F, RouterDReq, router_types::PaymentsResponseData>,


// Function: permanent_card
// File: crates/router/src/types/storage/payment_method.rs
// Module: router

pub fn permanent_card(
        payment_method_id: common_utils::id_type::GlobalPaymentMethodId,
        locker_id: Option<String>,
        token: String,
    ) -> Self


// Struct: SubMerchant
// File: crates/hyperswitch_connectors/src/connectors/worldpay/requests.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct SubMerchant


// File: crates/router/src/core/payouts/helpers.rs
// Module: router
// Public functions: 20

use ::payment_methods::controller::PaymentMethodsController;
use api_models::{enums, payment_methods::Card, payouts};
use common_utils::{
    crypto::Encryptable,
    encryption::Encryption,
    errors::CustomResult,
    ext_traits::{AsyncExt, StringExt, ValueExt},
    fp_utils, id_type, payout_method_utils as payout_additional, pii, type_name,
    types::{
        keymanager::{Identifier, KeyManagerState},
        MinorUnit, UnifiedCode, UnifiedMessage,
    },
};
#[cfg(feature = "v1")]
use common_utils::{generate_customer_id_of_default_length, types::keymanager::ToEncryptable};
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::type_encryption::{crypto_operation, CryptoOperation};
use masking::{ExposeInterface, PeekInterface, Secret, SwitchStrategy};
use router_env::logger;

use super::PayoutData;
#[cfg(feature = "payouts")]
use crate::core::payments::route_connector_v1_for_payouts;
use crate::{
    consts,
    core::{
        errors::{self, RouterResult, StorageErrorExt},
        payment_methods::{
            cards,
            transformers::{DataDuplicationCheck, StoreCardReq, StoreGenericReq, StoreLockerReq},
            vault,
        },
        payments::{helpers as payment_helpers, routing, CustomerDetails},
        routing::TransactionData,
        utils as core_utils,
    },
    db::StorageInterface,
    routes::{metrics, SessionState},
    services,
    types::{
        api::{self, enums as api_enums},
        domain::{self, types::AsyncLift},
        storage,
        transformers::ForeignFrom,
    },
    utils::{self, OptionExt},
};

#[allow(clippy::too_many_arguments)]
pub async fn make_payout_method_data(
    state: &SessionState,
    payout_method_data: Option<&api::PayoutMethodData>,
    payout_token: Option<&str>,
    customer_id: &id_type::CustomerId,
    merchant_id: &id_type::MerchantId,
    payout_type: Option<api_enums::PayoutType>,
    merchant_key_store: &domain::MerchantKeyStore,
    payout_data: Option<&mut PayoutData>,
    storage_scheme: storage::enums::MerchantStorageScheme,
) -> RouterResult<Option<api::PayoutMethodData>> {
    let db = &*state.store;
    let hyperswitch_token = if let Some(payout_token) = payout_token {
        if payout_token.starts_with("temporary_token_") {
            Some(payout_token.to_string())
        } else {
            let certain_payout_type = payout_type.get_required_value("payout_type")?.to_owned();
            let key = format!(
                "pm_token_{}_{}_hyperswitch",
                payout_token,
                api_enums::PaymentMethod::foreign_from(certain_payout_type)
            );

            let redis_conn = state
                .store
                .get_redis_conn()
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed to get redis connection")?;

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

            let payment_token = match payment_token_data {
                storage::PaymentTokenData::PermanentCard(storage::CardTokenData {
                    locker_id,
                    token,
                    ..
                }) => locker_id.or(Some(token)),
                storage::PaymentTokenData::TemporaryGeneric(storage::GenericTokenData {
                    token,
                }) => Some(token),
                _ => None,
            };
            payment_token.or(Some(payout_token.to_string()))
        }
    } else {
        None
    };

    match (
        payout_method_data.to_owned(),
        hyperswitch_token,
        payout_data,
    ) {
        // Get operation
        (None, Some(payout_token), _) => {
            if payout_token.starts_with("temporary_token_")
                || payout_type == Some(api_enums::PayoutType::Bank)
            {
                let (pm, supplementary_data) = vault::Vault::get_payout_method_data_from_temporary_locker(
                    state,
                    &payout_token,
                    merchant_key_store,
                )
                .await
                .attach_printable(
                    "Payout method for given token not found or there was a problem fetching it",
                )?;
                utils::when(
                    supplementary_data
                        .customer_id
                        .ne(&Some(customer_id.to_owned())),
                    || {
                        Err(errors::ApiErrorResponse::PreconditionFailed { message: "customer associated with payout method and customer passed in payout are not same".into() })
                    },
                )?;
                Ok(pm)
            } else {
                let resp = cards::get_card_from_locker(
                    state,
                    customer_id,
                    merchant_id,
                    payout_token.as_ref(),
                )
                .await
                .attach_printable("Payout method [card] could not be fetched from HS locker")?;
                Ok(Some({
                    api::PayoutMethodData::Card(api::CardPayout {
                        card_number: resp.card_number,
                        expiry_month: resp.card_exp_month,
                        expiry_year: resp.card_exp_year,
                        card_holder_name: resp.name_on_card,
                    })
                }))
            }
        }

        // Create / Update operation
        (Some(payout_method), payout_token, Some(payout_data)) => {
            let lookup_key = vault::Vault::store_payout_method_data_in_locker(
                state,
                payout_token.to_owned(),
                payout_method,
                Some(customer_id.to_owned()),
                merchant_key_store,
            )
            .await?;

            // Update payout_token in payout_attempt table
            if payout_token.is_none() {
                let updated_payout_attempt = storage::PayoutAttemptUpdate::PayoutTokenUpdate {
                    payout_token: lookup_key,
                };
                payout_data.payout_attempt = db
                    .update_payout_attempt(
                        &payout_data.payout_attempt,
                        updated_payout_attempt,
                        &payout_data.payouts,
                        storage_scheme,
                    )
                    .await
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Error updating token in payout attempt")?;
            }
            Ok(Some(payout_method.clone()))
        }

        // Ignore if nothing is passed
        _ => Ok(None),
    }
}

pub fn should_create_connector_transfer_method(
    payout_data: &PayoutData,
    connector_data: &api::ConnectorData,
) -> RouterResult<Option<String>> {
    let connector_transfer_method_id = payout_data.payment_method.as_ref().and_then(|pm| {
        let common_mandate_reference = pm
            .get_common_mandate_reference()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("unable to deserialize connector mandate details")
            .ok()?;

        connector_data
            .merchant_connector_id
            .as_ref()
            .and_then(|merchant_connector_id| {
                common_mandate_reference
                    .payouts
                    .and_then(|payouts_mandate_reference| {
                        payouts_mandate_reference
                            .get(merchant_connector_id)
                            .and_then(|payouts_mandate_reference_record| {
                                payouts_mandate_reference_record.transfer_method_id.clone()
                            })
                    })
            })
    });

    Ok(connector_transfer_method_id)
}

pub async fn fetch_payout_method_data(
    state: &SessionState,
    payout_data: &mut PayoutData,
    connector_data: &api::ConnectorData,
    merchant_context: &domain::MerchantContext,
) -> RouterResult<()> {
    let connector_transfer_method_id =
        should_create_connector_transfer_method(payout_data, connector_data)?;

    if connector_transfer_method_id.is_some() {
        logger::info!("Using stored transfer_method_id, skipping payout_method_data fetch");
    } else {
        let customer_id = payout_data
            .payouts
            .customer_id
            .clone()
            .get_required_value("customer_id")?;

        let payout_method_data_clone = payout_data.payout_method_data.clone();
        let payout_token = payout_data.payout_attempt.payout_token.clone();
        let merchant_id = payout_data.payout_attempt.merchant_id.clone();
        let payout_type = payout_data.payouts.payout_type;

        let payout_method_data = make_payout_method_data(
            state,
            payout_method_data_clone.as_ref(),
            payout_token.as_deref(),
            &customer_id,
            &merchant_id,
            payout_type,
            merchant_context.get_merchant_key_store(),
            Some(payout_data),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await?
        .get_required_value("payout_method_data")?;

        payout_data.payout_method_data = Some(payout_method_data);
    }

    Ok(())
}

#[cfg(feature = "v1")]
pub async fn save_payout_data_to_locker(
    state: &SessionState,
    payout_data: &mut PayoutData,
    customer_id: &id_type::CustomerId,
    payout_method_data: &api::PayoutMethodData,
    connector_mandate_details: Option<serde_json::Value>,
    merchant_context: &domain::MerchantContext,
) -> RouterResult<()> {
    let mut pm_id: Option<String> = None;
    let payouts = &payout_data.payouts;
    let key_manager_state = state.into();
    let (mut locker_req, card_details, bank_details, wallet_details, payment_method_type) =
        match payout_method_data {
            payouts::PayoutMethodData::Card(card) => {
                let card_detail = api::CardDetail {
                    card_number: card.card_number.to_owned(),
                    card_holder_name: card.card_holder_name.to_owned(),
                    card_exp_month: card.expiry_month.to_owned(),
                    card_exp_year: card.expiry_year.to_owned(),
                    nick_name: None,
                    card_issuing_country: None,
                    card_network: None,
                    card_issuer: None,
                    card_type: None,
                };
                let payload = StoreLockerReq::LockerCard(StoreCardReq {
                    merchant_id: merchant_context.get_merchant_account().get_id().clone(),
                    merchant_customer_id: customer_id.to_owned(),
                    card: Card {
                        card_number: card.card_number.to_owned(),
                        name_on_card: card.card_holder_name.to_owned(),
                        card_exp_month: card.expiry_month.to_owned(),
                        card_exp_year: card.expiry_year.to_owned(),
                        card_brand: None,
                        card_isin: None,
                        nick_name: None,
                    },
                    requestor_card_reference: None,
                    ttl: state.conf.locker.ttl_for_storage_in_secs,
                });
                (
                    payload,
                    Some(card_detail),
                    None,
                    None,
                    api_enums::PaymentMethodType::Debit,
                )
            }
            _ => {
                let key = merchant_context
                    .get_merchant_key_store()
                    .key
                    .get_inner()
                    .peek();
                let key_manager_state: KeyManagerState = state.into();
                let enc_data = async {
                    serde_json::to_value(payout_method_data.to_owned())
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("Unable to encode payout method data")
                        .ok()
                        .map(|v| {
                            let secret: Secret<String> = Secret::new(v.to_string());
                            secret
                        })
                        .async_lift(|inner| async {
                            crypto_operation(
                                &key_manager_state,
                                type_name!(storage::PaymentMethod),
                                CryptoOperation::EncryptOptional(inner),
                                Identifier::Merchant(
                                    merchant_context
                                        .get_merchant_key_store()
                                        .merchant_id
                                        .clone(),
                                ),
                                key,
                            )
                            .await
                            .and_then(|val| val.try_into_optionaloperation())
                        })
                        .await
                }
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed to encrypt payout method data")?
                .map(Encryption::from)
                .map(|e| e.into_inner())
                .map_or(Err(errors::ApiErrorResponse::InternalServerError), |e| {
                    Ok(hex::encode(e.peek()))
                })?;
                let payload = StoreLockerReq::LockerGeneric(StoreGenericReq {
                    merchant_id: merchant_context.get_merchant_account().get_id().to_owned(),
                    merchant_customer_id: customer_id.to_owned(),
                    enc_data,
                    ttl: state.conf.locker.ttl_for_storage_in_secs,
                });
                match payout_method_data {
                    payouts::PayoutMethodData::Bank(bank) => (
                        payload,
                        None,
                        Some(bank.to_owned()),
                        None,
                        api_enums::PaymentMethodType::foreign_from(bank),
                    ),
                    payouts::PayoutMethodData::Wallet(wallet) => (
                        payload,
                        None,
                        None,
                        Some(wallet.to_owned()),
                        api_enums::PaymentMethodType::foreign_from(wallet),
                    ),
                    payouts::PayoutMethodData::Card(_) => {
                        Err(errors::ApiErrorResponse::InternalServerError)?
                    }
                }
            }
        };

    // Store payout method in locker
    let stored_resp = cards::add_card_to_hs_locker(
        state,
        &locker_req,
        customer_id,
        api_enums::LockerChoice::HyperswitchCardVault,
    )
    .await
    .change_context(errors::ApiErrorResponse::InternalServerError)?;

    let db = &*state.store;

    // Handle duplicates
    let (should_insert_in_pm_table, metadata_update) = match stored_resp.duplication_check {
        // Check if equivalent entry exists in payment_methods
        Some(duplication_check) => {
            let locker_ref = stored_resp.card_reference.clone();

            // Use locker ref as payment_method_id
            let existing_pm_by_pmid = db
                .find_payment_method(
                    &(state.into()),
                    merchant_context.get_merchant_key_store(),
                    &locker_ref,
                    merchant_context.get_merchant_account().storage_scheme,
                )
                .await;

            match existing_pm_by_pmid {
                // If found, update locker's metadata [DELETE + INSERT OP], don't insert in payment_method's table
                Ok(pm) => {
                    pm_id = Some(pm.payment_method_id.clone());
                    (
                        false,
                        if duplication_check == DataDuplicationCheck::MetaDataChanged {
                            Some(pm.clone())
                        } else {
                            None
                        },
                    )
                }

                // If not found, use locker ref as locker_id
                Err(err) => {
                    if err.current_context().is_db_not_found() {
                        match db
                            .find_payment_method_by_locker_id(
                                &(state.into()),
                                merchant_context.get_merchant_key_store(),
                                &locker_ref,
                                merchant_context.get_merchant_account().storage_scheme,
                            )
                            .await
                        {
                            // If found, update locker's metadata [DELETE + INSERT OP], don't insert in payment_methods table
                            Ok(pm) => {
                                pm_id = Some(pm.payment_method_id.clone());
                                (
                                    false,
                                    if duplication_check == DataDuplicationCheck::MetaDataChanged {
                                        Some(pm.clone())
                                    } else {
                                        None
                                    },
                                )
                            }
                            Err(err) => {
                                // If not found, update locker's metadata [DELETE + INSERT OP], and insert in payment_methods table
                                if err.current_context().is_db_not_found() {
                                    (true, None)

                                // Misc. DB errors
                                } else {
                                    Err(err)
                                        .change_context(
                                            errors::ApiErrorResponse::InternalServerError,
                                        )
                                        .attach_printable(
                                            "DB failures while finding payment method by locker ID",
                                        )?
                                }
                            }
                        }
                    // Misc. DB errors
                    } else {
                        Err(err)
                            .change_context(errors::ApiErrorResponse::InternalServerError)
                            .attach_printable("DB failures while finding payment method by pm ID")?
                    }
                }
            }
        }

        // Not duplicate, should be inserted in payment_methods table
        None => (true, None),
    };

    // Form payment method entry and card's metadata whenever insertion or metadata update is required
    let (card_details_encrypted, new_payment_method) =
        if let (api::PayoutMethodData::Card(_), true, _)
        | (api::PayoutMethodData::Card(_), _, Some(_)) = (
            payout_method_data,
            should_insert_in_pm_table,
            metadata_update.as_ref(),
        ) {
            // Fetch card info from db
            let card_isin = card_details.as_ref().map(|c| c.card_number.get_card_isin());

            let mut payment_method = api::PaymentMethodCreate {
                payment_method: Some(api_enums::PaymentMethod::foreign_from(payout_method_data)),
                payment_method_type: Some(payment_method_type),
                payment_method_issuer: None,
                payment_method_issuer_code: None,
                bank_transfer: None,
                card: card_details.clone(),
                wallet: None,
                metadata: None,
                customer_id: Some(customer_id.to_owned()),
                card_network: None,
                client_secret: None,
                payment_method_data: None,
                billing: None,
                connector_mandate_details: None,
                network_transaction_id: None,
            };

            let pm_data = card_isin
                .clone()
                .async_and_then(|card_isin| async move {
                    db.get_card_info(&card_isin)
                        .await
                        .map_err(|error| services::logger::warn!(card_info_error=?error))
                        .ok()
                })
                .await
                .flatten()
                .map(|card_info| {
                    payment_method
                        .payment_method_issuer
                        .clone_from(&card_info.card_issuer);
                    payment_method.card_network =
                        card_info.card_network.clone().map(|cn| cn.to_string());
                    api::payment_methods::PaymentMethodsData::Card(
                        api::payment_methods::CardDetailsPaymentMethod {
                            last4_digits: card_details.as_ref().map(|c| c.card_number.get_last4()),
                            issuer_country: card_info.card_issuing_country,
                            expiry_month: card_details.as_ref().map(|c| c.card_exp_month.clone()),
                            expiry_year: card_details.as_ref().map(|c| c.card_exp_year.clone()),
                            nick_name: card_details.as_ref().and_then(|c| c.nick_name.clone()),
                            card_holder_name: card_details
                                .as_ref()
                                .and_then(|c| c.card_holder_name.clone()),

                            card_isin: card_isin.clone(),
                            card_issuer: card_info.card_issuer,
                            card_network: card_info.card_network,
                            card_type: card_info.card_type,
                            saved_to_locker: true,
                            co_badged_card_data: None,
                        },
                    )
                })
                .unwrap_or_else(|| {
                    api::payment_methods::PaymentMethodsData::Card(
                        api::payment_methods::CardDetailsPaymentMethod {
                            last4_digits: card_details.as_ref().map(|c| c.card_number.get_last4()),
                            issuer_country: None,
                            expiry_month: card_details.as_ref().map(|c| c.card_exp_month.clone()),
                            expiry_year: card_details.as_ref().map(|c| c.card_exp_year.clone()),
                            nick_name: card_details.as_ref().and_then(|c| c.nick_name.clone()),
                            card_holder_name: card_details
                                .as_ref()
                                .and_then(|c| c.card_holder_name.clone()),

                            card_isin: card_isin.clone(),
                            card_issuer: None,
                            card_network: None,
                            card_type: None,
                            saved_to_locker: true,
                            co_badged_card_data: None,
                        },
                    )
                });
            (
                Some(
                    cards::create_encrypted_data(
                        &key_manager_state,
                        merchant_context.get_merchant_key_store(),
                        pm_data,
                    )
                    .await
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Unable to encrypt customer details")?,
                ),
                payment_method,
            )
        } else {
            (
                None,
                api::PaymentMethodCreate {
                    payment_method: Some(api_enums::PaymentMethod::foreign_from(
                        payout_method_data,
                    )),
                    payment_method_type: Some(payment_method_type),
                    payment_method_issuer: None,
                    payment_method_issuer_code: None,
                    bank_transfer: bank_details,
                    card: None,
                    wallet: wallet_details,
                    metadata: None,
                    customer_id: Some(customer_id.to_owned()),
                    card_network: None,
                    client_secret: None,
                    payment_method_data: None,
                    billing: None,
                    connector_mandate_details: None,
                    network_transaction_id: None,
                },
            )
        };

    let payment_method_billing_address = payout_data
        .billing_address
        .clone()
        .async_map(|billing_addr| async {
            cards::create_encrypted_data(
                &key_manager_state,
                merchant_context.get_merchant_key_store(),
                billing_addr,
            )
            .await
        })
        .await
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to encrypt billing address")?;

    // Insert new entry in payment_methods table
    if should_insert_in_pm_table {
        let payment_method_id = common_utils::generate_id(consts::ID_LENGTH, "pm");
        payout_data.payment_method = Some(
            cards::PmCards {
                state,
                merchant_context,
            }
            .create_payment_method(
                &new_payment_method,
                customer_id,
                &payment_method_id,
                Some(stored_resp.card_reference.clone()),
                merchant_context.get_merchant_account().get_id(),
                None,
                None,
                card_details_encrypted.clone(),
                connector_mandate_details,
                None,
                None,
                payment_method_billing_address,
                None,
                None,
                None,
                None,
                Default::default(),
            )
            .await?,
        );
    }

    /*  1. Delete from locker
     *  2. Create new entry in locker
     *  3. Handle creation response from locker
     *  4. Update card's metadata in payment_methods table
     */
    if let Some(existing_pm) = metadata_update {
        let card_reference = &existing_pm
            .locker_id
            .clone()
            .unwrap_or(existing_pm.payment_method_id.clone());
        // Delete from locker
        cards::delete_card_from_hs_locker(
            state,
            customer_id,
            merchant_context.get_merchant_account().get_id(),
            card_reference,
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable(
            "Failed to delete PMD from locker as a part of metadata update operation",
        )?;

        locker_req.update_requestor_card_reference(Some(card_reference.to_string()));

        // Store in locker
        let stored_resp = cards::add_card_to_hs_locker(
            state,
            &locker_req,
            customer_id,
            api_enums::LockerChoice::HyperswitchCardVault,
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError);

        // Check if locker operation was successful or not, if not, delete the entry from payment_methods table
        if let Err(err) = stored_resp {
            logger::error!(vault_err=?err);
            db.delete_payment_method_by_merchant_id_payment_method_id(
                &(state.into()),
                merchant_context.get_merchant_key_store(),
                merchant_context.get_merchant_account().get_id(),
                &existing_pm.payment_method_id,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;

            Err(errors::ApiErrorResponse::InternalServerError).attach_printable(
                "Failed to insert PMD from locker as a part of metadata update operation",
            )?
        };

        // Update card's metadata in payment_methods table
        let pm_update = storage::PaymentMethodUpdate::PaymentMethodDataUpdate {
            payment_method_data: card_details_encrypted.map(Into::into),
        };
        payout_data.payment_method = Some(
            db.update_payment_method(
                &(state.into()),
                merchant_context.get_merchant_key_store(),
                existing_pm,
                pm_update,
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to add payment method in db")?,
        );
    };

    // Store card_reference in payouts table
    let payout_method_id = match &payout_data.payment_method {
        Some(pm) => pm.payment_method_id.clone(),
        None => {
            if let Some(id) = pm_id {
                id
            } else {
                Err(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Payment method was not found")?
            }
        }
    };

    let updated_payout = storage::PayoutsUpdate::PayoutMethodIdUpdate { payout_method_id };

    payout_data.payouts = db
        .update_payout(
            payouts,
            updated_payout,
            &payout_data.payout_attempt,
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Error updating payouts in saved payout method")?;

    Ok(())
}

#[cfg(feature = "v2")]
pub async fn save_payout_data_to_locker(
    _state: &SessionState,
    _payout_data: &mut PayoutData,
    _customer_id: &id_type::CustomerId,
    _payout_method_data: &api::PayoutMethodData,
    _connector_mandate_details: Option<serde_json::Value>,
    _merchant_context: &domain::MerchantContext,
) -> RouterResult<()> {
    todo!()
}

#[cfg(feature = "v2")]
pub(super) async fn get_or_create_customer_details(
    _state: &SessionState,
    _customer_details: &CustomerDetails,
    _merchant_context: &domain::MerchantContext,
) -> RouterResult<Option<domain::Customer>> {
    todo!()
}

#[cfg(feature = "v1")]
pub(super) async fn get_or_create_customer_details(
    state: &SessionState,
    customer_details: &CustomerDetails,
    merchant_context: &domain::MerchantContext,
) -> RouterResult<Option<domain::Customer>> {
    let db: &dyn StorageInterface = &*state.store;
    // Create customer_id if not passed in request
    let customer_id = customer_details
        .customer_id
        .clone()
        .unwrap_or_else(generate_customer_id_of_default_length);

    let merchant_id = merchant_context.get_merchant_account().get_id();
    let key = merchant_context
        .get_merchant_key_store()
        .key
        .get_inner()
        .peek();
    let key_manager_state = &state.into();

    match db
        .find_customer_optional_by_customer_id_merchant_id(
            key_manager_state,
            &customer_id,
            merchant_id,
            merchant_context.get_merchant_key_store(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)?
    {
        // Customer found
        Some(customer) => Ok(Some(customer)),

        // Customer not found
        // create only if atleast one of the fields were provided for customer creation or else throw error
        None => {
            if customer_details.name.is_some()
                || customer_details.email.is_some()
                || customer_details.phone.is_some()
                || customer_details.phone_country_code.is_some()
            {
                let encrypted_data = crypto_operation(
                    &state.into(),
                    type_name!(domain::Customer),
                    CryptoOperation::BatchEncrypt(
                        domain::FromRequestEncryptableCustomer::to_encryptable(
                            domain::FromRequestEncryptableCustomer {
                                name: customer_details.name.clone(),
                                email: customer_details
                                    .email
                                    .clone()
                                    .map(|a| a.expose().switch_strategy()),
                                phone: customer_details.phone.clone(),
                                tax_registration_id: customer_details.tax_registration_id.clone(),
                            },
                        ),
                    ),
                    Identifier::Merchant(
                        merchant_context
                            .get_merchant_key_store()
                            .merchant_id
                            .clone(),
                    ),
                    key,
                )
                .await
                .and_then(|val| val.try_into_batchoperation())
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed to encrypt customer")?;
                let encryptable_customer =
                    domain::FromRequestEncryptableCustomer::from_encryptable(encrypted_data)
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("Failed to form EncryptableCustomer")?;

                let customer = domain::Customer {
                    customer_id: customer_id.clone(),
                    merchant_id: merchant_id.to_owned().clone(),
                    name: encryptable_customer.name,
                    email: encryptable_customer.email.map(|email| {
                        let encryptable: Encryptable<Secret<String, pii::EmailStrategy>> =
                            Encryptable::new(
                                email.clone().into_inner().switch_strategy(),
                                email.into_encrypted(),
                            );
                        encryptable
                    }),
                    phone: encryptable_customer.phone,
                    description: None,
                    phone_country_code: customer_details.phone_country_code.to_owned(),
                    metadata: None,
                    connector_customer: None,
                    created_at: common_utils::date_time::now(),
                    modified_at: common_utils::date_time::now(),
                    address_id: None,
                    default_payment_method_id: None,
                    updated_by: None,
                    version: common_types::consts::API_VERSION,
                    tax_registration_id: encryptable_customer.tax_registration_id,
                };

                Ok(Some(
                    db.insert_customer(
                        customer,
                        key_manager_state,
                        merchant_context.get_merchant_key_store(),
                        merchant_context.get_merchant_account().storage_scheme,
                    )
                    .await
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable_lazy(|| {
                        format!(
                            "Failed to insert customer [id - {customer_id:?}] for merchant [id - {merchant_id:?}]",
                        )
                    })?,
                ))
            } else {
                Err(report!(errors::ApiErrorResponse::InvalidRequestData {
                    message: format!("customer for id - {customer_id:?} not found"),
                }))
            }
        }
    }
}

#[cfg(all(feature = "payouts", feature = "v1"))]
pub async fn decide_payout_connector(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    request_straight_through: Option<api::routing::StraightThroughAlgorithm>,
    routing_data: &mut storage::RoutingData,
    payout_data: &mut PayoutData,
    eligible_connectors: Option<Vec<enums::RoutableConnectors>>,
) -> RouterResult<api::ConnectorCallType> {
    // 1. For existing attempts, use stored connector
    let payout_attempt = &payout_data.payout_attempt;
    if let Some(connector_name) = payout_attempt.connector.clone() {
        // Connector was already decided previously, use the same connector
        let connector_data = api::ConnectorData::get_payout_connector_by_name(
            &state.conf.connectors,
            &connector_name,
            api::GetToken::Connector,
            payout_attempt.merchant_connector_id.clone(),
        )
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Invalid connector name received in 'routed_through'")?;

        routing_data.routed_through = Some(connector_name.clone());
        return Ok(api::ConnectorCallType::PreDetermined(connector_data.into()));
    }

    // Validate and get the business_profile from payout_attempt
    let business_profile = core_utils::validate_and_get_business_profile(
        state.store.as_ref(),
        &(state).into(),
        merchant_context.get_merchant_key_store(),
        Some(&payout_attempt.profile_id),
        merchant_context.get_merchant_account().get_id(),
    )
    .await?
    .get_required_value("Profile")?;

    // 2. Check routing algorithm passed in the request
    if let Some(routing_algorithm) = request_straight_through {
        let (mut connectors, check_eligibility) =
            routing::perform_straight_through_routing(&routing_algorithm, None)
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed execution of straight through routing")?;

        if check_eligibility {
            connectors = routing::perform_eligibility_analysis_with_fallback(
                state,
                merchant_context.get_merchant_key_store(),
                connectors,
                &TransactionData::Payout(payout_data),
                eligible_connectors,
                &business_profile,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("failed eligibility analysis and fallback")?;
        }

        let first_connector_choice = connectors
            .first()
            .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)
            .attach_printable("Empty connector list returned")?
            .clone();

        let connector_data = connectors
            .into_iter()
            .map(|conn| {
                api::ConnectorData::get_payout_connector_by_name(
                    &state.conf.connectors,
                    &conn.connector.to_string(),
                    api::GetToken::Connector,
                    payout_attempt.merchant_connector_id.clone(),
                )
                .map(|connector_data| connector_data.into())
            })
            .collect::<CustomResult<Vec<_>, _>>()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Invalid connector name received")?;

        routing_data.routed_through = Some(first_connector_choice.connector.to_string());
        routing_data.merchant_connector_id = first_connector_choice.merchant_connector_id;

        routing_data.routing_info.algorithm = Some(routing_algorithm);
        return Ok(api::ConnectorCallType::Retryable(connector_data));
    }

    // 3. Check algorithm passed in routing data
    if let Some(ref routing_algorithm) = routing_data.algorithm {
        let (mut connectors, check_eligibility) =
            routing::perform_straight_through_routing(routing_algorithm, None)
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed execution of straight through routing")?;

        if check_eligibility {
            connectors = routing::perform_eligibility_analysis_with_fallback(
                state,
                merchant_context.get_merchant_key_store(),
                connectors,
                &TransactionData::Payout(payout_data),
                eligible_connectors,
                &business_profile,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("failed eligibility analysis and fallback")?;
        }

        let first_connector_choice = connectors
            .first()
            .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)
            .attach_printable("Empty connector list returned")?
            .clone();

        connectors.remove(0);

        let connector_data = connectors
            .into_iter()
            .map(|conn| {
                api::ConnectorData::get_payout_connector_by_name(
                    &state.conf.connectors,
                    &conn.connector.to_string(),
                    api::GetToken::Connector,
                    payout_attempt.merchant_connector_id.clone(),
                )
                .map(|connector_data| connector_data.into())
            })
            .collect::<CustomResult<Vec<_>, _>>()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Invalid connector name received")?;

        routing_data.routed_through = Some(first_connector_choice.connector.to_string());
        routing_data.merchant_connector_id = first_connector_choice.merchant_connector_id;

        return Ok(api::ConnectorCallType::Retryable(connector_data));
    }

    // 4. Route connector
    route_connector_v1_for_payouts(
        state,
        merchant_context,
        &payout_data.business_profile,
        payout_data,
        routing_data,
        eligible_connectors,
    )
    .await
}

pub async fn get_default_payout_connector(
    _state: &SessionState,
    request_connector: Option<serde_json::Value>,
) -> CustomResult<api::ConnectorChoice, errors::ApiErrorResponse> {
    Ok(request_connector.map_or(
        api::ConnectorChoice::Decide,
        api::ConnectorChoice::StraightThrough,
    ))
}

#[cfg(feature = "v1")]
pub fn should_call_payout_connector_create_customer<'a>(
    state: &'a SessionState,
    connector: &'a api::ConnectorData,
    customer: &'a Option<domain::Customer>,
    connector_label: &'a str,
) -> (bool, Option<&'a str>) {
    // Check if create customer is required for the connector
    match enums::PayoutConnectors::try_from(connector.connector_name) {
        Ok(connector) => {
            let connector_needs_customer = state
                .conf
                .connector_customer
                .payout_connector_list
                .contains(&connector);

            if connector_needs_customer {
                let connector_customer_details = customer
                    .as_ref()
                    .and_then(|customer| customer.get_connector_customer_id(connector_label));
                let should_call_connector = connector_customer_details.is_none();
                (should_call_connector, connector_customer_details)
            } else {
                (false, None)
            }
        }
        _ => (false, None),
    }
}

#[cfg(feature = "v2")]
pub fn should_call_payout_connector_create_customer<'a>(
    state: &'a SessionState,
    connector: &'a api::ConnectorData,
    customer: &'a Option<domain::Customer>,
    merchant_connector_id: &'a domain::MerchantConnectorAccountTypeDetails,
) -> (bool, Option<&'a str>) {
    // Check if create customer is required for the connector
    match enums::PayoutConnectors::try_from(connector.connector_name) {
        Ok(connector) => {
            let connector_needs_customer = state
                .conf
                .connector_customer
                .payout_connector_list
                .contains(&connector);

            if connector_needs_customer {
                let connector_customer_details = customer
                    .as_ref()
                    .and_then(|customer| customer.get_connector_customer_id(merchant_connector_id));
                let should_call_connector = connector_customer_details.is_none();


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

impl AuthenticationStatus


// Struct: FinixPaymentsRequest
// File: crates/hyperswitch_connectors/src/connectors/finix/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct FinixPaymentsRequest


// Function: new
// File: crates/api_models/src/analytics/disputes.rs
// Module: api_models

pub fn new(
        dispute_stage: Option<DisputeStage>,
        connector: Option<String>,
        currency: Option<Currency>,
        normalized_time_range: TimeRange,
    ) -> Self


// Function: get_filters
// File: crates/analytics/src/auth_events/core.rs
// Module: analytics

pub fn get_filters(
    pool: &AnalyticsProvider,
    req: GetAuthEventFilterRequest,
    auth: &AuthInfo,
) -> AnalyticsResult<AuthEventFiltersResponse>


// Function: find_by_merchant_id_payment_id
// File: crates/diesel_models/src/query/authorization.rs
// Module: diesel_models

pub fn find_by_merchant_id_payment_id(
        conn: &PgPooledConn,
        merchant_id: &common_utils::id_type::MerchantId,
        payment_id: &common_utils::id_type::PaymentId,
    ) -> StorageResult<Vec<Self>>


// Struct: TrustpaymentsCaptureRequest
// File: crates/hyperswitch_connectors/src/connectors/trustpayments/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TrustpaymentsCaptureRequest


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

pub struct CreditCardError


// Function: dummy_connector_payment
// File: crates/router/src/routes/dummy_connector.rs
// Module: router

pub fn dummy_connector_payment(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    json_payload: web::Json<types::DummyConnectorPaymentRequest>,
) -> impl actix_web::Responder


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

impl api::MandateSetup for for Taxjar


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

pub struct PaysafeErrorResponse


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

pub fn get_total_amount(&self) -> MinorUnit


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

impl api::Payment for for Jpmorgan


// Struct: BillwerkTokenRequest
// File: crates/hyperswitch_connectors/src/connectors/billwerk/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct BillwerkTokenRequest


// Module Structure
// File: crates/router/src/core/connector_onboarding/paypal.rs
// Module: router

// Public exports:
pub use external_services::http_client;


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

impl PaymentMetricAccumulator for for AverageAccumulator