impl EmailData for VerifyEmail {
    async fn get_email_data(&self, base_url: &str) -> CustomResult<EmailContents, EmailError> {
        let token = EmailToken::new_token(
            self.recipient_email.clone(),
            None,
            domain::Origin::VerifyEmail,
            &self.settings,
        )
        .await
        .change_context(EmailError::TokenGenerationFailure)?;

        let verify_email_link = get_link_with_token(
            base_url,
            token,
            "verify_email",
            &self.auth_id,
            &self.theme_id,
        );

        let body = html::get_html_body(EmailBody::Verify {
            link: verify_email_link,
            entity_name: self.theme_config.entity_name.clone(),
            entity_logo_url: self.theme_config.entity_logo_url.clone(),
            primary_color: self.theme_config.primary_color.clone(),
            background_color: self.theme_config.background_color.clone(),
            foreground_color: self.theme_config.foreground_color.clone(),
        });

        Ok(EmailContents {
            subject: format!(
                "Welcome to the {} community!",
                self.theme_config.entity_name
            ),
            body: external_services::email::IntermediateString::new(body),
            recipient: self.recipient_email.clone().into_inner(),
        })
    }
}


pub struct PaymentRoutingInfoInner {
    pub algorithm: Option<routing::StraightThroughAlgorithm>,
    pub pre_routing_results:
        Option<HashMap<api_enums::PaymentMethodType, PreRoutingConnectorChoice>>,
}


pub async fn update_payment_method(
        &self,
        store_token_response: &pm_transformers::StoreCardRespPayload,
        payment_method: domain::PaymentMethod,
        network_token_details: &NetworkTokenizationResponse,
        card_details: &domain::CardDetail,
    ) -> RouterResult<domain::PaymentMethod> {
        // Form encrypted network token data
        let enc_token_data = self
            .encrypt_network_token(network_token_details, card_details, true)
            .await?;

        // Update payment method
        let payment_method_update = diesel_models::PaymentMethodUpdate::NetworkTokenDataUpdate {
            network_token_requestor_reference_id: network_token_details.1.clone(),
            network_token_locker_id: Some(store_token_response.card_reference.clone()),
            network_token_payment_method_data: Some(enc_token_data.into()),
        };
        self.state
            .store
            .update_payment_method(
                &self.state.into(),
                self.key_store,
                payment_method,
                payment_method_update,
                self.merchant_account.storage_scheme,
            )
            .await
            .inspect_err(|err| logger::info!("Error updating payment method: {:?}", err))
            .change_context(errors::ApiErrorResponse::InternalServerError)
    }


File: crates/router/src/core/payments/flows/post_session_tokens_flow.rs

use async_trait::async_trait;

use super::ConstructFlowSpecificData;
use crate::{
    core::{
        errors::{ConnectorErrorExt, RouterResult},
        payments::{self, access_token, helpers, transformers, Feature, PaymentData},
    },
    routes::SessionState,
    services,
    types::{self, api, domain},
};

#[async_trait]
impl
    ConstructFlowSpecificData<
        api::PostSessionTokens,
        types::PaymentsPostSessionTokensData,
        types::PaymentsResponseData,
    > for PaymentData<api::PostSessionTokens>
{
    #[cfg(feature = "v1")]
    async fn construct_router_data<'a>(
        &self,
        state: &SessionState,
        connector_id: &str,
        merchant_context: &domain::MerchantContext,
        customer: &Option<domain::Customer>,
        merchant_connector_account: &helpers::MerchantConnectorAccountType,
        merchant_recipient_data: Option<types::MerchantRecipientData>,
        header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
    ) -> RouterResult<types::PaymentsPostSessionTokensRouterData> {
        Box::pin(transformers::construct_payment_router_data::<
            api::PostSessionTokens,
            types::PaymentsPostSessionTokensData,
        >(
            state,
            self.clone(),
            connector_id,
            merchant_context,
            customer,
            merchant_connector_account,
            merchant_recipient_data,
            header_payload,
        ))
        .await
    }

    #[cfg(feature = "v2")]
    async fn construct_router_data<'a>(
        &self,
        state: &SessionState,
        connector_id: &str,
        merchant_context: &domain::MerchantContext,
        customer: &Option<domain::Customer>,
        merchant_connector_account: &domain::MerchantConnectorAccountTypeDetails,
        merchant_recipient_data: Option<types::MerchantRecipientData>,
        header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
    ) -> RouterResult<types::PaymentsPostSessionTokensRouterData> {
        todo!()
    }
}

#[async_trait]
impl Feature<api::PostSessionTokens, types::PaymentsPostSessionTokensData>
    for types::RouterData<
        api::PostSessionTokens,
        types::PaymentsPostSessionTokensData,
        types::PaymentsResponseData,
    >
{
    async fn decide_flows<'a>(
        self,
        state: &SessionState,
        connector: &api::ConnectorData,
        call_connector_action: payments::CallConnectorAction,
        connector_request: Option<services::Request>,
        _business_profile: &domain::Profile,
        _header_payload: hyperswitch_domain_models::payments::HeaderPayload,
        _return_raw_connector_response: Option<bool>,
    ) -> RouterResult<Self> {
        let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
            api::PostSessionTokens,
            types::PaymentsPostSessionTokensData,
            types::PaymentsResponseData,
        > = connector.connector.get_connector_integration();

        let resp = services::execute_connector_processing_step(
            state,
            connector_integration,
            &self,
            call_connector_action,
            connector_request,
            None,
        )
        .await
        .to_payment_failed_response()?;
        Ok(resp)
    }

    async fn add_access_token<'a>(
        &self,
        state: &SessionState,
        connector: &api::ConnectorData,
        merchant_context: &domain::MerchantContext,
        creds_identifier: Option<&str>,
    ) -> RouterResult<types::AddAccessTokenResult> {
        Box::pin(access_token::add_access_token(
            state,
            connector,
            merchant_context,
            self,
            creds_identifier,
        ))
        .await
    }

    async fn build_flow_specific_connector_request(
        &mut self,
        state: &SessionState,
        connector: &api::ConnectorData,
        call_connector_action: payments::CallConnectorAction,
    ) -> RouterResult<(Option<services::Request>, bool)> {
        let request = match call_connector_action {
            payments::CallConnectorAction::Trigger => {
                let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
                    api::PostSessionTokens,
                    types::PaymentsPostSessionTokensData,
                    types::PaymentsResponseData,
                > = connector.connector.get_connector_integration();

                connector_integration
                    .build_request(self, &state.conf.connectors)
                    .to_payment_failed_response()?
            }
            _ => None,
        };

        Ok((request, true))
    }
}


File: crates/router/src/services/kafka/payment_attempt.rs
 Public functions: 2
 Public structs: 2

#[cfg(feature = "v2")]
use common_types::payments;
#[cfg(feature = "v2")]
use common_utils::types;
use common_utils::{id_type, types::MinorUnit};
use diesel_models::enums as storage_enums;
#[cfg(feature = "v2")]
use diesel_models::payment_attempt;
#[cfg(feature = "v2")]
use hyperswitch_domain_models::{
    address, payments::payment_attempt::PaymentAttemptFeatureMetadata,
    router_response_types::RedirectForm,
};
use hyperswitch_domain_models::{
    mandates::MandateDetails, payments::payment_attempt::PaymentAttempt,
};
use time::OffsetDateTime;

