pub struct UpdatePaymentMethodRecord {
    pub payment_method_id: String,
    pub status: Option<common_enums::PaymentMethodStatus>,
    pub network_transaction_id: Option<String>,
    pub line_number: Option<i64>,
    pub payment_instrument_id: Option<masking::Secret<String>>,
    pub merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
}


pub struct WorldpayRouterData<T> {
    amount: i64,
    router_data: T,
}


impl ConnectorValidation for Opayo {
    fn validate_connector_against_payment_request(
        &self,
        capture_method: Option<enums::CaptureMethod>,
        _payment_method: enums::PaymentMethod,
        _pmt: Option<enums::PaymentMethodType>,
    ) -> CustomResult<(), errors::ConnectorError> {
        let capture_method = capture_method.unwrap_or_default();
        match capture_method {
            enums::CaptureMethod::Automatic
            | enums::CaptureMethod::Manual
            | enums::CaptureMethod::SequentialAutomatic => Ok(()),
            enums::CaptureMethod::ManualMultiple | enums::CaptureMethod::Scheduled => Err(
                crate::utils::construct_not_supported_error_report(capture_method, self.id()),
            ),
        }
    }
}


pub async fn create_decision_engine_merchant(
    state: &SessionState,
    profile_id: &id_type::ProfileId,
) -> RouterResult<()> {
    let merchant_account_req = open_router::MerchantAccount {
        merchant_id: profile_id.get_string_repr().to_string(),
        gateway_success_rate_based_decider_input: None,
    };

    routing_utils::ConfigApiClient::send_decision_engine_request::<_, serde_json::Value>(
        state,
        services::Method::Post,
        DECISION_ENGINE_MERCHANT_CREATE_ENDPOINT,
        Some(merchant_account_req),
        None,
        None,
    )
    .await
    .change_context(errors::ApiErrorResponse::InternalServerError)
    .attach_printable("Failed to create merchant account on decision engine")?;

    Ok(())
}


pub struct ThreeDSRequestChallenge {
    pub return_url: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub preference: Option<ThreeDsPreference>,
}


File: crates/euclid/src/dssa/types.rs
 Public functions: 5
 Public structs: 3

use std::{collections::HashMap, fmt};

use serde::Serialize;

use crate::{
    dssa::{self, graph},
    frontend::{ast, dir},
    types::{DataType, EuclidValue, Metadata},
};

pub trait EuclidAnalysable: Sized {
    fn get_dir_value_for_analysis(&self, rule_name: String) -> Vec<(dir::DirValue, Metadata)>;
}

#[derive(Debug, Clone)]
pub enum CtxValueKind<'a> {
    Assertion(&'a dir::DirValue),
    Negation(&'a [dir::DirValue]),
}

impl CtxValueKind<'_> {
    pub fn get_assertion(&self) -> Option<&dir::DirValue> {
        if let Self::Assertion(val) = self {
            Some(val)
        } else {
            None
        }
    }

    pub fn get_negation(&self) -> Option<&[dir::DirValue]> {
        if let Self::Negation(vals) = self {
            Some(vals)
        } else {
            None
        }
    }

    pub fn get_key(&self) -> Option<dir::DirKey> {
        match self {
            Self::Assertion(val) => Some(val.get_key()),
            Self::Negation(vals) => vals.first().map(|v| (*v).get_key()),
        }
    }
}

#[derive(Debug, Clone)]
pub struct ContextValue<'a> {
    pub value: CtxValueKind<'a>,
    pub metadata: &'a Metadata,
}

impl<'a> ContextValue<'a> {
    #[inline]
    pub fn assertion(value: &'a dir::DirValue, metadata: &'a Metadata) -> Self {
        Self {
            value: CtxValueKind::Assertion(value),
            metadata,
        }
    }

    #[inline]
    pub fn negation(values: &'a [dir::DirValue], metadata: &'a Metadata) -> Self {
        Self {
            value: CtxValueKind::Negation(values),
            metadata,
        }
    }
}

pub type ConjunctiveContext<'a> = Vec<ContextValue<'a>>;

#[derive(Clone, Serialize)]
pub enum AnalyzeResult {
    AllOk,
}

#[derive(Debug, Clone, Serialize, thiserror::Error)]
pub struct AnalysisError {
    #[serde(flatten)]
    pub error_type: AnalysisErrorType,
    pub metadata: Metadata,
}
impl fmt::Display for AnalysisError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.error_type.fmt(f)
    }
}
#[derive(Debug, Clone, Serialize)]
pub struct ValueData {
    pub value: dir::DirValue,
    pub metadata: Metadata,
}

#[derive(Debug, Clone, Serialize, thiserror::Error)]
#[serde(tag = "type", content = "info", rename_all = "snake_case")]
pub enum AnalysisErrorType {
    #[error("Invalid program key given: '{0}'")]
    InvalidKey(String),
    #[error("Invalid variant '{got}' received for key '{key}'")]
    InvalidVariant {
        key: String,
        expected: Vec<String>,
        got: String,
    },
    #[error(
        "Invalid data type for value '{}' (expected {expected}, got {got})",
        key
    )]
    InvalidType {
        key: String,
        expected: DataType,
        got: DataType,
    },
    #[error("Invalid comparison '{operator:?}' for value type {value_type}")]
    InvalidComparison {
        operator: ast::ComparisonType,
        value_type: DataType,
    },
    #[error("Invalid value received for length as '{value}: {:?}'", message)]
    InvalidValue {
        key: dir::DirKeyKind,
        value: String,
        message: Option<String>,
    },
    #[error("Conflicting assertions received for key '{}'", .key.kind)]
    ConflictingAssertions {
        key: dir::DirKey,
        values: Vec<ValueData>,
    },

    #[error("Key '{}' exhaustively negated", .key.kind)]
    ExhaustiveNegation {
        key: dir::DirKey,
        metadata: Vec<Metadata>,
    },
    #[error("The condition '{value}' was asserted and negated in the same condition")]
    NegatedAssertion {
        value: dir::DirValue,
        assertion_metadata: Metadata,
        negation_metadata: Metadata,
    },
    #[error("Graph analysis error: {0:#?}")]
    GraphAnalysis(
        graph::AnalysisError<dir::DirValue>,
        hyperswitch_constraint_graph::Memoization<dir::DirValue>,
    ),
    #[error("State machine error")]
    StateMachine(dssa::state_machine::StateMachineError),
    #[error("Unsupported program key '{0}'")]
    UnsupportedProgramKey(dir::DirKeyKind),
    #[error("Ran into an unimplemented feature")]
    NotImplemented,
    #[error("The payment method type is not supported under the payment method")]
    NotSupported,
}

#[derive(Debug, Clone)]
pub enum ValueType {
    EnumVariants(Vec<EuclidValue>),
    Number,
}

impl EuclidAnalysable for common_enums::AuthenticationType {
    fn get_dir_value_for_analysis(&self, rule_name: String) -> Vec<(dir::DirValue, Metadata)> {
        let auth = self.to_string();

        let dir_value = match self {
            Self::ThreeDs => dir::DirValue::AuthenticationType(Self::ThreeDs),
            Self::NoThreeDs => dir::DirValue::AuthenticationType(Self::NoThreeDs),
        };

        vec![(
            dir_value,
            HashMap::from_iter([(
                "AUTHENTICATION_TYPE".to_string(),
                serde_json::json!({
                    "rule_name": rule_name,
                    "Authentication_type": auth,
                }),
            )]),
        )]
    }
}