#[cfg(feature = "v1")]
#[derive(serde::Serialize, Debug)]
pub struct KafkaPaymentAttempt<'a> {
    pub payment_id: &'a id_type::PaymentId,
    pub merchant_id: &'a id_type::MerchantId,
    pub attempt_id: &'a String,
    pub status: storage_enums::AttemptStatus,
    pub amount: MinorUnit,
    pub currency: Option<storage_enums::Currency>,
    pub save_to_locker: Option<bool>,
    pub connector: Option<&'a String>,
    pub error_message: Option<&'a String>,
    pub offer_amount: Option<MinorUnit>,
    pub surcharge_amount: Option<MinorUnit>,
    pub tax_amount: Option<MinorUnit>,
    pub payment_method_id: Option<&'a String>,
    pub payment_method: Option<storage_enums::PaymentMethod>,
    pub connector_transaction_id: Option<&'a String>,
    pub capture_method: Option<storage_enums::CaptureMethod>,
    #[serde(default, with = "time::serde::timestamp::option")]
    pub capture_on: Option<OffsetDateTime>,
    pub confirm: bool,
    pub authentication_type: Option<storage_enums::AuthenticationType>,
    #[serde(with = "time::serde::timestamp")]
    pub created_at: OffsetDateTime,
    #[serde(with = "time::serde::timestamp")]
    pub modified_at: OffsetDateTime,
    #[serde(default, with = "time::serde::timestamp::option")]
    pub last_synced: Option<OffsetDateTime>,
    pub cancellation_reason: Option<&'a String>,
    pub amount_to_capture: Option<MinorUnit>,
    pub mandate_id: Option<&'a String>,
    pub browser_info: Option<String>,
    pub error_code: Option<&'a String>,
    pub connector_metadata: Option<String>,
    // TODO: These types should implement copy ideally
    pub payment_experience: Option<&'a storage_enums::PaymentExperience>,
    pub payment_method_type: Option<&'a storage_enums::PaymentMethodType>,
    pub payment_method_data: Option<String>,
    pub error_reason: Option<&'a String>,
    pub multiple_capture_count: Option<i16>,
    pub amount_capturable: MinorUnit,
    pub merchant_connector_id: Option<&'a id_type::MerchantConnectorAccountId>,
    pub net_amount: MinorUnit,
    pub unified_code: Option<&'a String>,
    pub unified_message: Option<&'a String>,
    pub mandate_data: Option<&'a MandateDetails>,
    pub client_source: Option<&'a String>,
    pub client_version: Option<&'a String>,
    pub profile_id: &'a id_type::ProfileId,
    pub organization_id: &'a id_type::OrganizationId,
    pub card_network: Option<String>,
    pub card_discovery: Option<String>,
    pub routing_approach: Option<storage_enums::RoutingApproach>,
    pub debit_routing_savings: Option<MinorUnit>,
    pub signature_network: Option<common_enums::CardNetwork>,
    pub is_issuer_regulated: Option<bool>,
}

#[cfg(feature = "v1")]
impl<'a> KafkaPaymentAttempt<'a> {
    pub fn from_storage(attempt: &'a PaymentAttempt) -> Self {
        let card_payment_method_data = attempt
            .get_payment_method_data()
            .and_then(|data| data.get_additional_card_info());
        Self {
            payment_id: &attempt.payment_id,
            merchant_id: &attempt.merchant_id,
            attempt_id: &attempt.attempt_id,
            status: attempt.status,
            amount: attempt.net_amount.get_order_amount(),
            currency: attempt.currency,
            save_to_locker: attempt.save_to_locker,
            connector: attempt.connector.as_ref(),
            error_message: attempt.error_message.as_ref(),
            offer_amount: attempt.offer_amount,
            surcharge_amount: attempt.net_amount.get_surcharge_amount(),
            tax_amount: attempt.net_amount.get_tax_on_surcharge(),
            payment_method_id: attempt.payment_method_id.as_ref(),
            payment_method: attempt.payment_method,
            connector_transaction_id: attempt.connector_transaction_id.as_ref(),
            capture_method: attempt.capture_method,
            capture_on: attempt.capture_on.map(|i| i.assume_utc()),
            confirm: attempt.confirm,
            authentication_type: attempt.authentication_type,
            created_at: attempt.created_at.assume_utc(),
            modified_at: attempt.modified_at.assume_utc(),
            last_synced: attempt.last_synced.map(|i| i.assume_utc()),
            cancellation_reason: attempt.cancellation_reason.as_ref(),
            amount_to_capture: attempt.amount_to_capture,
            mandate_id: attempt.mandate_id.as_ref(),
            browser_info: attempt.browser_info.as_ref().map(|v| v.to_string()),
            error_code: attempt.error_code.as_ref(),
            connector_metadata: attempt.connector_metadata.as_ref().map(|v| v.to_string()),
            payment_experience: attempt.payment_experience.as_ref(),
            payment_method_type: attempt.payment_method_type.as_ref(),
            payment_method_data: attempt.payment_method_data.as_ref().map(|v| v.to_string()),
            error_reason: attempt.error_reason.as_ref(),
            multiple_capture_count: attempt.multiple_capture_count,
            amount_capturable: attempt.amount_capturable,
            merchant_connector_id: attempt.merchant_connector_id.as_ref(),
            net_amount: attempt.net_amount.get_total_amount(),
            unified_code: attempt.unified_code.as_ref(),
            unified_message: attempt.unified_message.as_ref(),
            mandate_data: attempt.mandate_data.as_ref(),
            client_source: attempt.client_source.as_ref(),
            client_version: attempt.client_version.as_ref(),
            profile_id: &attempt.profile_id,
            organization_id: &attempt.organization_id,
            card_network: attempt
                .payment_method_data
                .as_ref()
                .and_then(|data| data.as_object())
                .and_then(|pm| pm.get("card"))
                .and_then(|data| data.as_object())
                .and_then(|card| card.get("card_network"))
                .and_then(|network| network.as_str())
                .map(|network| network.to_string()),
            card_discovery: attempt
                .card_discovery
                .map(|discovery| discovery.to_string()),
            routing_approach: attempt.routing_approach.clone(),
            debit_routing_savings: attempt.debit_routing_savings,
            signature_network: card_payment_method_data
                .as_ref()
                .and_then(|data| data.signature_network.clone()),
            is_issuer_regulated: card_payment_method_data.and_then(|data| data.is_regulated),
        }
    }
}

#[cfg(feature = "v2")]
#[derive(serde::Serialize, Debug)]
pub struct KafkaPaymentAttempt<'a> {
    pub payment_id: &'a id_type::GlobalPaymentId,
    pub merchant_id: &'a id_type::MerchantId,
    pub attempt_id: &'a id_type::GlobalAttemptId,
    pub status: storage_enums::AttemptStatus,
    pub amount: MinorUnit,
    pub connector: Option<&'a String>,
    pub error_message: Option<&'a String>,
    pub surcharge_amount: Option<MinorUnit>,
    pub tax_amount: Option<MinorUnit>,
    pub payment_method_id: Option<&'a id_type::GlobalPaymentMethodId>,
    pub payment_method: storage_enums::PaymentMethod,
    pub connector_transaction_id: Option<&'a String>,
    pub authentication_type: storage_enums::AuthenticationType,
    #[serde(with = "time::serde::timestamp")]
    pub created_at: OffsetDateTime,
    #[serde(with = "time::serde::timestamp")]
    pub modified_at: OffsetDateTime,
    #[serde(default, with = "time::serde::timestamp::option")]
    pub last_synced: Option<OffsetDateTime>,
    pub cancellation_reason: Option<&'a String>,
    pub amount_to_capture: Option<MinorUnit>,
    pub browser_info: Option<&'a types::BrowserInformation>,
    pub error_code: Option<&'a String>,
    pub connector_metadata: Option<String>,
    // TODO: These types should implement copy ideally
    pub payment_experience: Option<&'a storage_enums::PaymentExperience>,
    pub payment_method_type: &'a storage_enums::PaymentMethodType,
    pub payment_method_data: Option<String>,
    pub error_reason: Option<&'a String>,
    pub multiple_capture_count: Option<i16>,
    pub amount_capturable: MinorUnit,
    pub merchant_connector_id: Option<&'a id_type::MerchantConnectorAccountId>,
    pub net_amount: MinorUnit,
    pub unified_code: Option<&'a String>,
    pub unified_message: Option<&'a String>,
    pub client_source: Option<&'a String>,
    pub client_version: Option<&'a String>,
    pub profile_id: &'a id_type::ProfileId,
    pub organization_id: &'a id_type::OrganizationId,
    pub card_network: Option<String>,
    pub card_discovery: Option<String>,

    pub connector_payment_id: Option<types::ConnectorTransactionId>,
    pub payment_token: Option<String>,
    pub preprocessing_step_id: Option<String>,
    pub connector_response_reference_id: Option<String>,
    pub updated_by: &'a String,
    pub encoded_data: Option<&'a masking::Secret<String>>,
    pub external_three_ds_authentication_attempted: Option<bool>,
    pub authentication_connector: Option<String>,
    pub authentication_id: Option<String>,
    pub fingerprint_id: Option<String>,
    pub customer_acceptance: Option<&'a masking::Secret<payments::CustomerAcceptance>>,
    pub shipping_cost: Option<MinorUnit>,
    pub order_tax_amount: Option<MinorUnit>,
    pub charges: Option<payments::ConnectorChargeResponseData>,
    pub processor_merchant_id: &'a id_type::MerchantId,
    pub created_by: Option<&'a types::CreatedBy>,
    pub payment_method_type_v2: storage_enums::PaymentMethod,
    pub payment_method_subtype: storage_enums::PaymentMethodType,
    pub routing_result: Option<serde_json::Value>,
    pub authentication_applied: Option<common_enums::AuthenticationType>,
    pub external_reference_id: Option<String>,
    pub tax_on_surcharge: Option<MinorUnit>,
    pub payment_method_billing_address: Option<masking::Secret<&'a address::Address>>, // adjusted from Encryption
    pub redirection_data: Option<&'a RedirectForm>,
    pub connector_payment_data: Option<String>,
    pub connector_token_details: Option<&'a payment_attempt::ConnectorTokenDetails>,
    pub feature_metadata: Option<&'a PaymentAttemptFeatureMetadata>,
    pub network_advice_code: Option<String>,
    pub network_decline_code: Option<String>,
    pub network_error_message: Option<String>,
    pub connector_request_reference_id: Option<String>,
}

#[cfg(feature = "v2")]
impl<'a> KafkaPaymentAttempt<'a> {
    pub fn from_storage(attempt: &'a PaymentAttempt) -> Self {
        use masking::PeekInterface;
        let PaymentAttempt {
            payment_id,
            merchant_id,
            amount_details,
            status,
            connector,
            error,
            authentication_type,
            created_at,
            modified_at,
            last_synced,
            cancellation_reason,
            browser_info,
            payment_token,
            connector_metadata,
            payment_experience,
            payment_method_data,
            routing_result,
            preprocessing_step_id,
            multiple_capture_count,
            connector_response_reference_id,
            updated_by,
            redirection_data,
            encoded_data,
            merchant_connector_id,
            external_three_ds_authentication_attempted,
            authentication_connector,
            authentication_id,
            fingerprint_id,
            client_source,
            client_version,
            customer_acceptance,
            profile_id,
            organization_id,
            payment_method_type,
            payment_method_id,
            connector_payment_id,
            payment_method_subtype,
            authentication_applied,
            external_reference_id,
            payment_method_billing_address,
            id,
            connector_token_details,
            card_discovery,
            charges,
            feature_metadata,
            processor_merchant_id,
            created_by,
            connector_request_reference_id,
            network_transaction_id: _,
        } = attempt;

        let (connector_payment_id, connector_payment_data) = connector_payment_id
            .clone()
            .map(types::ConnectorTransactionId::form_id_and_data)
            .map(|(txn_id, txn_data)| (Some(txn_id), txn_data))
            .unwrap_or((None, None));

        Self {
            payment_id,
            merchant_id,
            attempt_id: id,
            status: *status,
            amount: amount_details.get_net_amount(),
            connector: connector.as_ref(),
            error_message: error.as_ref().map(|error_details| &error_details.message),
            surcharge_amount: amount_details.get_surcharge_amount(),
            tax_amount: amount_details.get_tax_on_surcharge(),
            payment_method_id: payment_method_id.as_ref(),
            payment_method: *payment_method_type,
            connector_transaction_id: connector_response_reference_id.as_ref(),
            authentication_type: *authentication_type,
            created_at: created_at.assume_utc(),
            modified_at: modified_at.assume_utc(),
            last_synced: last_synced.map(|i| i.assume_utc()),
            cancellation_reason: cancellation_reason.as_ref(),
            amount_to_capture: amount_details.get_amount_to_capture(),
            browser_info: browser_info.as_ref(),
            error_code: error.as_ref().map(|error_details| &error_details.code),
            connector_metadata: connector_metadata.as_ref().map(|v| v.peek().to_string()),
            payment_experience: payment_experience.as_ref(),
            payment_method_type: payment_method_subtype,
            payment_method_data: payment_method_data.as_ref().map(|v| v.peek().to_string()),
            error_reason: error
                .as_ref()
                .and_then(|error_details| error_details.reason.as_ref()),
            multiple_capture_count: *multiple_capture_count,
            amount_capturable: amount_details.get_amount_capturable(),
            merchant_connector_id: merchant_connector_id.as_ref(),
            net_amount: amount_details.get_net_amount(),
            unified_code: error
                .as_ref()
                .and_then(|error_details| error_details.unified_code.as_ref()),
            unified_message: error
                .as_ref()
                .and_then(|error_details| error_details.unified_message.as_ref()),
            client_source: client_source.as_ref(),
            client_version: client_version.as_ref(),
            profile_id,
            organization_id,
            card_network: payment_method_data
                .as_ref()
                .map(|data| data.peek())
                .and_then(|data| data.as_object())
                .and_then(|pm| pm.get("card"))
                .and_then(|data| data.as_object())
                .and_then(|card| card.get("card_network"))
                .and_then(|network| network.as_str())
                .map(|network| network.to_string()),
            card_discovery: card_discovery.map(|discovery| discovery.to_string()),
            payment_token: payment_token.clone(),
            preprocessing_step_id: preprocessing_step_id.clone(),
            connector_response_reference_id: connector_response_reference_id.clone(),
            updated_by,
            encoded_data: encoded_data.as_ref(),
            external_three_ds_authentication_attempted: *external_three_ds_authentication_attempted,
            authentication_connector: authentication_connector.clone(),
            authentication_id: authentication_id
                .as_ref()
                .map(|id| id.get_string_repr().to_string().clone()),
            fingerprint_id: fingerprint_id.clone(),
            customer_acceptance: customer_acceptance.as_ref(),
            shipping_cost: amount_details.get_shipping_cost(),
            order_tax_amount: amount_details.get_order_tax_amount(),
            charges: charges.clone(),
            processor_merchant_id,
            created_by: created_by.as_ref(),
            payment_method_type_v2: *payment_method_type,
            connector_payment_id: connector_payment_id.as_ref().cloned(),
            payment_method_subtype: *payment_method_subtype,
            routing_result: routing_result.clone(),
            authentication_applied: *authentication_applied,
            external_reference_id: external_reference_id.clone(),
            tax_on_surcharge: amount_details.get_tax_on_surcharge(),
            payment_method_billing_address: payment_method_billing_address
                .as_ref()
                .map(|v| masking::Secret::new(v.get_inner())),
            redirection_data: redirection_data.as_ref(),
            connector_payment_data,
            connector_token_details: connector_token_details.as_ref(),
            feature_metadata: feature_metadata.as_ref(),
            network_advice_code: error
                .as_ref()
                .and_then(|details| details.network_advice_code.clone()),
            network_decline_code: error
                .as_ref()
                .and_then(|details| details.network_decline_code.clone()),
            network_error_message: error
                .as_ref()
                .and_then(|details| details.network_error_message.clone()),
            connector_request_reference_id: connector_request_reference_id.clone(),
        }
    }
}