impl Responder {
    let flow = Flow::CustomersGetMandates;
    let customer_id = path.into_inner();

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        customer_id,
        |state, auth: auth::AuthenticationData, customer_id, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            crate::core::mandate::get_customer_mandates(state, merchant_context, customer_id)
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuth {
                permission: Permission::MerchantMandateRead,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


impl webhooks::IncomingWebhook for Bankofamerica {
    fn get_webhook_object_reference_id(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_event_type(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        Ok(api_models::webhooks::IncomingWebhookEvent::EventNotSupported)
    }

    fn get_webhook_resource_object(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }
}

impl webhooks::IncomingWebhook for for Bankofamerica


pub struct ProfileNew;


pub struct AuthenticationErrorInformation {
    pub rmsg: String,
}


impl auth_service::AuthServiceBankAccountCredentials for Plaid {}

impl auth_service::AuthServiceBankAccountCredentials for for Plaid


pub fn add_connector_http_status_code_metrics(option_status_code: Option<u16>) {
    if let Some(status_code) = option_status_code {
        let status_code_type = get_http_status_code_type(status_code).ok();
        match status_code_type.as_deref() {
            Some("1xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_1XX_COUNT.add(1, &[]),
            Some("2xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_2XX_COUNT.add(1, &[]),
            Some("3xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_3XX_COUNT.add(1, &[]),
            Some("4xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_4XX_COUNT.add(1, &[]),
            Some("5xx") => metrics::CONNECTOR_HTTP_STATUS_CODE_5XX_COUNT.add(1, &[]),
            _ => logger::info!("Skip metrics as invalid http status code received from connector"),
        };
    } else {
        logger::info!("Skip metrics as no http status code received from connector")
    }
}


pub struct PaymentAdditionalData<'a, F>
where
    F: Clone,
{
    router_base_url: String,
    connector_name: String,
    payment_data: PaymentData<F>,
    state: &'a SessionState,
    customer_data: &'a Option<domain::Customer>,
}


pub struct MerchantConnectorDetails {
    /// Account details of the Connector. You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Useful for storing additional, structured information on an object.
    #[schema(value_type = Option<Object>,example = json!({ "auth_type": "HeaderKey","api_key": "Basic MyVerySecretApiKey" }))]
    pub connector_account_details: pii::SecretSerdeValue,
    /// Metadata is useful for storing additional, unstructured information on an object.
    #[schema(value_type = Option<Object>,max_length = 255,example = json!({ "city": "NY", "unit": "245" }))]
    pub metadata: Option<pii::SecretSerdeValue>,
}


impl api::Refund for CtpMastercard {}


pub struct CeleroAddress {
    first_name: Option<Secret<String>>,
    last_name: Option<Secret<String>>,
    address_line_1: Option<Secret<String>>,
    address_line_2: Option<Secret<String>>,
    city: Option<String>,
    state: Option<Secret<String>>,
    postal_code: Option<Secret<String>>,
    country: Option<common_enums::CountryAlpha2>,
    phone: Option<Secret<String>>,
    email: Option<Email>,
}


pub struct Card {
    number: cards::CardNumber,
    expiration_month: Secret<String>,
    expiration_year: Secret<String>,
    security_code: Option<Secret<String>>,
    #[serde(rename = "type")]
    card_type: Option<String>,
    type_selection_indicator: Option<String>,
}


pub struct GlobalpayCancelRouterData<T> {
    pub amount: Option<StringMinorUnit>,
    pub router_data: T,
}


pub trait TransitionTo<S: State> {}


impl MergedEnabledPaymentMethodTypes {
    fn get_required_fields(
        self,
        input: RequiredFieldsInput,
    ) -> RequiredFieldsForEnabledPaymentMethodTypes {
        let required_fields_config = input.required_fields_config;
        let is_cit_transaction = input.setup_future_usage == common_enums::FutureUsage::OffSession;

        let required_fields_info = self
            .0
            .into_iter()
            .map(|payment_methods_enabled| {
                let required_fields =
                    required_fields_config.get_required_fields(&payment_methods_enabled);

                let required_fields = required_fields
                    .map(|required_fields| {
                        let common_required_fields = required_fields
                            .common
                            .iter()
                            .flatten()
                            .map(ToOwned::to_owned);

                        // Collect mandate required fields because this is for zero auth mandates only
                        let mandate_required_fields = required_fields
                            .mandate
                            .iter()
                            .flatten()
                            .map(ToOwned::to_owned);

                        // Collect non-mandate required fields because this is for zero auth mandates only
                        let non_mandate_required_fields = required_fields
                            .non_mandate
                            .iter()
                            .flatten()
                            .map(ToOwned::to_owned);

                        // Combine mandate and non-mandate required fields based on setup_future_usage
                        if is_cit_transaction {
                            common_required_fields
                                .chain(non_mandate_required_fields)
                                .collect::<Vec<_>>()
                        } else {
                            common_required_fields
                                .chain(mandate_required_fields)
                                .collect::<Vec<_>>()
                        }
                    })
                    .unwrap_or_default();

                RequiredFieldsForEnabledPaymentMethod {
                    required_fields,
                    payment_method_type: payment_methods_enabled.payment_method_type,
                    payment_method_subtype: payment_methods_enabled.payment_method_subtype,
                    payment_experience: payment_methods_enabled.payment_experience,
                    connectors: payment_methods_enabled.connectors,
                }
            })
            .collect();

        RequiredFieldsForEnabledPaymentMethodTypes(required_fields_info)
    }
}


pub fn get_pending_captures_without_connector_capture_id(&self) -> Vec<&storage::Capture> {
        self.get_pending_captures()
            .into_iter()
            .filter(|capture| capture.get_optional_connector_transaction_id().is_none())
            .collect()
    }


impl api::ConnectorAccessToken for Fiserv {}

impl api::ConnectorAccessToken for for Fiserv


pub struct SilverflowCardData {
    pub number: String,
    pub expiry_month: Secret<String>,
    pub expiry_year: Secret<String>,
    pub cvc: String,
    pub holder_name: String,
}


pub fn get_value(&self) -> &T {
        match self {
            Self::ValueSet(value) => value,
            Self::ValueExists(value) => value,
        }
    }


pub struct Advice {
    pub code: Option<String>,
}


File: crates/hyperswitch_connectors/src/connectors/nomupay/transformers.rs
 Public structs: 22

#[cfg(feature = "payouts")]
use common_enums::enums::PayoutEntityType;
use common_enums::{enums, Currency, PayoutStatus};
use common_utils::{pii::Email, types::FloatMajorUnit};
use hyperswitch_domain_models::router_data::ConnectorAuthType;
#[cfg(feature = "payouts")]
use hyperswitch_domain_models::{
    router_response_types::PayoutsResponseData, types::PayoutsRouterData,
};
use hyperswitch_interfaces::errors;
use masking::Secret;
use serde::{Deserialize, Serialize};

#[cfg(feature = "payouts")]
use crate::utils::PayoutFulfillRequestData;
#[cfg(feature = "payouts")]
use crate::{types::PayoutsResponseRouterData, utils::RouterData as UtilsRouterData};

pub const PURPOSE_OF_PAYMENT_IS_OTHER: &str = "OTHER";

pub struct NomupayRouterData<T> {
    pub amount: FloatMajorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
    pub router_data: T,
}

impl<T> From<(FloatMajorUnit, T)> for NomupayRouterData<T> {
    fn from((amount, item): (FloatMajorUnit, T)) -> Self {
        //Todo :  use utils to convert the amount to the type of amount that a connector accepts
        Self {
            amount,
            router_data: item,
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Address {
    pub country: enums::CountryAlpha2,
    pub state_province: Secret<String>,
    pub street: Secret<String>,
    pub city: String,
    pub postal_code: Secret<String>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum ProfileType {
    #[default]
    Individual,
    Businness,
}

#[cfg(feature = "payouts")]
impl From<PayoutEntityType> for ProfileType {
    fn from(entity: PayoutEntityType) -> Self {
        match entity {
            PayoutEntityType::Personal
            | PayoutEntityType::NaturalPerson
            | PayoutEntityType::Individual => Self::Individual,
            _ => Self::Businness,
        }
    }
}

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub enum NomupayGender {
    Male,
    Female,
    #[default]
    Other,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Profile {
    pub profile_type: ProfileType,
    pub first_name: Secret<String>,
    pub last_name: Secret<String>,
    pub date_of_birth: Secret<String>,
    pub gender: NomupayGender,
    pub email_address: Email,
    pub phone_number_country_code: Option<String>,
    pub phone_number: Option<Secret<String>>,
    pub address: Address,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct OnboardSubAccountRequest {
    pub account_id: Secret<String>,
    pub client_sub_account_id: Secret<String>,
    pub profile: Profile,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct BankAccount {
    pub bank_id: Option<Secret<String>>,
    pub account_id: Secret<String>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct VirtualAccountsType {
    pub country_code: String,
    pub currency_code: String,
    pub bank_id: Secret<String>,
    pub bank_account_id: Secret<String>,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum TransferMethodType {
    #[default]
    BankAccount,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct OnboardTransferMethodRequest {
    pub country_code: enums::CountryAlpha2,
    pub currency_code: Currency,
    #[serde(rename = "type")]
    pub transfer_method_type: TransferMethodType,
    pub display_name: Secret<String>,
    pub bank_account: BankAccount,
    pub profile: Profile,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct NomupayPaymentRequest {
    pub source_id: Secret<String>,
    pub destination_id: Secret<String>,
    pub payment_reference: String,
    pub amount: FloatMajorUnit,
    pub currency_code: Currency,
    pub purpose: String,
    pub description: Option<String>,
    pub internal_memo: Option<String>,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct QuoteRequest {
    pub source_id: Secret<String>,
    pub source_currency_code: Currency,
    pub destination_currency_code: Currency,
    pub amount: FloatMajorUnit,
    pub include_fee: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct CommitRequest {
    pub source_id: Secret<String>,
    pub id: String,
    pub destination_id: Secret<String>,
    pub payment_reference: String,
    pub amount: FloatMajorUnit,
    pub currency_code: Currency,
    pub purpose: String,
    pub description: String,
    pub internal_memo: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct OnboardSubAccountResponse {
    pub account_id: Secret<String>,
    pub id: String,
    pub client_sub_account_id: Secret<String>,
    pub profile: Profile,
    pub virtual_accounts: Vec<VirtualAccountsType>,
    pub status: String,
    pub created_on: String,
    pub last_updated: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct OnboardTransferMethodResponse {
    pub parent_id: Secret<String>,
    pub account_id: Secret<String>,
    pub sub_account_id: Secret<String>,
    pub id: String,
    pub status: String,
    pub created_on: String,
    pub last_updated: String,
    pub country_code: String,
    pub currency_code: Currency,
    pub display_name: String,
    #[serde(rename = "type")]
    pub transfer_method_type: String,
    pub profile: Profile,
    pub bank_account: BankAccount,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct NomupayPaymentResponse {
    pub id: String,
    pub status: NomupayPaymentStatus,
    pub created_on: String,
    pub last_updated: String,
    pub source_id: Secret<String>,
    pub destination_id: Secret<String>,
    pub payment_reference: String,
    pub amount: FloatMajorUnit,
    pub currency_code: String,
    pub purpose: String,
    pub description: String,
    pub internal_memo: String,
    pub release_on: String,
    pub expire_on: String,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct FeesType {
    #[serde(rename = "type")]
    pub fees_type: String,
    pub fees: FloatMajorUnit,
    pub currency_code: Currency,
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct PayoutQuoteResponse {
    pub source_id: Secret<String>,
    pub destination_currency_code: Currency,
    pub amount: FloatMajorUnit,
    pub source_currency_code: Currency,
    pub include_fee: bool,
    pub fees: Vec<FeesType>,
    pub payment_reference: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct CommitResponse {
    pub id: String,
    pub status: String,
    pub created_on: String,
    pub last_updated: String,
    pub source_id: Secret<String>,
    pub destination_id: Secret<String>,
    pub payment_reference: String,
    pub amount: FloatMajorUnit,
    pub currency_code: Currency,
    pub purpose: String,
    pub description: String,
    pub internal_memo: String,
    pub release_on: String,
    pub expire_on: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct NomupayMetadata {
    pub private_key: Secret<String>,
}

#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ValidationError {
    pub field: String,
    pub message: String,
}

#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DetailsType {
    pub loc: Vec<String>,
    #[serde(rename = "type")]
    pub error_type: String,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct NomupayInnerError {
    pub error_code: String,
    pub error_description: Option<String>,
    pub validation_errors: Option<Vec<ValidationError>>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct NomupayErrorResponse {
    pub status: Option<String>,
    pub code: Option<u64>,
    pub error: Option<NomupayInnerError>,
    pub status_code: Option<u16>,
    pub detail: Option<Vec<DetailsType>>,
}

pub struct NomupayAuthType {
    pub(super) kid: Secret<String>,
    #[cfg(feature = "payouts")]
    pub(super) eid: Secret<String>,
}

impl TryFrom<&ConnectorAuthType> for NomupayAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            #[cfg(feature = "payouts")]
            ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self {
                kid: api_key.to_owned(),
                eid: key1.to_owned(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum NomupayPaymentStatus {
    Pending,
    Processed,
    Failed,
    #[default]
    Processing,
    Scheduled,
    PendingAccountActivation,
    PendingTransferMethodCreation,
    PendingAccountKyc,
}

impl From<NomupayPaymentStatus> for PayoutStatus {
    fn from(item: NomupayPaymentStatus) -> Self {
        match item {
            NomupayPaymentStatus::Processed => Self::Success,
            NomupayPaymentStatus::Failed => Self::Failed,
            NomupayPaymentStatus::Processing
            | NomupayPaymentStatus::Pending
            | NomupayPaymentStatus::Scheduled
            | NomupayPaymentStatus::PendingAccountActivation
            | NomupayPaymentStatus::PendingTransferMethodCreation
            | NomupayPaymentStatus::PendingAccountKyc => Self::Pending,
        }
    }
}

#[cfg(feature = "payouts")]
fn get_profile<F>(
    item: &PayoutsRouterData<F>,
    entity_type: PayoutEntityType,
) -> Result<Profile, error_stack::Report<errors::ConnectorError>> {
    let my_address = Address {
        country: item.get_billing_country()?,
        state_province: item.get_billing_state()?,
        street: item.get_billing_line1()?,
        city: item.get_billing_city()?,
        postal_code: item.get_billing_zip()?,
    };

    Ok(Profile {
        profile_type: ProfileType::from(entity_type),
        first_name: item.get_billing_first_name()?,
        last_name: item.get_billing_last_name()?,
        date_of_birth: Secret::new("1991-01-01".to_string()), // Query raised with Nomupay regarding why this field is required
        gender: NomupayGender::Other, // Query raised with Nomupay regarding why this field is required
        email_address: item.get_billing_email()?,
        phone_number_country_code: item
            .get_billing_phone()
            .map(|phone| phone.country_code.clone())?,
        phone_number: Some(item.get_billing_phone_number()?),
        address: my_address,
    })
}

// PoRecipient Request
#[cfg(feature = "payouts")]
impl<F> TryFrom<&PayoutsRouterData<F>> for OnboardSubAccountRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PayoutsRouterData<F>) -> Result<Self, Self::Error> {
        let request = item.request.to_owned();
        let payout_type = request.payout_type;

        let profile = get_profile(item, request.entity_type)?;

        let nomupay_auth_type = NomupayAuthType::try_from(&item.connector_auth_type)?;

        match payout_type {
            Some(common_enums::PayoutType::Bank) => Ok(Self {
                account_id: nomupay_auth_type.eid,
                client_sub_account_id: Secret::new(item.connector_request_reference_id.clone()),
                profile,
            }),
            _ => Err(errors::ConnectorError::NotImplemented(
                "This payment method is not implemented for Nomupay".to_string(),
            )
            .into()),
        }
    }
}

// PoRecipient Response
#[cfg(feature = "payouts")]
impl<F> TryFrom<PayoutsResponseRouterData<F, OnboardSubAccountResponse>> for PayoutsRouterData<F> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PayoutsResponseRouterData<F, OnboardSubAccountResponse>,
    ) -> Result<Self, Self::Error> {
        let response: OnboardSubAccountResponse = item.response;

        Ok(Self {
            response: Ok(PayoutsResponseData {
                status: Some(PayoutStatus::RequiresVendorAccountCreation),
                connector_payout_id: Some(response.id.to_string()),
                payout_eligible: None,
                should_add_next_step_to_process_tracker: false,
                error_code: None,
                error_message: None,
            }),
            ..item.data
        })
    }
}

// PoRecipientAccount Request
#[cfg(feature = "payouts")]
impl<F> TryFrom<&PayoutsRouterData<F>> for OnboardTransferMethodRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &PayoutsRouterData<F>) -> Result<Self, Self::Error> {
        let payout_method_data = item.get_payout_method_data()?;
        match payout_method_data {
            api_models::payouts::PayoutMethodData::Bank(bank) => match bank {
                api_models::payouts::Bank::Sepa(bank_details) => {
                    let bank_account = BankAccount {
                        bank_id: bank_details.bic,
                        account_id: bank_details.iban,
                    };

                    let country_iso2_code = item
                        .get_billing_country()
                        .unwrap_or(enums::CountryAlpha2::CA);

                    let profile = get_profile(item, item.request.entity_type)?;

                    Ok(Self {
                        country_code: country_iso2_code,
                        currency_code: item.request.destination_currency,
                        transfer_method_type: TransferMethodType::BankAccount,
                        display_name: item.get_billing_full_name()?,
                        bank_account,
                        profile,
                    })
                }
                other_bank => Err(errors::ConnectorError::NotSupported {
                    message: format!("{other_bank:?} is not supported"),
                    connector: "nomupay",
                }
                .into()),
            },
            _ => Err(errors::ConnectorError::NotImplemented(
                "This payment method is not implemented for Nomupay".to_string(),
            )
            .into()),
        }
    }
}

// PoRecipientAccount response
#[cfg(feature = "payouts")]
impl<F> TryFrom<PayoutsResponseRouterData<F, OnboardTransferMethodResponse>>
    for PayoutsRouterData<F>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PayoutsResponseRouterData<F, OnboardTransferMethodResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(PayoutsResponseData {
                status: Some(PayoutStatus::RequiresCreation),
                connector_payout_id: Some(item.response.id),
                payout_eligible: None,
                should_add_next_step_to_process_tracker: false,
                error_code: None,
                error_message: None,
            }),
            ..item.data
        })
    }
}

// PoFulfill Request
#[cfg(feature = "payouts")]
impl<F> TryFrom<(&PayoutsRouterData<F>, FloatMajorUnit)> for NomupayPaymentRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        (item, amount): (&PayoutsRouterData<F>, FloatMajorUnit),
    ) -> Result<Self, Self::Error> {
        let nomupay_auth_type = NomupayAuthType::try_from(&item.connector_auth_type)?;
        let destination = item.request.clone().get_connector_transfer_method_id()?;

        Ok(Self {
            source_id: nomupay_auth_type.eid,
            destination_id: Secret::new(destination),
            payment_reference: item.connector_request_reference_id.clone(),
            amount,
            currency_code: item.request.destination_currency,
            purpose: PURPOSE_OF_PAYMENT_IS_OTHER.to_string(),
            description: item.description.clone(),
            internal_memo: item.description.clone(),
        })
    }
}

// PoFulfill response
#[cfg(feature = "payouts")]
impl<F> TryFrom<PayoutsResponseRouterData<F, NomupayPaymentResponse>> for PayoutsRouterData<F> {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: PayoutsResponseRouterData<F, NomupayPaymentResponse>,
    ) -> Result<Self, Self::Error> {
        let response: NomupayPaymentResponse = item.response;

        Ok(Self {
            response: Ok(PayoutsResponseData {
                status: Some(PayoutStatus::from(response.status)),
                connector_payout_id: Some(response.id),
                payout_eligible: None,
                should_add_next_step_to_process_tracker: false,
                error_code: None,
                error_message: None,
            }),
            ..item.data
        })
    }
}


impl masking::SerializableSecret for Address {}

impl masking::SerializableSecret for for Address


impl ResourceExt for Resource {
            fn entities(&self) -> Vec<EntityType> {
                match self {
                    #(#entity_impl_res),*
                }
            }
        }


pub async fn customer_retrieve(
    state: web::Data<routes::AppState>,
    req: HttpRequest,
    path: web::Path<id_type::CustomerId>,
) -> HttpResponse {
    let customer_id = path.into_inner();

    let flow = Flow::CustomersRetrieve;

    Box::pin(wrap::compatibility_api_wrap::<
        _,
        _,
        _,
        _,
        _,
        types::CustomerRetrieveResponse,
        errors::StripeErrorCode,
        _,
    >(
        flow,
        state.into_inner(),
        &req,
        customer_id,
        |state, auth: auth::AuthenticationData, customer_id, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            customers::retrieve_customer(state, merchant_context, None, customer_id)
        },
        &auth::HeaderAuth(auth::ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        }),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


Documentation: api-reference/v2/merchant-account/merchant-account--profile-list.mdx
# Type: Doc File

---
openapi: get /v2/merchant-accounts/{id}/profiles
---


pub struct MandatePaymentRequest {
    pub amount: FloatMajorUnit,
    pub currency: Currency,
    pub capture_method: String,
    pub payment_method_id: Secret<String>,
    pub channel_properties: ChannelProperties,
}


pub struct CaptureNew {
    pub capture_id: String,
    pub payment_id: common_utils::id_type::PaymentId,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub status: storage_enums::CaptureStatus,
    pub amount: MinorUnit,
    pub currency: Option<storage_enums::Currency>,
    pub connector: String,
    pub error_message: Option<String>,
    pub error_code: Option<String>,
    pub error_reason: Option<String>,
    pub tax_amount: Option<MinorUnit>,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub created_at: PrimitiveDateTime,
    #[serde(with = "common_utils::custom_serde::iso8601")]
    pub modified_at: PrimitiveDateTime,
    pub authorized_attempt_id: String,
    pub connector_capture_id: Option<ConnectorTransactionId>,
    pub capture_sequence: i16,
    pub connector_response_reference_id: Option<String>,
    /// INFO: This field is deprecated and replaced by processor_capture_data
    pub connector_capture_data: Option<String>,
    pub processor_capture_data: Option<String>,
}


pub struct AirwallexPaymentsResponse {
    status: AirwallexPaymentStatus,
    //Unique identifier for the PaymentIntent
    id: String,
    amount: Option<f32>,
    //ID of the PaymentConsent related to this PaymentIntent
    payment_consent_id: Option<Secret<String>>,
    next_action: Option<AirwallexPaymentsNextAction>,
}


File: crates/api_models/src/analytics/active_payments.rs
 Public functions: 1
 Public structs: 4

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

use super::NameDescription;

#[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 ActivePaymentsMetrics {
    ActivePayments,
}

pub mod metric_behaviour {
    pub struct ActivePayments;
}

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

#[derive(Debug, serde::Serialize, Eq)]
pub struct ActivePaymentsMetricsBucketIdentifier {
    pub time_bucket: Option<String>,
}

impl ActivePaymentsMetricsBucketIdentifier {
    pub fn new(time_bucket: Option<String>) -> Self {
        Self { time_bucket }
    }
}

impl Hash for ActivePaymentsMetricsBucketIdentifier {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.time_bucket.hash(state);
    }
}

impl PartialEq for ActivePaymentsMetricsBucketIdentifier {
    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 ActivePaymentsMetricsBucketValue {
    pub active_payments: Option<u64>,
}

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


impl ConnectorPreAuthentication for Threedsecureio {}

impl ConnectorPreAuthentication for for Threedsecureio


impl ConnectorCommon for Hipay {
    fn id(&self) -> &'static str {
        "hipay"
    }

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Base
    }

    fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str {
        connectors.hipay.base_url.as_ref()
    }

    fn get_auth_header(
        &self,
        auth_type: &ConnectorAuthType,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        let auth = hipay::HipayAuthType::try_from(auth_type)
            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
        let auth_key = format!("{}:{}", auth.api_key.peek(), auth.key1.peek());
        let auth_header = format!("Basic {}", BASE64_ENGINE.encode(auth_key));
        Ok(vec![(
            headers::AUTHORIZATION.to_string(),
            auth_header.into_masked(),
        )])
    }

    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response: hipay::HipayErrorResponse =
            res.response
                .parse_struct("HipayErrorResponse")
                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.code.to_string(),
            message: response.message,
            reason: response.description,
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}


impl api::PaymentCapture for Santander {}

impl api::PaymentCapture for for Santander


pub struct LabelWithStatusEliminationEventResponse {
    pub label: String,
    pub elimination_information: Option<EliminationInformationEventResponse>,
}


Documentation: api-reference/v2/payments/payments--confirm-intent.mdx
# Type: Doc File

---
openapi: post /v2/payments/{id}/confirm-intent
---


Documentation: crates/api_models/README.md
# Type: Doc File

# API Models

Request/response models for the `router` crate.


pub struct VoidStatus {
    pub authorization: SilverflowVoidAuthorizationStatus,
}


pub struct ArchipelWalletInformation {
    wallet_indicator: Option<String>,
    wallet_provider: ArchipelWalletProvider,
    wallet_cryptogram: Secret<String>,
}


pub struct ExchangeTokenRequest {
    pub public_token: String,
}


File: crates/openapi/src/routes/poll.rs
 Public functions: 1

/// Poll - Retrieve Poll Status
#[utoipa::path(
    get,
    path = "/poll/status/{poll_id}",
    params(
        ("poll_id" = String, Path, description = "The identifier for poll")
    ),
    responses(
        (status = 200, description = "The poll status was retrieved successfully", body = PollResponse),
        (status = 404, description = "Poll not found")
    ),
    tag = "Poll",
    operation_id = "Retrieve Poll Status",
    security(("publishable_key" = []))
)]
pub async fn retrieve_poll_status() {}


    let router_data = payment_data
        .construct_router_data(
            state,
            connector.connector.id(),
            merchant_context,
            customer,
            &merchant_connector_account_type_details,
            None,
            None,
        )
        .await?;

    Ok((
        merchant_connector_account_type_details,
        updated_customer,
        router_data,
    ))
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
#[allow(clippy::type_complexity)]
#[instrument(skip_all)]
pub async fn call_connector_service_prerequisites_for_external_vault_proxy<
    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,
    domain::MerchantConnectorAccountTypeDetails,
    Option<storage::CustomerUpdate>,
    RouterData<F, RouterDReq, router_types::PaymentsResponseData>,
)>
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>,
{
    // get merchant connector account related to external vault
    let external_vault_source: id_type::MerchantConnectorAccountId = business_profile
        .external_vault_connector_details
        .clone()
        .map(|connector_details| connector_details.vault_connector_id.clone())
        .ok_or(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("mca_id not present for external vault")?;

    let external_vault_merchant_connector_account_type_details =
        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorAccount(Box::new(
            helpers::get_merchant_connector_account_v2(
                state,
                merchant_context.get_merchant_key_store(),
                Some(&external_vault_source),
            )
            .await?,
        ));

    let (merchant_connector_account_type_details, updated_customer, router_data) =
        call_connector_service_prerequisites(
            state,
            req_state,
            merchant_context,
            connector,
            operation,
            payment_data,
            customer,
            call_connector_action,
            schedule_time,
            header_payload,
            frm_suggestion,
            business_profile,
            is_retry_payment,
            should_retry_with_pan,
            all_keys_required,
        )
        .await?;
    Ok((
        merchant_connector_account_type_details,
        external_vault_merchant_connector_account_type_details,
        updated_customer,
        router_data,
    ))
}

#[cfg(feature = "v2")]
#[instrument(skip_all)]
pub async fn internal_call_connector_service_prerequisites<F, RouterDReq, ApiRequest, D>(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    connector: api::ConnectorData,
    operation: &BoxedOperation<'_, F, ApiRequest, D>,
    payment_data: &mut D,
    business_profile: &domain::Profile,
) -> RouterResult<(
    domain::MerchantConnectorAccountTypeDetails,
    RouterData<F, RouterDReq, router_types::PaymentsResponseData>,
)>
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>,
{
    let merchant_connector_details =
        payment_data
            .get_merchant_connector_details()
            .ok_or_else(|| {
                error_stack::report!(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Merchant connector details not found in payment data")
            })?;
    let merchant_connector_account =
        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorDetails(
            merchant_connector_details,
        );

    operation
        .to_domain()?
        .populate_payment_data(
            state,
            payment_data,
            merchant_context,
            business_profile,
            &connector,
        )
        .await?;

    let router_data = payment_data
        .construct_router_data(
            state,
            connector.connector.id(),
            merchant_context,
            &None,
            &merchant_connector_account,
            None,
            None,
        )
        .await?;

    Ok((merchant_connector_account, router_data))
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
#[instrument(skip_all)]
pub async fn connector_service_decider<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,
    call_connector_action: CallConnectorAction,
    header_payload: HeaderPayload,
    business_profile: &domain::Profile,
    return_raw_connector_response: Option<bool>,
    merchant_connector_account_type_details: domain::MerchantConnectorAccountTypeDetails,
) -> RouterResult<RouterData<F, RouterDReq, router_types::PaymentsResponseData>>
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>,
{
    let mut router_data = payment_data
        .construct_router_data(
            state,
            connector.connector.id(),
            merchant_context,
            &None,
            &merchant_connector_account_type_details,
            None,
            None,
        )
        .await?;

    // do order creation
    let should_call_unified_connector_service = should_call_unified_connector_service(
        state,
        merchant_context,
        &router_data,
        Some(payment_data),
    )
    .await?;

    let (connector_request, should_continue_further) = if !should_call_unified_connector_service {
        let mut should_continue_further = true;

        let should_continue = match router_data
            .create_order_at_connector(state, &connector, should_continue_further)
            .await?
        {
            Some(create_order_response) => {
                if let Ok(order_id) = create_order_response.clone().create_order_result {
                    payment_data.set_connector_response_reference_id(Some(order_id))
                }

                // Set the response in routerdata response to carry forward
                router_data
                    .update_router_data_with_create_order_response(create_order_response.clone());
                create_order_response.create_order_result.ok().map(|_| ())
            }
            // If create order is not required, then we can proceed with further processing
            None => Some(()),
        };

        let should_continue: (Option<common_utils::request::Request>, bool) = match should_continue
        {
            Some(_) => {
                router_data
                    .build_flow_specific_connector_request(
                        state,
                        &connector,
                        call_connector_action.clone(),
                    )
                    .await?
            }
            None => (None, false),
        };
        should_continue
    } else {
        // If unified connector service is called, these values are not used
        // as the request is built in the unified connector service call
        (None, false)
    };

    (_, *payment_data) = operation
        .to_update_tracker()?
        .update_trackers(
            state,
            req_state,
            payment_data.clone(),
            None, // customer is not used in internal flows
            merchant_context.get_merchant_account().storage_scheme,
            None,
            merchant_context.get_merchant_key_store(),
            None, // frm_suggestion is not used in internal flows
            header_payload.clone(),
        )
        .await?;

    record_time_taken_with(|| async {
        if should_call_unified_connector_service {
            router_env::logger::info!(
                "Processing payment through UCS gateway system- payment_id={}, attempt_id={}",
                payment_data.get_payment_intent().id.get_string_repr(),
                payment_data.get_payment_attempt().id.get_string_repr()
            );

            router_data
                .call_unified_connector_service(
                    state,
                    merchant_connector_account_type_details.clone(),
                    merchant_context,
                )
                .await?;

            Ok(router_data)
        } else {
            Err(
                errors::ApiErrorResponse::InternalServerError
            )
            .attach_printable("Unified connector service is down and traditional connector service fallback is not implemented")
        }
    })
    .await
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
#[instrument(skip_all)]
pub async fn decide_unified_connector_service_call<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,
    return_raw_connector_response: Option<bool>,
    merchant_connector_account_type_details: domain::MerchantConnectorAccountTypeDetails,
    mut router_data: RouterData<F, RouterDReq, router_types::PaymentsResponseData>,
    updated_customer: Option<storage::CustomerUpdate>,
) -> RouterResult<RouterData<F, RouterDReq, router_types::PaymentsResponseData>>
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>,
{
    record_time_taken_with(|| async {
        if should_call_unified_connector_service(
            state,
            merchant_context,
            &router_data,
            Some(payment_data),
        )
        .await?
        {
            router_env::logger::info!(
                "Executing payment through UCS gateway system - payment_id={}, attempt_id={}",
                payment_data.get_payment_intent().id.get_string_repr(),
                payment_data.get_payment_attempt().id.get_string_repr()
            );
            if should_add_task_to_process_tracker(payment_data) {
                operation
                    .to_domain()?
                    .add_task_to_process_tracker(
                        state,
                        payment_data.get_payment_attempt(),
                        false,
                        schedule_time,
                    )
                    .await
                    .map_err(|error| logger::error!(process_tracker_error=?error))
                    .ok();
            }

            (_, *payment_data) = operation
                .to_update_tracker()?
                .update_trackers(
                    state,
                    req_state,
                    payment_data.clone(),
                    customer.clone(),
                    merchant_context.get_merchant_account().storage_scheme,
                    None,
                    merchant_context.get_merchant_key_store(),
                    frm_suggestion,
                    header_payload.clone(),
                )
                .await?;

            router_data
                .call_unified_connector_service(
                    state,
                    merchant_connector_account_type_details.clone(),
                    merchant_context,
                )
                .await?;

            Ok(router_data)
        } else {
            router_env::logger::info!(
                "Processing payment through Direct gateway system - payment_id={}, attempt_id={}",
                payment_data.get_payment_intent().id.get_string_repr(),
                payment_data.get_payment_attempt().id.get_string_repr()
            );

            call_connector_service(
                state,
                req_state,
                merchant_context,
                connector,
                operation,
                payment_data,
                customer,
                call_connector_action,
                schedule_time,
                header_payload,
                frm_suggestion,
                business_profile,
                is_retry_payment,
                should_retry_with_pan,
                return_raw_connector_response,
                merchant_connector_account_type_details,
                router_data,
                updated_customer,
            )
            .await
        }
    })
    .await
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
#[instrument(skip_all)]
pub async fn call_unified_connector_service_for_external_proxy<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,
    _return_raw_connector_response: Option<bool>,
    merchant_connector_account_type_details: domain::MerchantConnectorAccountTypeDetails,
    external_vault_merchant_connector_account_type_details: domain::MerchantConnectorAccountTypeDetails,
    mut router_data: RouterData<F, RouterDReq, router_types::PaymentsResponseData>,
    _updated_customer: Option<storage::CustomerUpdate>,
) -> RouterResult<RouterData<F, RouterDReq, router_types::PaymentsResponseData>>
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>,
{
    record_time_taken_with(|| async {
        (_, *payment_data) = operation
            .to_update_tracker()?
            .update_trackers(
                state,
                req_state,
                payment_data.clone(),
                customer.clone(),
                merchant_context.get_merchant_account().storage_scheme,
                None,
                merchant_context.get_merchant_key_store(),
                frm_suggestion,
                header_payload.clone(),
            )
            .await?;

        router_data
            .call_unified_connector_service_with_external_vault_proxy(
                state,
                merchant_connector_account_type_details.clone(),
                external_vault_merchant_connector_account_type_details.clone(),
                merchant_context,
            )
            .await?;

        Ok(router_data)
    })
    .await
}

#[cfg(feature = "v1")]
// This function does not perform the tokenization action, as the payment method is not saved in this flow.
#[allow(clippy::too_many_arguments)]
#[instrument(skip_all)]
pub async fn proxy_for_call_connector_service<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,
    validate_result: &operations::ValidateResult,
    schedule_time: Option<time::PrimitiveDateTime>,
    header_payload: HeaderPayload,

    business_profile: &domain::Profile,
    return_raw_connector_response: Option<bool>,
) -> RouterResult<(
    RouterData<F, RouterDReq, router_types::PaymentsResponseData>,
    helpers::MerchantConnectorAccountType,
)>
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>,
{
    let stime_connector = Instant::now();

    let merchant_connector_account = construct_profile_id_and_get_mca(
        state,
        merchant_context,
        payment_data,
        &connector.connector_name.to_string(),
        connector.merchant_connector_id.as_ref(),
        false,
    )
    .await?;

    if payment_data
        .get_payment_attempt()
        .merchant_connector_id
        .is_none()
    {
        payment_data.set_merchant_connector_id_in_attempt(merchant_connector_account.get_mca_id());
    }

    let merchant_recipient_data = None;

    let mut router_data = payment_data
        .construct_router_data(
            state,
            connector.connector.id(),
            merchant_context,
            customer,
            &merchant_connector_account,
            merchant_recipient_data,
            None,
        )
        .await?;

    let add_access_token_result = router_data
        .add_access_token(
            state,
            &connector,
            merchant_context,
            payment_data.get_creds_identifier(),
        )
        .await?;

    router_data = router_data.add_session_token(state, &connector).await?;

    let mut should_continue_further = access_token::update_router_data_with_access_token_result(
        &add_access_token_result,
        &mut router_data,
        &call_connector_action,
    );

    (router_data, should_continue_further) = complete_preprocessing_steps_if_required(
        state,
        &connector,
        payment_data,
        router_data,
        operation,
        should_continue_further,
    )
    .await?;

    if let Ok(router_types::PaymentsResponseData::PreProcessingResponse {
        session_token: Some(session_token),
        ..
    }) = router_data.response.to_owned()
    {
        payment_data.push_sessions_token(session_token);
    };

    let (connector_request, should_continue_further) = if should_continue_further {
        // Check if the actual flow specific request can be built with available data
        router_data
            .build_flow_specific_connector_request(state, &connector, call_connector_action.clone())
            .await?
    } else {
        (None, false)
    };

    if should_add_task_to_process_tracker(payment_data) {
        operation
            .to_domain()?
            .add_task_to_process_tracker(
                state,
                payment_data.get_payment_attempt(),
                validate_result.requeue,
                schedule_time,
            )
            .await
            .map_err(|error| logger::error!(process_tracker_error=?error))
            .ok();
    }

    let updated_customer = None;
    let frm_suggestion = None;

    (_, *payment_data) = operation
        .to_update_tracker()?
        .update_trackers(
            state,
            req_state,
            payment_data.clone(),
            customer.clone(),
            merchant_context.get_merchant_account().storage_scheme,
            updated_customer,
            merchant_context.get_merchant_key_store(),
            frm_suggestion,
            header_payload.clone(),
        )
        .await?;

    let router_data = if should_continue_further {
        // The status of payment_attempt and intent will be updated in the previous step
        // update this in router_data.
        // This is added because few connector integrations do not update the status,
        // and rely on previous status set in router_data
        router_data.status = payment_data.get_payment_attempt().status;
        router_data
            .decide_flows(
                state,
                &connector,
                call_connector_action,
                connector_request,
                business_profile,
                header_payload.clone(),
                return_raw_connector_response,
            )
            .await
    } else {
        Ok(router_data)
    }?;

    let etime_connector = Instant::now();
    let duration_connector = etime_connector.saturating_duration_since(stime_connector);
    tracing::info!(duration = format!("Duration taken: {}", duration_connector.as_millis()));

    Ok((router_data, merchant_connector_account))
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
#[instrument(skip_all)]
pub async fn proxy_for_call_connector_service<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,
    call_connector_action: CallConnectorAction,
    header_payload: HeaderPayload,
    business_profile: &domain::Profile,
    return_raw_connector_response: Option<bool>,
) -> RouterResult<RouterData<F, RouterDReq, router_types::PaymentsResponseData>>
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>,
{
    let stime_connector = Instant::now();

    let merchant_connector_account =
        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorAccount(Box::new(
            helpers::get_merchant_connector_account_v2(
                state,
                merchant_context.get_merchant_key_store(),
                connector.merchant_connector_id.as_ref(),
            )
            .await?,
        ));
    operation
        .to_domain()?
        .populate_payment_data(
            state,
            payment_data,
            merchant_context,
            business_profile,
            &connector,
        )
        .await?;

    let mut router_data = payment_data
        .construct_router_data(
            state,
            connector.connector.id(),
            merchant_context,
            &None,
            &merchant_connector_account,
            None,
            None,
        )
        .await?;

    let add_access_token_result = router_data
        .add_access_token(
            state,
            &connector,
            merchant_context,
            payment_data.get_creds_identifier(),
        )
        .await?;

    router_data = router_data.add_session_token(state, &connector).await?;

    let mut should_continue_further = access_token::update_router_data_with_access_token_result(
        &add_access_token_result,
        &mut router_data,
        &call_connector_action,
    );

    let (connector_request, should_continue_further) = if should_continue_further {
        router_data
            .build_flow_specific_connector_request(state, &connector, call_connector_action.clone())
            .await?
    } else {
        (None, false)
    };

    (_, *payment_data) = operation
        .to_update_tracker()?
        .update_trackers(
            state,
            req_state,
            payment_data.clone(),
            None,
            merchant_context.get_merchant_account().storage_scheme,
            None,
            merchant_context.get_merchant_key_store(),
            None,
            header_payload.clone(),
        )
        .await?;

    let router_data = if should_continue_further {
        router_data
            .decide_flows(
                state,
                &connector,
                call_connector_action,
                connector_request,
                business_profile,
                header_payload.clone(),
                return_raw_connector_response,
            )
            .await
    } else {
        Ok(router_data)
    }?;

    let etime_connector = Instant::now();
    let duration_connector = etime_connector.saturating_duration_since(stime_connector);
    tracing::info!(duration = format!("Duration taken: {}", duration_connector.as_millis()));

    Ok(router_data)
}

#[cfg(feature = "v2")]
#[allow(clippy::too_many_arguments)]
#[instrument(skip_all)]
pub async fn call_connector_service_for_external_vault_proxy<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,
    call_connector_action: CallConnectorAction,
    header_payload: HeaderPayload,
    business_profile: &domain::Profile,
    return_raw_connector_response: Option<bool>,
) -> RouterResult<RouterData<F, RouterDReq, router_types::PaymentsResponseData>>
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>,
{
    let stime_connector = Instant::now();

    let merchant_connector_account =
        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorAccount(Box::new(
            helpers::get_merchant_connector_account_v2(
                state,
                merchant_context.get_merchant_key_store(),
                connector.merchant_connector_id.as_ref(),
            )
            .await?,
        ));
    operation
        .to_domain()?
        .populate_payment_data(
            state,
            payment_data,
            merchant_context,
            business_profile,
            &connector,
        )
        .await?;

    let mut router_data = payment_data
        .construct_router_data(
            state,
            connector.connector.id(),
            merchant_context,
            &None,
            &merchant_connector_account,
            None,
            None,
        )
        .await?;

    // let add_access_token_result = router_data
    //     .add_access_token(
    //         state,
    //         &connector,
    //         merchant_context,
    //         payment_data.get_creds_identifier(),
    //     )
    //     .await?;

    // router_data = router_data.add_session_token(state, &connector).await?;

    // let mut should_continue_further = access_token::update_router_data_with_access_token_result(
    //     &add_access_token_result,
    //     &mut router_data,
    //     &call_connector_action,
    // );
    let should_continue_further = true;

    let (connector_request, should_continue_further) = if should_continue_further {
        router_data
            .build_flow_specific_connector_request(state, &connector, call_connector_action.clone())
            .await?
    } else {
        (None, false)
    };

    (_, *payment_data) = operation
        .to_update_tracker()?
        .update_trackers(
            state,
            req_state,
            payment_data.clone(),
            None,
            merchant_context.get_merchant_account().storage_scheme,
            None,
            merchant_context.get_merchant_key_store(),
            None,
            header_payload.clone(),
        )
        .await?;

    let router_data = if should_continue_further {
        router_data
            .decide_flows(
                state,
                &connector,
                call_connector_action,
                connector_request,
                business_profile,
                header_payload.clone(),
                return_raw_connector_response,
            )
            .await
    } else {
        Ok(router_data)
    }?;

    let etime_connector = Instant::now();
    let duration_connector = etime_connector.saturating_duration_since(stime_connector);
    tracing::info!(duration = format!("Duration taken: {}", duration_connector.as_millis()));

    Ok(router_data)
}
struct ApplePayWallet;
struct PazeWallet;
struct GooglePayWallet;

#[async_trait::async_trait]
pub trait WalletFlow<F, D>: Send + Sync
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + Send + Sync + Clone,
{
    /// Check if wallet data is already decrypted and return token if so
    fn check_predecrypted_token(
        &self,
        _payment_data: &D,
    ) -> CustomResult<Option<PaymentMethodToken>, errors::ApiErrorResponse> {
        // Default implementation returns None (no pre-decrypted data)
        Ok(None)
    }

    fn decide_wallet_flow(
        &self,
        state: &SessionState,
        payment_data: &D,
        merchant_connector_account: &helpers::MerchantConnectorAccountType,
    ) -> CustomResult<Option<DecideWalletFlow>, errors::ApiErrorResponse>;

    async fn decrypt_wallet_token(
        &self,
        wallet_flow: &DecideWalletFlow,
        payment_data: &D,
    ) -> CustomResult<PaymentMethodToken, errors::ApiErrorResponse>;
}

#[async_trait::async_trait]
impl<F, D> WalletFlow<F, D> for PazeWallet
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + Send + Sync + Clone,
{
    fn decide_wallet_flow(
        &self,
        state: &SessionState,
        _payment_data: &D,
        _merchant_connector_account: &helpers::MerchantConnectorAccountType,
    ) -> CustomResult<Option<DecideWalletFlow>, errors::ApiErrorResponse> {
        let paze_keys = state
            .conf
            .paze_decrypt_keys
            .as_ref()
            .get_required_value("Paze decrypt keys")
            .attach_printable("Paze decrypt keys not found in the configuration")?;

        let wallet_flow = DecideWalletFlow::PazeDecrypt(PazePaymentProcessingDetails {
            paze_private_key: paze_keys.get_inner().paze_private_key.clone(),
            paze_private_key_passphrase: paze_keys.get_inner().paze_private_key_passphrase.clone(),
        });
        Ok(Some(wallet_flow))
    }

    async fn decrypt_wallet_token(
        &self,
        wallet_flow: &DecideWalletFlow,
        payment_data: &D,
    ) -> CustomResult<PaymentMethodToken, errors::ApiErrorResponse> {
        let paze_payment_processing_details = wallet_flow
            .get_paze_payment_processing_details()
            .get_required_value("Paze payment processing details")
            .attach_printable(
                "Paze payment processing details not found in Paze decryption flow",
            )?;

        let paze_wallet_data = payment_data
                .get_payment_method_data()
                .and_then(|payment_method_data| payment_method_data.get_wallet_data())
                .and_then(|wallet_data| wallet_data.get_paze_wallet_data())
                .get_required_value("Paze wallet token").attach_printable(
                    "Paze wallet data not found in the payment method data during the Paze decryption flow",
                )?;

        let paze_data = decrypt_paze_token(
            paze_wallet_data.clone(),
            paze_payment_processing_details.paze_private_key.clone(),
            paze_payment_processing_details
                .paze_private_key_passphrase
                .clone(),
        )
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("failed to decrypt paze token")?;

        let paze_decrypted_data = paze_data
            .parse_value::<hyperswitch_domain_models::router_data::PazeDecryptedData>(
                "PazeDecryptedData",
            )
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("failed to parse PazeDecryptedData")?;
        Ok(PaymentMethodToken::PazeDecrypt(Box::new(
            paze_decrypted_data,
        )))
    }
}

#[async_trait::async_trait]
impl<F, D> WalletFlow<F, D> for ApplePayWallet
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + Send + Sync + Clone,
{
    fn check_predecrypted_token(
        &self,
        payment_data: &D,
    ) -> CustomResult<Option<PaymentMethodToken>, errors::ApiErrorResponse> {
        let apple_pay_wallet_data = payment_data
            .get_payment_method_data()
            .and_then(|payment_method_data| payment_method_data.get_wallet_data())
            .and_then(|wallet_data| wallet_data.get_apple_pay_wallet_data());

        let result = if let Some(data) = apple_pay_wallet_data {
            match &data.payment_data {
                common_payments_types::ApplePayPaymentData::Encrypted(_) => None,
                common_payments_types::ApplePayPaymentData::Decrypted(
                    apple_pay_predecrypt_data,
                ) => {
                    helpers::validate_card_expiry(
                        &apple_pay_predecrypt_data.application_expiration_month,
                        &apple_pay_predecrypt_data.application_expiration_year,
                    )?;
                    Some(PaymentMethodToken::ApplePayDecrypt(Box::new(
                        apple_pay_predecrypt_data.clone(),
                    )))
                }
            }
        } else {
            None
        };
        Ok(result)
    }

    fn decide_wallet_flow(
        &self,
        state: &SessionState,
        payment_data: &D,
        merchant_connector_account: &helpers::MerchantConnectorAccountType,
    ) -> CustomResult<Option<DecideWalletFlow>, errors::ApiErrorResponse> {
        let apple_pay_metadata = check_apple_pay_metadata(state, Some(merchant_connector_account));

        add_apple_pay_flow_metrics(
            &apple_pay_metadata,
            payment_data.get_payment_attempt().connector.clone(),
            payment_data.get_payment_attempt().merchant_id.clone(),
        );

        let wallet_flow = match apple_pay_metadata {
            Some(domain::ApplePayFlow::Simplified(payment_processing_details)) => Some(
                DecideWalletFlow::ApplePayDecrypt(payment_processing_details),
            ),
            Some(domain::ApplePayFlow::Manual) | None => None,
        };
        Ok(wallet_flow)
    }

    async fn decrypt_wallet_token(
        &self,
        wallet_flow: &DecideWalletFlow,
        payment_data: &D,
    ) -> CustomResult<PaymentMethodToken, errors::ApiErrorResponse> {
        let apple_pay_payment_processing_details = wallet_flow
            .get_apple_pay_payment_processing_details()
            .get_required_value("Apple Pay payment processing details")
            .attach_printable(
                "Apple Pay payment processing details not found in Apple Pay decryption flow",
            )?;
        let apple_pay_wallet_data = payment_data
                .get_payment_method_data()
                .and_then(|payment_method_data| payment_method_data.get_wallet_data())
                .and_then(|wallet_data| wallet_data.get_apple_pay_wallet_data())
                .get_required_value("Apple Pay wallet token").attach_printable(
                    "Apple Pay wallet data not found in the payment method data during the Apple Pay decryption flow",
                )?;

        let apple_pay_data =
            ApplePayData::token_json(domain::WalletData::ApplePay(apple_pay_wallet_data.clone()))
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("failed to parse apple pay token to json")?
                .decrypt(
                    &apple_pay_payment_processing_details.payment_processing_certificate,
                    &apple_pay_payment_processing_details.payment_processing_certificate_key,
                )
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("failed to decrypt apple pay token")?;

        let apple_pay_predecrypt_internal = apple_pay_data
            .parse_value::<hyperswitch_domain_models::router_data::ApplePayPredecryptDataInternal>(
                "ApplePayPredecryptDataInternal",
            )
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable(
                "failed to parse decrypted apple pay response to ApplePayPredecryptData",
            )?;

        let apple_pay_predecrypt =
            common_types::payments::ApplePayPredecryptData::try_from(apple_pay_predecrypt_internal)
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable(
                    "failed to convert ApplePayPredecryptDataInternal to ApplePayPredecryptData",
                )?;

        Ok(PaymentMethodToken::ApplePayDecrypt(Box::new(
            apple_pay_predecrypt,
        )))
    }
}

#[async_trait::async_trait]
impl<F, D> WalletFlow<F, D> for GooglePayWallet
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + Send + Sync + Clone,
{
    fn check_predecrypted_token(
        &self,
        payment_data: &D,
    ) -> CustomResult<Option<PaymentMethodToken>, errors::ApiErrorResponse> {
        let google_pay_wallet_data = payment_data
            .get_payment_method_data()


impl api::MandateSetup for Inespay {}


impl ConnectorAuthenticationMap {
    pub fn inner(&self) -> &HashMap<String, ConnectorAuthType> {
        &self.0
    }

    /// # Panics
    ///
    /// Will panic if `CONNECTOR_AUTH_FILE_PATH` env  is not set
    #[allow(clippy::expect_used)]
    pub fn new() -> Self {
        // Do `export CONNECTOR_AUTH_FILE_PATH="/hyperswitch/crates/router/tests/connectors/sample_auth.toml"`
        // before running tests in shell
        let path = env::var("CONNECTOR_AUTH_FILE_PATH")
            .expect("connector authentication file path not set");

        // Read the file contents to a JsonString
        let contents =
            &std::fs::read_to_string(path).expect("Failed to read connector authentication file");

        // Deserialize the JsonString to a HashMap
        let auth_config: HashMap<String, toml::Value> =
            toml::from_str(contents).expect("Failed to deserialize TOML file");

        // auth_config contains the data in below given format:
        // {
        //  "connector_name": Table(
        //      {
        //          "api_key": String(
        //                 "API_Key",
        //          ),
        //          "api_secret": String(
        //              "Secret key",
        //          ),
        //          "key1": String(
        //                  "key1",
        //          ),
        //          "key2": String(
        //              "key2",
        //          ),
        //      },
        //  ),
        // "connector_name": Table(
        //  ...
        // }

        // auth_map refines and extracts required information
        let auth_map = auth_config
            .into_iter()
            .map(|(connector_name, config)| {
                let auth_type = match config {
                    toml::Value::Table(mut table) => {
                        if let Some(auth_key_map_value) = table.remove("auth_key_map") {
                            // This is a CurrencyAuthKey
                            if let toml::Value::Table(auth_key_map_table) = auth_key_map_value {
                                let mut parsed_auth_map = HashMap::new();
                                for (currency, val) in auth_key_map_table {
                                    if let Ok(currency_enum) =
                                        currency.parse::<common_enums::Currency>()
                                    {
                                        parsed_auth_map
                                            .insert(currency_enum, Secret::new(val.to_string()));
                                    }
                                }
                                ConnectorAuthType::CurrencyAuthKey {
                                    auth_key_map: parsed_auth_map,
                                }
                            } else {
                                ConnectorAuthType::NoKey
                            }
                        } else {
                            match (
                                table.get("api_key"),
                                table.get("key1"),
                                table.get("api_secret"),
                                table.get("key2"),
                            ) {
                                (Some(api_key), None, None, None) => ConnectorAuthType::HeaderKey {
                                    api_key: Secret::new(
                                        api_key.as_str().unwrap_or_default().to_string(),
                                    ),
                                },
                                (Some(api_key), Some(key1), None, None) => {
                                    ConnectorAuthType::BodyKey {
                                        api_key: Secret::new(
                                            api_key.as_str().unwrap_or_default().to_string(),
                                        ),
                                        key1: Secret::new(
                                            key1.as_str().unwrap_or_default().to_string(),
                                        ),
                                    }
                                }
                                (Some(api_key), Some(key1), Some(api_secret), None) => {
                                    ConnectorAuthType::SignatureKey {
                                        api_key: Secret::new(
                                            api_key.as_str().unwrap_or_default().to_string(),
                                        ),
                                        key1: Secret::new(
                                            key1.as_str().unwrap_or_default().to_string(),
                                        ),
                                        api_secret: Secret::new(
                                            api_secret.as_str().unwrap_or_default().to_string(),
                                        ),
                                    }
                                }
                                (Some(api_key), Some(key1), Some(api_secret), Some(key2)) => {
                                    ConnectorAuthType::MultiAuthKey {
                                        api_key: Secret::new(
                                            api_key.as_str().unwrap_or_default().to_string(),
                                        ),
                                        key1: Secret::new(
                                            key1.as_str().unwrap_or_default().to_string(),
                                        ),
                                        api_secret: Secret::new(
                                            api_secret.as_str().unwrap_or_default().to_string(),
                                        ),
                                        key2: Secret::new(
                                            key2.as_str().unwrap_or_default().to_string(),
                                        ),
                                    }
                                }
                                _ => ConnectorAuthType::NoKey,
                            }
                        }
                    }
                    _ => ConnectorAuthType::NoKey,
                };
                (connector_name, auth_type)
            })
            .collect();
        Self(auth_map)
    }
}


/// Verifies that the client configuration is usable
    pub fn validate(&self) -> Result<(), InvalidCrmConfig> {
        match self {
            Self::HubspotProxy { hubspot_proxy } => hubspot_proxy.validate(),
            Self::NoCrm => Ok(()),
        }
    }


File: crates/analytics/src/auth_events/metrics/challenge_flow_count.rs

use std::collections::HashSet;

use api_models::analytics::{
    auth_events::{AuthEventDimensions, AuthEventFilters, AuthEventMetricsBucketIdentifier},
    Granularity, TimeRange,
};
use common_enums::DecoupledAuthenticationType;
use common_utils::errors::ReportSwitchExt;
use error_stack::ResultExt;
use time::PrimitiveDateTime;

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

#[derive(Default)]
pub(super) struct ChallengeFlowCount;

#[async_trait::async_trait]
impl<T> super::AuthEventMetric<T> for ChallengeFlowCount
where
    T: AnalyticsDataSource + super::AuthEventMetricAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,
{
    async fn load_metrics(
        &self,
        auth: &AuthInfo,
        dimensions: &[AuthEventDimensions],
        filters: &AuthEventFilters,
        granularity: Option<Granularity>,
        time_range: &TimeRange,
        pool: &T,
    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
        let mut query_builder: QueryBuilder<T> =
            QueryBuilder::new(AnalyticsCollection::Authentications);
        for dim in dimensions.iter() {
            query_builder.add_select_column(dim).switch()?;
        }
        query_builder
            .add_select_column(Aggregate::Count {
                field: None,
                alias: Some("count"),
            })
            .switch()?;

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

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

        query_builder
            .add_filter_clause(
                "authentication_type",
                DecoupledAuthenticationType::Challenge,
            )
            .switch()?;
        filters.set_filter_clause(&mut query_builder).switch()?;
        time_range
            .set_filter_clause(&mut query_builder)
            .attach_printable("Error filtering time range")
            .switch()?;
        auth.set_filter_clause(&mut query_builder).switch()?;

        for dim in dimensions.iter() {
            query_builder
                .add_group_by_clause(dim)
                .attach_printable("Error grouping by dimensions")
                .switch()?;
        }
        if let Some(granularity) = granularity {
            granularity
                .set_group_by_clause(&mut query_builder)
                .attach_printable("Error adding granularity")
                .switch()?;
        }

        query_builder
            .execute_query::<AuthEventMetricRow, _>(pool)
            .await
            .change_context(MetricsError::QueryBuildingError)?
            .change_context(MetricsError::QueryExecutionFailure)?
            .into_iter()
            .map(|i| {
                Ok((
                    AuthEventMetricsBucketIdentifier::new(
                        i.authentication_status.as_ref().map(|i| i.0),
                        i.trans_status.as_ref().map(|i| i.0.clone()),
                        i.authentication_type.as_ref().map(|i| i.0),
                        i.error_message.clone(),
                        i.authentication_connector.as_ref().map(|i| i.0),
                        i.message_version.clone(),
                        i.acs_reference_number.clone(),
                        i.mcc.clone(),
                        i.currency.as_ref().map(|i| i.0),
                        i.merchant_country.clone(),
                        i.billing_country.clone(),
                        i.shipping_country.clone(),
                        i.issuer_country.clone(),
                        i.earliest_supported_version.clone(),
                        i.latest_supported_version.clone(),
                        i.whitelist_decision,
                        i.device_manufacturer.clone(),
                        i.device_type.clone(),
                        i.device_brand.clone(),
                        i.device_os.clone(),
                        i.device_display.clone(),
                        i.browser_name.clone(),
                        i.browser_version.clone(),
                        i.issuer_id.clone(),
                        i.scheme_name.clone(),
                        i.exemption_requested,
                        i.exemption_accepted,
                        TimeRange {
                            start_time: match (granularity, i.start_bucket) {
                                (Some(g), Some(st)) => g.clip_to_start(st)?,
                                _ => time_range.start_time,
                            },
                            end_time: granularity.as_ref().map_or_else(
                                || Ok(time_range.end_time),
                                |g| i.end_bucket.map(|et| g.clip_to_end(et)).transpose(),
                            )?,
                        },
                    ),
                    i,
                ))
            })
            .collect::<error_stack::Result<
                HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
                crate::query::PostProcessingError,
            >>()
            .change_context(MetricsError::PostProcessingFailure)
    }
}


impl OpenSearchAuth {
    pub fn validate(&self) -> Result<(), ApplicationError> {
        use common_utils::{ext_traits::ConfigExt, fp_utils::when};

        match self {
            Self::Basic { username, password } => {
                when(username.is_default_or_empty(), || {
                    Err(ApplicationError::InvalidConfigurationValueError(
                        "Opensearch Basic auth username must not be empty".into(),
                    ))
                })?;

                when(password.is_default_or_empty(), || {
                    Err(ApplicationError::InvalidConfigurationValueError(
                        "Opensearch Basic auth password must not be empty".into(),
                    ))
                })?;
            }

            Self::Aws { region } => {
                when(region.is_default_or_empty(), || {
                    Err(ApplicationError::InvalidConfigurationValueError(
                        "Opensearch Aws auth region must not be empty".into(),
                    ))
                })?;
            }
        };

        Ok(())
    }
}


pub struct PaymentConfirmData<F>
where
    F: Clone,
{
    pub flow: PhantomData<F>,
    pub payment_intent: PaymentIntent,
    pub payment_attempt: PaymentAttempt,
    pub payment_method_data: Option<payment_method_data::PaymentMethodData>,
    pub payment_address: payment_address::PaymentAddress,
    pub mandate_data: Option<api_models::payments::MandateIds>,
    pub payment_method: Option<payment_methods::PaymentMethod>,
    pub merchant_connector_details: Option<common_types::domain::MerchantConnectorAuthDetails>,
    pub external_vault_pmd: Option<payment_method_data::ExternalVaultPaymentMethodData>,
}


pub fn from_storage(refund: &'a Refund) -> Self {
        Self {
            internal_reference_id: &refund.internal_reference_id,
            refund_id: &refund.refund_id,
            payment_id: &refund.payment_id,
            merchant_id: &refund.merchant_id,
            connector_transaction_id: refund.get_connector_transaction_id(),
            connector: &refund.connector,
            connector_refund_id: refund.get_optional_connector_refund_id(),
            external_reference_id: refund.external_reference_id.as_ref(),
            refund_type: &refund.refund_type,
            total_amount: &refund.total_amount,
            currency: &refund.currency,
            refund_amount: &refund.refund_amount,
            refund_status: &refund.refund_status,
            sent_to_gateway: &refund.sent_to_gateway,
            refund_error_message: refund.refund_error_message.as_ref(),
            refund_arn: refund.refund_arn.as_ref(),
            created_at: refund.created_at.assume_utc(),
            modified_at: refund.modified_at.assume_utc(),
            description: refund.description.as_ref(),
            attempt_id: &refund.attempt_id,
            refund_reason: refund.refund_reason.as_ref(),
            refund_error_code: refund.refund_error_code.as_ref(),
            profile_id: refund.profile_id.as_ref(),
            organization_id: &refund.organization_id,
        }
    }