impl super::KafkaMessage for KafkaPaymentAttempt<'_> {
    #[cfg(feature = "v1")]
    fn key(&self) -> String {
        format!(
            "{}_{}_{}",
            self.merchant_id.get_string_repr(),
            self.payment_id.get_string_repr(),
            self.attempt_id
        )
    }
    #[cfg(feature = "v2")]
    fn key(&self) -> String {
        format!(
            "{}_{}_{}",
            self.merchant_id.get_string_repr(),
            self.payment_id.get_string_repr(),
            self.attempt_id.get_string_repr()
        )
    }

    fn event_type(&self) -> crate::events::EventType {
        crate::events::EventType::PaymentAttempt
    }
}


pub async fn payment_method_delete_api() {}


impl Responder {
    let flow = Flow::CreateConfigKey;
    let payload = json_payload.into_inner();

    api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, _, data, _| configs::set_config(state, data),
        &ADMIN_API_AUTH,
        api_locking::LockAction::NotApplicable,
    )
    .await
}


pub struct JpmorganAuthType {
    pub(super) _api_key: Secret<String>,
    pub(super) _key1: Secret<String>,
}


pub struct ThreeDsResponse {
    pub outcome: String,
    pub issuer_response: IssuerResponse,
}


pub struct SelfLinkInner {
    pub href: String,
}


#[proc_macro_derive(EnumNums)]
pub fn enum_nums(ts: TokenStream) -> TokenStream {
    inner::enum_nums_inner(ts)
}


File: crates/kgraph_utils/benches/evaluation.rs

#![allow(unused, clippy::expect_used)]

use std::{collections::HashMap, str::FromStr};

use api_models::{
    admin as admin_api, enums as api_enums, payment_methods::RequestPaymentMethodTypes,
};
use common_utils::types::MinorUnit;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use euclid::{
    dirval,
    dssa::graph::{self, CgraphExt},
    frontend::dir,
    types::{NumValue, NumValueRefinement},
};
use hyperswitch_constraint_graph::{CycleCheck, Memoization};
use kgraph_utils::{error::KgraphError, transformers::IntoDirValue, types::CountryCurrencyFilter};

#[cfg(feature = "v1")]
fn build_test_data(
    total_enabled: usize,
    total_pm_types: usize,
) -> hyperswitch_constraint_graph::ConstraintGraph<dir::DirValue> {
    use api_models::{admin::*, payment_methods::*};

    let mut pms_enabled: Vec<PaymentMethodsEnabled> = Vec::new();

    for _ in (0..total_enabled) {
        let mut pm_types: Vec<RequestPaymentMethodTypes> = Vec::new();
        for _ in (0..total_pm_types) {
            pm_types.push(RequestPaymentMethodTypes {
                payment_method_type: api_enums::PaymentMethodType::Credit,
                payment_experience: None,
                card_networks: Some(vec![
                    api_enums::CardNetwork::Visa,
                    api_enums::CardNetwork::Mastercard,
                ]),
                accepted_currencies: Some(AcceptedCurrencies::EnableOnly(vec![
                    api_enums::Currency::USD,
                    api_enums::Currency::INR,
                ])),
                accepted_countries: None,
                minimum_amount: Some(MinorUnit::new(10)),
                maximum_amount: Some(MinorUnit::new(1000)),
                recurring_enabled: Some(true),
                installment_payment_enabled: Some(true),
            });
        }

        pms_enabled.push(PaymentMethodsEnabled {
            payment_method: api_enums::PaymentMethod::Card,
            payment_method_types: Some(pm_types),
        });
    }

    let profile_id = common_utils::generate_profile_id_of_default_length();

    // #[cfg(feature = "v2")]
    // let stripe_account = MerchantConnectorResponse {
    //     connector_type: api_enums::ConnectorType::FizOperations,
    //     connector_name: "stripe".to_string(),
    //     id: common_utils::generate_merchant_connector_account_id_of_default_length(),
    //     connector_account_details: masking::Secret::new(serde_json::json!({})),
    //     disabled: None,
    //     metadata: None,
    //     payment_methods_enabled: Some(pms_enabled),
    //     connector_label: Some("something".to_string()),
    //     frm_configs: None,
    //     connector_webhook_details: None,
    //     profile_id,
    //     applepay_verified_domains: None,
    //     pm_auth_config: None,
    //     status: api_enums::ConnectorStatus::Inactive,
    //     additional_merchant_data: None,
    //     connector_wallets_details: None,
    // };

    #[cfg(feature = "v1")]
    let stripe_account = MerchantConnectorResponse {
        connector_type: api_enums::ConnectorType::FizOperations,
        connector_name: "stripe".to_string(),
        merchant_connector_id:
            common_utils::generate_merchant_connector_account_id_of_default_length(),
        connector_account_details: masking::Secret::new(serde_json::json!({})),
        test_mode: None,
        disabled: None,
        metadata: None,
        payment_methods_enabled: Some(pms_enabled),
        business_country: Some(api_enums::CountryAlpha2::US),
        business_label: Some("hello".to_string()),
        connector_label: Some("something".to_string()),
        business_sub_label: Some("something".to_string()),
        frm_configs: None,
        connector_webhook_details: None,
        profile_id,
        applepay_verified_domains: None,
        pm_auth_config: None,
        status: api_enums::ConnectorStatus::Inactive,
        additional_merchant_data: None,
        connector_wallets_details: None,
    };
    let config = CountryCurrencyFilter {
        connector_configs: HashMap::new(),
        default_configs: None,
    };

    #[cfg(feature = "v1")]
    kgraph_utils::mca::make_mca_graph(vec![stripe_account], &config)
        .expect("Failed graph construction")
}

#[cfg(feature = "v1")]
fn evaluation(c: &mut Criterion) {
    let small_graph = build_test_data(3, 8);
    let big_graph = build_test_data(20, 20);

    c.bench_function("MCA Small Graph Evaluation", |b| {
        b.iter(|| {
            small_graph.key_value_analysis(
                dirval!(Connector = Stripe),
                &graph::AnalysisContext::from_dir_values([
                    dirval!(Connector = Stripe),
                    dirval!(PaymentMethod = Card),
                    dirval!(CardType = Credit),
                    dirval!(CardNetwork = Visa),
                    dirval!(PaymentCurrency = BWP),
                    dirval!(PaymentAmount = 100),
                ]),
                &mut Memoization::new(),
                &mut CycleCheck::new(),
                None,
            );
        });
    });

    c.bench_function("MCA Big Graph Evaluation", |b| {
        b.iter(|| {
            big_graph.key_value_analysis(
                dirval!(Connector = Stripe),
                &graph::AnalysisContext::from_dir_values([
                    dirval!(Connector = Stripe),
                    dirval!(PaymentMethod = Card),
                    dirval!(CardType = Credit),
                    dirval!(CardNetwork = Visa),
                    dirval!(PaymentCurrency = BWP),
                    dirval!(PaymentAmount = 100),
                ]),
                &mut Memoization::new(),
                &mut CycleCheck::new(),
                None,
            );
        });
    });
}

#[cfg(feature = "v1")]
criterion_group!(benches, evaluation);
#[cfg(feature = "v1")]
criterion_main!(benches);

#[cfg(feature = "v2")]
fn main() {}


pub struct SquarePaymentsResponse {
    payment: SquarePaymentsResponseDetails,
}


pub struct NexixpayNonMandatePaymentRequest {
    card: NexixpayCard,
    recurrence: Option<RecurrenceRequest>,
}


pub struct SubError {
    pub code: String,
    pub message: String,
    pub path: Option<String>,
    pub field: Option<String>,
}


File: crates/test_utils/tests/connectors/noon_ui.rs

use serial_test::serial;
use thirtyfour::{prelude::*, WebDriver};

use crate::{selenium::*, tester};

struct NoonSeleniumTest;

impl SeleniumTest for NoonSeleniumTest {
    fn get_connector_name(&self) -> String {
        "noon".to_string()
    }
}

async fn should_make_noon_3ds_payment(web_driver: WebDriver) -> Result<(), WebDriverError> {
    let conn = NoonSeleniumTest {};
    conn.make_redirection_payment(
        web_driver,
        vec![
            Event::Trigger(Trigger::Goto(&format!("{CHECKOUT_BASE_URL}/saved/176"))),
            Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
            Event::Trigger(Trigger::SwitchFrame(By::Id("redirectTo3ds1Frame"))),
            Event::Trigger(Trigger::SwitchFrame(By::Css("iframe[frameborder='0']"))),
            Event::Trigger(Trigger::SendKeys(By::Css("input.input-field"), "1234")),
            Event::Trigger(Trigger::Click(By::Css("input.button.primary"))),
            Event::Trigger(Trigger::Sleep(5)),
            Event::Assert(Assert::IsPresent("succeeded")),
        ],
    )
    .await?;
    Ok(())
}

async fn should_make_noon_3ds_mandate_payment(web_driver: WebDriver) -> Result<(), WebDriverError> {
    let conn = NoonSeleniumTest {};
    conn.make_redirection_payment(
        web_driver,
        vec![
            Event::Trigger(Trigger::Goto(&format!("{CHECKOUT_BASE_URL}/saved/214"))),
            Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
            Event::Trigger(Trigger::SwitchFrame(By::Id("redirectTo3ds1Frame"))),
            Event::Trigger(Trigger::SwitchFrame(By::Css("iframe[frameborder='0']"))),
            Event::Trigger(Trigger::SendKeys(By::Css("input.input-field"), "1234")),
            Event::Trigger(Trigger::Click(By::Css("input.button.primary"))),
            Event::Trigger(Trigger::Sleep(5)),
            Event::Assert(Assert::IsPresent("succeeded")),
            Event::Assert(Assert::IsPresent("Mandate ID")),
            Event::Assert(Assert::IsPresent("man_")), // mandate id starting with man_
            Event::Trigger(Trigger::Click(By::Css("a.btn"))),
            Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
            Event::Assert(Assert::IsPresent("succeeded")),
        ],
    )
    .await?;
    Ok(())
}

async fn should_make_noon_non_3ds_mandate_payment(
    web_driver: WebDriver,
) -> Result<(), WebDriverError> {
    let conn = NoonSeleniumTest {};
    conn.make_redirection_payment(
        web_driver,
        vec![
            Event::Trigger(Trigger::Goto(&format!("{CHECKOUT_BASE_URL}/saved/215"))),
            Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
            Event::Assert(Assert::IsPresent("succeeded")),
            Event::Assert(Assert::IsPresent("Mandate ID")),
            Event::Assert(Assert::IsPresent("man_")), // mandate id starting with man_
            Event::Trigger(Trigger::Click(By::Css("a.btn"))),
            Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
            Event::Assert(Assert::IsPresent("succeeded")),
        ],
    )
    .await?;
    Ok(())
}

#[test]
#[serial]
fn should_make_noon_3ds_payment_test() {
    tester!(should_make_noon_3ds_payment);
}

#[test]
#[serial]
fn should_make_noon_3ds_mandate_payment_test() {
    tester!(should_make_noon_3ds_mandate_payment);
}

#[test]
#[serial]
fn should_make_noon_non_3ds_mandate_payment_test() {
    tester!(should_make_noon_non_3ds_mandate_payment);
}


/// Retrieves the decision to be taken for auto retries flow.
    pub fn get_decision(&self) -> common_enums::GsmDecision {
        self.decision
    }


pub fn get_acs_url(&self) -> Option<String> {
        if let Self::Challenge(challenge_params) = self {
            challenge_params.acs_url.as_ref().map(ToString::to_string)
        } else {
            None
        }
    }


pub async fn payouts_fulfill_core(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    req: payouts::PayoutActionRequest,
) -> RouterResponse<payouts::PayoutCreateResponse> {
    let mut payout_data = Box::pin(make_payout_data(
        &state,
        &merchant_context,
        None,
        &payouts::PayoutRequest::PayoutActionRequest(req.to_owned()),
        &state.locale,
    ))
    .await?;

    let payout_attempt = payout_data.payout_attempt.to_owned();
    let status = payout_attempt.status;

    // Verify if fulfillment can be triggered
    if helpers::is_payout_terminal_state(status)
        || status != api_enums::PayoutStatus::RequiresFulfillment
    {
        return Err(report!(errors::ApiErrorResponse::InvalidRequestData {
            message: format!(
                "Payout {:?} cannot be fulfilled for status {}",
                payout_attempt.payout_id, status
            ),
        }));
    }

    // Form connector data
    let connector_data = match &payout_attempt.connector {
        Some(connector) => api::ConnectorData::get_payout_connector_by_name(
            &state.conf.connectors,
            connector,
            api::GetToken::Connector,
            payout_attempt.merchant_connector_id.clone(),
        )
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to get the connector data")?,
        _ => Err(errors::ApplicationError::InvalidConfigurationValueError(
            "Connector not found in payout_attempt - should not reach here.".to_string(),
        ))
        .change_context(errors::ApiErrorResponse::MissingRequiredField {
            field_name: "connector",
        })
        .attach_printable("Connector not found for payout fulfillment")?,
    };

    helpers::fetch_payout_method_data(&state, &mut payout_data, &connector_data, &merchant_context)
        .await?;
    Box::pin(fulfill_payout(
        &state,
        &merchant_context,
        &connector_data,
        &mut payout_data,
    ))
    .await
    .attach_printable("Payout fulfillment failed for given Payout request")?;

    if helpers::is_payout_err_state(status) {
        return Err(report!(errors::ApiErrorResponse::PayoutFailed {
            data: Some(
                serde_json::json!({"payout_status": status.to_string(), "error_message": payout_attempt.error_message, "error_code": payout_attempt.error_code})
            ),
        }));
    }

    trigger_webhook_and_handle_response(&state, &merchant_context, &payout_data).await
}


pub struct SilverflowWebhookEventData {
    pub charge_key: Option<String>,
    pub refund_key: Option<String>,
    pub status: Option<PaymentStatus>,
    pub amount: Option<Amount>,
    pub transaction_reference: Option<String>,
}


pub trait QueryFilter<T>
where
    T: AnalyticsDataSource,
    AnalyticsCollection: ToSql<T>,
{
    fn set_filter_clause(&self, builder: &mut QueryBuilder<T>) -> QueryResult<()>;
}


impl api::Payment for Ebanx {}


pub async fn files_retrieve(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
    json_payload: web::Query<file_types::FileRetrieveQuery>,
) -> HttpResponse {
    let flow = Flow::RetrieveFile;
    let file_id = files::FileRetrieveRequest {
        file_id: path.into_inner(),
        dispute_id: json_payload.dispute_id.clone(),
    };
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        file_id,
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            files_retrieve_core(state, merchant_context, req)
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::DashboardNoPermissionAuth,
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub async fn create_new_merchant_and_insert_in_db(
        &self,
        state: SessionState,
    ) -> UserResult<domain::MerchantAccount> {
        self.check_if_already_exists_in_db(state.clone()).await?;

        let merchant_account_create_request = self
            .create_merchant_account_request()
            .attach_printable("Unable to construct merchant account create request")?;
        let org_id = merchant_account_create_request
            .clone()
            .organization_id
            .ok_or(UserErrors::InternalServerError)?;
        let ApplicationResponse::Json(merchant_account_response) =
            Box::pin(admin::create_merchant_account(
                state.clone(),
                merchant_account_create_request,
                Some(AuthenticationDataWithOrg {
                    organization_id: org_id,
                }),
            ))
            .await
            .change_context(UserErrors::InternalServerError)
            .attach_printable("Error while creating merchant")?
        else {
            return Err(UserErrors::InternalServerError.into());
        };

        let key_manager_state = &(&state).into();
        let merchant_key_store = state
            .store
            .get_merchant_key_store_by_merchant_id(
                key_manager_state,
                &merchant_account_response.merchant_id,
                &state.store.get_master_key().to_vec().into(),
            )
            .await
            .change_context(UserErrors::InternalServerError)
            .attach_printable("Failed to retrieve merchant key store by merchant_id")?;

        let merchant_account = state
            .store
            .find_merchant_account_by_merchant_id(
                key_manager_state,
                &merchant_account_response.merchant_id,
                &merchant_key_store,
            )
            .await
            .change_context(UserErrors::InternalServerError)
            .attach_printable("Failed to retrieve merchant account by merchant_id")?;
        Ok(merchant_account)
    }


pub async fn enable_platform_account(
    state: SessionState,
    merchant_id: id_type::MerchantId,
) -> RouterResponse<()> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let key_store = db
        .get_merchant_key_store_by_merchant_id(
            key_manager_state,
            &merchant_id,
            &db.get_master_key().to_vec().into(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    let merchant_account = db
        .find_merchant_account_by_merchant_id(key_manager_state, &merchant_id, &key_store)
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    db.update_merchant(
        key_manager_state,
        merchant_account,
        storage::MerchantAccountUpdate::ToPlatformAccount,
        &key_store,
    )
    .await
    .change_context(errors::ApiErrorResponse::InternalServerError)
    .attach_printable("Error while enabling platform merchant account")
    .map(|_| services::ApplicationResponse::StatusOk)
}


impl Tokenizable for ExternalVaultProxyPaymentsData {
    fn set_session_token(&mut self, token: Option<String>) {
        self.session_token = token;
    }
}

impl Tokenizable for for ExternalVaultProxyPaymentsData


File: crates/openapi/src/routes/payouts.rs
 Public functions: 11

/// Payouts - Create
#[utoipa::path(
    post,
    path = "/payouts/create",
    request_body=PayoutsCreateRequest,
    responses(
        (status = 200, description = "Payout created", body = PayoutCreateResponse),
        (status = 400, description = "Missing Mandatory fields")
    ),
    tag = "Payouts",
    operation_id = "Create a Payout",
    security(("api_key" = []))
)]
pub async fn payouts_create() {}

/// Payouts - Retrieve
#[utoipa::path(
    get,
    path = "/payouts/{payout_id}",
    params(
        ("payout_id" = String, Path, description = "The identifier for payout"),
        ("force_sync" = Option<bool>, Query, description = "Sync with the connector to get the payout details (defaults to false)")
    ),
    responses(
        (status = 200, description = "Payout retrieved", body = PayoutCreateResponse),
        (status = 404, description = "Payout does not exist in our records")
    ),
    tag = "Payouts",
    operation_id = "Retrieve a Payout",
    security(("api_key" = []))
)]
pub async fn payouts_retrieve() {}

/// Payouts - Update
#[utoipa::path(
    post,
    path = "/payouts/{payout_id}",
    params(
        ("payout_id" = String, Path, description = "The identifier for payout")
    ),
    request_body=PayoutUpdateRequest,
    responses(
        (status = 200, description = "Payout updated", body = PayoutCreateResponse),
        (status = 400, description = "Missing Mandatory fields")
    ),
    tag = "Payouts",
    operation_id = "Update a Payout",
    security(("api_key" = []))
)]
pub async fn payouts_update() {}

/// Payouts - Cancel
#[utoipa::path(
    post,
    path = "/payouts/{payout_id}/cancel",
    params(
        ("payout_id" = String, Path, description = "The identifier for payout")
    ),
    request_body=PayoutCancelRequest,
    responses(
        (status = 200, description = "Payout cancelled", body = PayoutCreateResponse),
        (status = 400, description = "Missing Mandatory fields")
    ),
    tag = "Payouts",
    operation_id = "Cancel a Payout",
    security(("api_key" = []))
)]
pub async fn payouts_cancel() {}

/// Payouts - Fulfill
#[utoipa::path(
    post,
    path = "/payouts/{payout_id}/fulfill",
    params(
        ("payout_id" = String, Path, description = "The identifier for payout")
    ),
    request_body=PayoutFulfillRequest,
    responses(
        (status = 200, description = "Payout fulfilled", body = PayoutCreateResponse),
        (status = 400, description = "Missing Mandatory fields")
    ),
    tag = "Payouts",
    operation_id = "Fulfill a Payout",
    security(("api_key" = []))
)]
pub async fn payouts_fulfill() {}

/// Payouts - List
#[utoipa::path(
    get,
    path = "/payouts/list",
    params(
        ("customer_id" = String, Query, description = "The identifier for customer"),
        ("starting_after" = String, Query, description = "A cursor for use in pagination, fetch the next list after some object"),
        ("ending_before" = String, Query, description = "A cursor for use in pagination, fetch the previous list before some object"),
        ("limit" = String, Query, description = "limit on the number of objects to return"),
        ("created" = String, Query, description = "The time at which payout is created"),
        ("time_range" = String, Query, description = "The time range for which objects are needed. TimeRange has two fields start_time and end_time from which objects can be filtered as per required scenarios (created_at, time less than, greater than etc).")
    ),
    responses(
        (status = 200, description = "Payouts listed", body = PayoutListResponse),
        (status = 404, description = "Payout not found")
    ),
    tag = "Payouts",
    operation_id = "List payouts using generic constraints",
    security(("api_key" = []))
)]
pub async fn payouts_list() {}

/// Payouts - List for the Given Profiles
#[utoipa::path(
    get,
    path = "/payouts/profile/list",
    params(
        ("customer_id" = String, Query, description = "The identifier for customer"),
        ("starting_after" = String, Query, description = "A cursor for use in pagination, fetch the next list after some object"),
        ("ending_before" = String, Query, description = "A cursor for use in pagination, fetch the previous list before some object"),
        ("limit" = String, Query, description = "limit on the number of objects to return"),
        ("created" = String, Query, description = "The time at which payout is created"),
        ("time_range" = String, Query, description = "The time range for which objects are needed. TimeRange has two fields start_time and end_time from which objects can be filtered as per required scenarios (created_at, time less than, greater than etc).")
    ),
    responses(
        (status = 200, description = "Payouts listed", body = PayoutListResponse),
        (status = 404, description = "Payout not found")
    ),
    tag = "Payouts",
    operation_id = "List payouts using generic constraints for the given Profiles",
    security(("api_key" = []))
)]
pub async fn payouts_list_profile() {}

/// Payouts - List available filters
#[utoipa::path(
    post,
    path = "/payouts/filter",
    request_body=TimeRange,
    responses(
        (status = 200, description = "Filters listed", body = PayoutListFilters)
    ),
    tag = "Payouts",
    operation_id = "List available payout filters",
    security(("api_key" = []))
)]
pub async fn payouts_list_filters() {}

/// Payouts - List using filters
#[utoipa::path(
    post,
    path = "/payouts/list",
    request_body=PayoutListFilterConstraints,
    responses(
        (status = 200, description = "Payouts filtered", body = PayoutListResponse),
        (status = 404, description = "Payout not found")
    ),
    tag = "Payouts",
    operation_id = "Filter payouts using specific constraints",
    security(("api_key" = []))
)]
pub async fn payouts_list_by_filter() {}

/// Payouts - List using filters for the given Profiles
#[utoipa::path(
    post,
    path = "/payouts/list",
    request_body=PayoutListFilterConstraints,
    responses(
        (status = 200, description = "Payouts filtered", body = PayoutListResponse),
        (status = 404, description = "Payout not found")
    ),
    tag = "Payouts",
    operation_id = "Filter payouts using specific constraints for the given Profiles",
    security(("api_key" = []))
)]
pub async fn payouts_list_by_filter_profile() {}

/// Payouts - Confirm
#[utoipa::path(
    post,
    path = "/payouts/{payout_id}/confirm",
    params(
        ("payout_id" = String, Path, description = "The identifier for payout")
    ),
    request_body=PayoutConfirmRequest,
    responses(
        (status = 200, description = "Payout updated", body = PayoutCreateResponse),
        (status = 400, description = "Missing Mandatory fields")
    ),
    tag = "Payouts",
    operation_id = "Confirm a Payout",
    security(("api_key" = []))
)]
pub async fn payouts_confirm() {}


pub struct RequiredFieldFinal {
    pub mandate: HashMap<String, RequiredFieldInfo>,
    pub non_mandate: HashMap<String, RequiredFieldInfo>,
    pub common: HashMap<String, RequiredFieldInfo>,
}


File: crates/scheduler/src/db/process_tracker.rs

use common_utils::errors::CustomResult;
pub use diesel_models as storage;
use diesel_models::enums as storage_enums;
use error_stack::{report, ResultExt};
use storage_impl::{connection, errors, mock_db::MockDb};
use time::PrimitiveDateTime;

use crate::{metrics, scheduler::Store};

#[async_trait::async_trait]
pub trait ProcessTrackerInterface: Send + Sync + 'static {
    async fn reinitialize_limbo_processes(
        &self,
        ids: Vec<String>,
        schedule_time: PrimitiveDateTime,
    ) -> CustomResult<usize, errors::StorageError>;

    async fn find_process_by_id(
        &self,
        id: &str,
    ) -> CustomResult<Option<storage::ProcessTracker>, errors::StorageError>;

    async fn update_process(
        &self,
        this: storage::ProcessTracker,
        process: storage::ProcessTrackerUpdate,
    ) -> CustomResult<storage::ProcessTracker, errors::StorageError>;

    async fn process_tracker_update_process_status_by_ids(
        &self,
        task_ids: Vec<String>,
        task_update: storage::ProcessTrackerUpdate,
    ) -> CustomResult<usize, errors::StorageError>;

    async fn insert_process(
        &self,
        new: storage::ProcessTrackerNew,
    ) -> CustomResult<storage::ProcessTracker, errors::StorageError>;

    async fn reset_process(
        &self,
        this: storage::ProcessTracker,
        schedule_time: PrimitiveDateTime,
    ) -> CustomResult<(), errors::StorageError>;

    async fn retry_process(
        &self,
        this: storage::ProcessTracker,
        schedule_time: PrimitiveDateTime,
    ) -> CustomResult<(), errors::StorageError>;

    async fn finish_process_with_business_status(
        &self,
        this: storage::ProcessTracker,
        business_status: &'static str,
    ) -> CustomResult<(), errors::StorageError>;

    async fn find_processes_by_time_status(
        &self,
        time_lower_limit: PrimitiveDateTime,
        time_upper_limit: PrimitiveDateTime,
        status: storage_enums::ProcessTrackerStatus,
        limit: Option<i64>,
    ) -> CustomResult<Vec<storage::ProcessTracker>, errors::StorageError>;
}

#[async_trait::async_trait]
impl ProcessTrackerInterface for Store {
    async fn find_process_by_id(
        &self,
        id: &str,
    ) -> CustomResult<Option<storage::ProcessTracker>, errors::StorageError> {
        let conn = connection::pg_connection_read(self).await?;
        storage::ProcessTracker::find_process_by_id(&conn, id)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
    }

    async fn reinitialize_limbo_processes(
        &self,
        ids: Vec<String>,
        schedule_time: PrimitiveDateTime,
    ) -> CustomResult<usize, errors::StorageError> {
        let conn = connection::pg_connection_write(self).await?;
        storage::ProcessTracker::reinitialize_limbo_processes(&conn, ids, schedule_time)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
    }

    async fn find_processes_by_time_status(
        &self,
        time_lower_limit: PrimitiveDateTime,
        time_upper_limit: PrimitiveDateTime,
        status: storage_enums::ProcessTrackerStatus,
        limit: Option<i64>,
    ) -> CustomResult<Vec<storage::ProcessTracker>, errors::StorageError> {
        let conn = connection::pg_connection_read(self).await?;
        storage::ProcessTracker::find_processes_by_time_status(
            &conn,
            time_lower_limit,
            time_upper_limit,
            status,
            limit,
            common_types::consts::API_VERSION,
        )
        .await
        .map_err(|error| report!(errors::StorageError::from(error)))
    }

    async fn insert_process(
        &self,
        new: storage::ProcessTrackerNew,
    ) -> CustomResult<storage::ProcessTracker, errors::StorageError> {
        let conn = connection::pg_connection_write(self).await?;
        new.insert_process(&conn)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
    }

    async fn update_process(
        &self,
        this: storage::ProcessTracker,
        process: storage::ProcessTrackerUpdate,
    ) -> CustomResult<storage::ProcessTracker, errors::StorageError> {
        let conn = connection::pg_connection_write(self).await?;
        this.update(&conn, process)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
    }

    async fn reset_process(
        &self,
        this: storage::ProcessTracker,
        schedule_time: PrimitiveDateTime,
    ) -> CustomResult<(), errors::StorageError> {
        self.update_process(
            this,
            storage::ProcessTrackerUpdate::StatusRetryUpdate {
                status: storage_enums::ProcessTrackerStatus::New,
                retry_count: 0,
                schedule_time,
            },
        )
        .await?;
        Ok(())
    }

    async fn retry_process(
        &self,
        this: storage::ProcessTracker,
        schedule_time: PrimitiveDateTime,
    ) -> CustomResult<(), errors::StorageError> {
        metrics::TASK_RETRIED.add(1, &[]);
        let retry_count = this.retry_count + 1;
        self.update_process(
            this,
            storage::ProcessTrackerUpdate::StatusRetryUpdate {
                status: storage_enums::ProcessTrackerStatus::Pending,
                retry_count,
                schedule_time,
            },
        )
        .await?;
        Ok(())
    }

    async fn finish_process_with_business_status(
        &self,
        this: storage::ProcessTracker,
        business_status: &'static str,
    ) -> CustomResult<(), errors::StorageError> {
        self.update_process(
            this,
            storage::ProcessTrackerUpdate::StatusUpdate {
                status: storage_enums::ProcessTrackerStatus::Finish,
                business_status: Some(String::from(business_status)),
            },
        )
        .await
        .attach_printable("Failed to update business status of process")?;
        metrics::TASK_FINISHED.add(1, &[]);
        Ok(())
    }

    async fn process_tracker_update_process_status_by_ids(
        &self,
        task_ids: Vec<String>,
        task_update: storage::ProcessTrackerUpdate,
    ) -> CustomResult<usize, errors::StorageError> {
        let conn = connection::pg_connection_write(self).await?;
        storage::ProcessTracker::update_process_status_by_ids(&conn, task_ids, task_update)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
    }
}

#[async_trait::async_trait]
impl ProcessTrackerInterface for MockDb {
    async fn find_process_by_id(
        &self,
        id: &str,
    ) -> CustomResult<Option<storage::ProcessTracker>, errors::StorageError> {
        let optional = self
            .processes
            .lock()
            .await
            .iter()
            .find(|process| process.id == id)
            .cloned();

        Ok(optional)
    }

    async fn reinitialize_limbo_processes(
        &self,
        _ids: Vec<String>,
        _schedule_time: PrimitiveDateTime,
    ) -> CustomResult<usize, errors::StorageError> {
        // [#172]: Implement function for `MockDb`
        Err(errors::StorageError::MockDbError)?
    }

    async fn find_processes_by_time_status(
        &self,
        _time_lower_limit: PrimitiveDateTime,
        _time_upper_limit: PrimitiveDateTime,
        _status: storage_enums::ProcessTrackerStatus,
        _limit: Option<i64>,
    ) -> CustomResult<Vec<storage::ProcessTracker>, errors::StorageError> {
        // [#172]: Implement function for `MockDb`
        Err(errors::StorageError::MockDbError)?
    }
    async fn insert_process(
        &self,
        new: storage::ProcessTrackerNew,
    ) -> CustomResult<storage::ProcessTracker, errors::StorageError> {
        let mut processes = self.processes.lock().await;
        let process = storage::ProcessTracker {
            id: new.id,
            name: new.name,
            tag: new.tag,
            runner: new.runner,
            retry_count: new.retry_count,
            schedule_time: new.schedule_time,
            rule: new.rule,
            tracking_data: new.tracking_data,
            business_status: new.business_status,
            status: new.status,
            event: new.event,
            created_at: new.created_at,
            updated_at: new.updated_at,
            version: new.version,
        };
        processes.push(process.clone());
        Ok(process)
    }

    async fn update_process(
        &self,
        _this: storage::ProcessTracker,
        _process: storage::ProcessTrackerUpdate,
    ) -> CustomResult<storage::ProcessTracker, errors::StorageError> {
        // [#172]: Implement function for `MockDb`
        Err(errors::StorageError::MockDbError)?
    }

    async fn reset_process(
        &self,
        _this: storage::ProcessTracker,
        _schedule_time: PrimitiveDateTime,
    ) -> CustomResult<(), errors::StorageError> {
        // [#172]: Implement function for `MockDb`
        Err(errors::StorageError::MockDbError)?
    }

    async fn retry_process(
        &self,
        _this: storage::ProcessTracker,
        _schedule_time: PrimitiveDateTime,
    ) -> CustomResult<(), errors::StorageError> {
        // [#172]: Implement function for `MockDb`
        Err(errors::StorageError::MockDbError)?
    }

    async fn finish_process_with_business_status(
        &self,
        _this: storage::ProcessTracker,
        _business_status: &'static str,
    ) -> CustomResult<(), errors::StorageError> {
        // [#172]: Implement function for `MockDb`
        Err(errors::StorageError::MockDbError)?
    }

    async fn process_tracker_update_process_status_by_ids(
        &self,
        _task_ids: Vec<String>,
        _task_update: storage::ProcessTrackerUpdate,
    ) -> CustomResult<usize, errors::StorageError> {
        // [#172]: Implement function for `MockDb`
        Err(errors::StorageError::MockDbError)?
    }
}


pub async fn from_origin(
        origin: Origin,
        user: UserFromStorage,
        state: &SessionState,
    ) -> UserResult<Self> {
        let flows = origin.get_flows();
        let path = vec![];
        for flow in flows {
            if flow
                .is_required(&user, &path, state, &state.tenant.tenant_id)
                .await?
            {
                return Ok(Self {
                    origin,
                    next_flow: *flow,
                    user,
                    path,
                    tenant_id: Some(state.tenant.tenant_id.clone()),
                });
            }
        }
        Err(UserErrors::InternalServerError.into())
    }


pub async fn store_payment_method_data_in_locker(
        state: &routes::SessionState,
        token_id: Option<String>,
        payment_method: &domain::PaymentMethodData,
        customer_id: Option<id_type::CustomerId>,
        pm: enums::PaymentMethod,
        merchant_key_store: &domain::MerchantKeyStore,
    ) -> RouterResult<String> {
        let value1 = payment_method
            .get_value1(customer_id.clone())
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Error getting Value1 for locker")?;

        let value2 = payment_method
            .get_value2(customer_id)
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Error getting Value12 for locker")?;

        let lookup_key = token_id.unwrap_or_else(|| generate_id_with_default_len("token"));

        let lookup_key = create_tokenize(
            state,
            value1,
            Some(value2),
            lookup_key,
            merchant_key_store.key.get_inner(),
        )
        .await?;
        add_delete_tokenized_data_task(&*state.store, &lookup_key, pm).await?;
        metrics::TOKENIZED_DATA_COUNT.add(1, &[]);
        Ok(lookup_key)
    }


pub async fn retrieve_decision_engine_active_rules(
    state: &SessionState,
    transaction_type: &enums::TransactionType,
    profile_id: common_utils::id_type::ProfileId,
    hs_records: Vec<routing_types::RoutingDictionaryRecord>,
) -> Vec<routing_types::RoutingDictionaryRecord> {
    let mut de_records =
        list_de_euclid_active_routing_algorithm(state, profile_id.get_string_repr().to_owned())
            .await
            .map_err(|e| {
                router_env::logger::error!(?e, "Failed to list DE Euclid active routing algorithm");
            })
            .ok() // Avoid throwing error if Decision Engine is not available or other errors thrown
            .unwrap_or_default();
    // Use Hs records to list the dynamic algorithms as DE is not supporting dynamic algorithms in HS standard
    let mut dynamic_algos = hs_records
        .into_iter()
        .filter(|record| record.kind == routing_types::RoutingAlgorithmKind::Dynamic)
        .collect::<Vec<_>>();
    de_records.append(&mut dynamic_algos);
    de_records
        .into_iter()
        .filter(|r| r.algorithm_for == Some(*transaction_type))
        .collect::<Vec<_>>()
}


pub struct AuthorizedotnetRefundResponse {
    pub transaction_response: RefundResponse,
    pub messages: ResponseMessages,
}


impl api::PaymentVoid for Globalpay {}


pub async fn form_payment_link_data(
    state: &SessionState,
    merchant_context: domain::MerchantContext,
    merchant_id: common_utils::id_type::MerchantId,
    payment_id: common_utils::id_type::PaymentId,
) -> RouterResult<(PaymentLink, PaymentLinkData, PaymentLinkConfig)> {
    todo!()
}