// File: crates/router/src/db/refund.rs
// Module: router

#[cfg(feature = "olap")]
use std::collections::{HashMap, HashSet};

#[cfg(feature = "olap")]
use common_utils::types::{ConnectorTransactionIdTrait, MinorUnit};
use diesel_models::{errors::DatabaseError, refund as diesel_refund};
use hyperswitch_domain_models::refunds;

use super::MockDb;
use crate::{
    core::errors::{self, CustomResult},
    types::storage::enums,
};

#[cfg(feature = "olap")]
const MAX_LIMIT: usize = 100;

#[async_trait::async_trait]
pub trait RefundInterface {
    #[cfg(feature = "v1")]
    async fn find_refund_by_internal_reference_id_merchant_id(
        &self,
        internal_reference_id: &str,
        merchant_id: &common_utils::id_type::MerchantId,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError>;

    #[cfg(feature = "v1")]
    async fn find_refund_by_payment_id_merchant_id(
        &self,
        payment_id: &common_utils::id_type::PaymentId,
        merchant_id: &common_utils::id_type::MerchantId,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<Vec<diesel_refund::Refund>, errors::StorageError>;

    #[cfg(feature = "v1")]
    async fn find_refund_by_merchant_id_refund_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_id: &str,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError>;

    #[cfg(feature = "v1")]
    async fn find_refund_by_merchant_id_connector_refund_id_connector(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_refund_id: &str,
        connector: &str,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError>;

    async fn update_refund(
        &self,
        this: diesel_refund::Refund,
        refund: diesel_refund::RefundUpdate,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError>;

    async fn find_refund_by_merchant_id_connector_transaction_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_transaction_id: &str,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<Vec<diesel_refund::Refund>, errors::StorageError>;

    #[cfg(feature = "v2")]
    async fn find_refund_by_id(
        &self,
        id: &common_utils::id_type::GlobalRefundId,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError>;

    async fn insert_refund(
        &self,
        new: diesel_refund::RefundNew,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError>;

    #[cfg(all(feature = "v1", feature = "olap"))]
    async fn filter_refund_by_constraints(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_details: &refunds::RefundListConstraints,
        storage_scheme: enums::MerchantStorageScheme,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<diesel_models::refund::Refund>, errors::StorageError>;

    #[cfg(all(feature = "v2", feature = "olap"))]
    async fn filter_refund_by_constraints(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_details: refunds::RefundListConstraints,
        storage_scheme: enums::MerchantStorageScheme,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<diesel_models::refund::Refund>, errors::StorageError>;

    #[cfg(all(feature = "v1", feature = "olap"))]
    async fn filter_refund_by_meta_constraints(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_details: &common_utils::types::TimeRange,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<api_models::refunds::RefundListMetaData, errors::StorageError>;

    #[cfg(all(feature = "v1", feature = "olap"))]
    async fn get_refund_status_with_count(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
        constraints: &common_utils::types::TimeRange,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<Vec<(common_enums::RefundStatus, i64)>, errors::StorageError>;

    #[cfg(all(feature = "v1", feature = "olap"))]
    async fn get_total_count_of_refunds(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_details: &refunds::RefundListConstraints,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<i64, errors::StorageError>;

    #[cfg(all(feature = "v2", feature = "olap"))]
    async fn get_total_count_of_refunds(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_details: refunds::RefundListConstraints,
        storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<i64, errors::StorageError>;
}

#[cfg(not(feature = "kv_store"))]
mod storage {
    use error_stack::report;
    use hyperswitch_domain_models::refunds;
    use router_env::{instrument, tracing};

    use super::RefundInterface;
    use crate::{
        connection,
        core::errors::{self, CustomResult},
        services::Store,
        types::storage::{self as storage_types, enums},
    };

    #[async_trait::async_trait]
    impl RefundInterface for Store {
        #[cfg(feature = "v1")]
        #[instrument(skip_all)]
        async fn find_refund_by_internal_reference_id_merchant_id(
            &self,
            internal_reference_id: &str,
            merchant_id: &common_utils::id_type::MerchantId,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            diesel_refund::Refund::find_by_internal_reference_id_merchant_id(
                &conn,
                internal_reference_id,
                merchant_id,
            )
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[instrument(skip_all)]
        async fn insert_refund(
            &self,
            new: diesel_refund::RefundNew,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            new.insert(&conn)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[instrument(skip_all)]
        async fn find_refund_by_merchant_id_connector_transaction_id(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            connector_transaction_id: &str,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<Vec<diesel_refund::Refund>, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            diesel_refund::Refund::find_by_merchant_id_connector_transaction_id(
                &conn,
                merchant_id,
                connector_transaction_id,
            )
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(feature = "v2")]
        async fn find_refund_by_id(
            &self,
            id: &common_utils::id_type::GlobalRefundId,
            storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            diesel_refund::Refund::find_by_global_id(&conn, id)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(feature = "v1")]
        #[instrument(skip_all)]
        async fn update_refund(
            &self,
            this: diesel_refund::Refund,
            refund: diesel_refund::RefundUpdate,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            this.update(&conn, refund)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(feature = "v2")]
        #[instrument(skip_all)]
        async fn update_refund(
            &self,
            this: diesel_refund::Refund,
            refund: diesel_refund::RefundUpdate,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            this.update_with_id(&conn, refund)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(feature = "v1")]
        #[instrument(skip_all)]
        async fn find_refund_by_merchant_id_refund_id(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            refund_id: &str,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            diesel_refund::Refund::find_by_merchant_id_refund_id(&conn, merchant_id, refund_id)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(feature = "v1")]
        #[instrument(skip_all)]
        async fn find_refund_by_merchant_id_connector_refund_id_connector(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            connector_refund_id: &str,
            connector: &str,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            diesel_refund::Refund::find_by_merchant_id_connector_refund_id_connector(
                &conn,
                merchant_id,
                connector_refund_id,
                connector,
            )
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(feature = "v1")]
        #[instrument(skip_all)]
        async fn find_refund_by_payment_id_merchant_id(
            &self,
            payment_id: &common_utils::id_type::PaymentId,
            merchant_id: &common_utils::id_type::MerchantId,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<Vec<diesel_refund::Refund>, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            diesel_refund::Refund::find_by_payment_id_merchant_id(&conn, payment_id, merchant_id)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(all(feature = "v1", feature = "olap"))]
        #[instrument(skip_all)]
        async fn filter_refund_by_constraints(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            refund_details: &refunds::RefundListConstraints,
            _storage_scheme: enums::MerchantStorageScheme,
            limit: i64,
            offset: i64,
        ) -> CustomResult<Vec<diesel_models::refund::Refund>, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            <diesel_models::refund::Refund as storage_types::RefundDbExt>::filter_by_constraints(
                &conn,
                merchant_id,
                refund_details,
                limit,
                offset,
            )
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(all(feature = "v2", feature = "olap"))]
        #[instrument(skip_all)]
        async fn filter_refund_by_constraints(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            refund_details: refunds::RefundListConstraints,
            _storage_scheme: enums::MerchantStorageScheme,
            limit: i64,
            offset: i64,
        ) -> CustomResult<Vec<diesel_models::refund::Refund>, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            <diesel_models::refund::Refund as storage_types::RefundDbExt>::filter_by_constraints(
                &conn,
                merchant_id,
                refund_details,
                limit,
                offset,
            )
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(all(feature = "v1", feature = "olap"))]
        #[instrument(skip_all)]
        async fn filter_refund_by_meta_constraints(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            refund_details: &api_models::payments::TimeRange,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<api_models::refunds::RefundListMetaData, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            <diesel_models::refund::Refund as storage_types::RefundDbExt>::filter_by_meta_constraints(
                &conn,
                merchant_id,
                refund_details,
            )
            .await
            .map_err(|error|report!(errors::StorageError::from(error)))
        }

        #[cfg(all(feature = "v1", feature = "olap"))]
        #[instrument(skip_all)]
        async fn get_refund_status_with_count(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
            time_range: &api_models::payments::TimeRange,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<Vec<(common_enums::RefundStatus, i64)>, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            <diesel_models::refund::Refund as storage_types::RefundDbExt>::get_refund_status_with_count(&conn, merchant_id,profile_id_list, time_range)
            .await
            .map_err(|error|report!(errors::StorageError::from(error)))
        }

        #[cfg(all(feature = "v1", feature = "olap"))]
        #[instrument(skip_all)]
        async fn get_total_count_of_refunds(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            refund_details: &refunds::RefundListConstraints,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<i64, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            <diesel_models::refund::Refund as storage_types::RefundDbExt>::get_refunds_count(
                &conn,
                merchant_id,
                refund_details,
            )
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(all(feature = "v2", feature = "olap"))]
        #[instrument(skip_all)]
        async fn get_total_count_of_refunds(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            refund_details: refunds::RefundListConstraints,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<i64, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            <diesel_models::refund::Refund as storage_types::RefundDbExt>::get_refunds_count(
                &conn,
                merchant_id,
                refund_details,
            )
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
        }
    }
}

#[cfg(feature = "kv_store")]
mod storage {
    use common_utils::{
        ext_traits::Encode, fallback_reverse_lookup_not_found, types::ConnectorTransactionIdTrait,
    };
    use diesel_models::refund as diesel_refund;
    use error_stack::{report, ResultExt};
    use hyperswitch_domain_models::refunds;
    use redis_interface::HsetnxReply;
    use router_env::{instrument, tracing};
    use storage_impl::redis::kv_store::{
        decide_storage_scheme, kv_wrapper, KvOperation, Op, PartitionKey,
    };

    use super::RefundInterface;
    use crate::{
        connection,
        core::errors::{self, utils::RedisErrorExt, CustomResult},
        db::reverse_lookup::ReverseLookupInterface,
        services::Store,
        types::storage::{self as storage_types, enums, kv},
        utils::db_utils,
    };
    #[async_trait::async_trait]
    impl RefundInterface for Store {
        #[cfg(feature = "v1")]
        #[instrument(skip_all)]
        async fn find_refund_by_internal_reference_id_merchant_id(
            &self,
            internal_reference_id: &str,
            merchant_id: &common_utils::id_type::MerchantId,
            storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let database_call = || async {
                let conn = connection::pg_connection_read(self).await?;
                diesel_refund::Refund::find_by_internal_reference_id_merchant_id(
                    &conn,
                    internal_reference_id,
                    merchant_id,
                )
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
            };
            let storage_scheme = Box::pin(decide_storage_scheme::<_, diesel_refund::Refund>(
                self,
                storage_scheme,
                Op::Find,
            ))
            .await;
            match storage_scheme {
                enums::MerchantStorageScheme::PostgresOnly => database_call().await,
                enums::MerchantStorageScheme::RedisKv => {
                    let lookup_id = format!(
                        "ref_inter_ref_{}_{internal_reference_id}",
                        merchant_id.get_string_repr()
                    );
                    let lookup = fallback_reverse_lookup_not_found!(
                        self.get_lookup_by_lookup_id(&lookup_id, storage_scheme)
                            .await,
                        database_call().await
                    );

                    let key = PartitionKey::CombinationKey {
                        combination: &lookup.pk_id,
                    };
                    Box::pin(db_utils::try_redis_get_else_try_database_get(
                        async {
                            Box::pin(kv_wrapper(
                                self,
                                KvOperation::<diesel_refund::Refund>::HGet(&lookup.sk_id),
                                key,
                            ))
                            .await?
                            .try_into_hget()
                        },
                        database_call,
                    ))
                    .await
                }
            }
        }

        #[cfg(feature = "v1")]
        #[instrument(skip_all)]
        async fn insert_refund(
            &self,
            new: diesel_refund::RefundNew,
            storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let storage_scheme = Box::pin(decide_storage_scheme::<_, diesel_refund::Refund>(
                self,
                storage_scheme,
                Op::Insert,
            ))
            .await;
            match storage_scheme {
                enums::MerchantStorageScheme::PostgresOnly => {
                    let conn = connection::pg_connection_write(self).await?;
                    new.insert(&conn)
                        .await
                        .map_err(|error| report!(errors::StorageError::from(error)))
                }
                enums::MerchantStorageScheme::RedisKv => {
                    let merchant_id = new.merchant_id.clone();
                    let payment_id = new.payment_id.clone();
                    let key = PartitionKey::MerchantIdPaymentId {
                        merchant_id: &merchant_id,
                        payment_id: &payment_id,
                    };
                    let key_str = key.to_string();
                    // TODO: need to add an application generated payment attempt id to distinguish between multiple attempts for the same payment id
                    // Check for database presence as well Maybe use a read replica here ?
                    let created_refund = diesel_refund::Refund {
                        refund_id: new.refund_id.clone(),
                        merchant_id: new.merchant_id.clone(),
                        attempt_id: new.attempt_id.clone(),
                        internal_reference_id: new.internal_reference_id.clone(),
                        payment_id: new.payment_id.clone(),
                        connector_transaction_id: new.connector_transaction_id.clone(),
                        connector: new.connector.clone(),
                        connector_refund_id: new.connector_refund_id.clone(),
                        external_reference_id: new.external_reference_id.clone(),
                        refund_type: new.refund_type,
                        total_amount: new.total_amount,
                        currency: new.currency,
                        refund_amount: new.refund_amount,
                        refund_status: new.refund_status,
                        sent_to_gateway: new.sent_to_gateway,
                        refund_error_message: None,
                        refund_error_code: None,
                        metadata: new.metadata.clone(),
                        refund_arn: new.refund_arn.clone(),
                        created_at: new.created_at,
                        modified_at: new.created_at,
                        description: new.description.clone(),
                        refund_reason: new.refund_reason.clone(),
                        profile_id: new.profile_id.clone(),
                        updated_by: new.updated_by.clone(),
                        merchant_connector_id: new.merchant_connector_id.clone(),
                        charges: new.charges.clone(),
                        split_refunds: new.split_refunds.clone(),
                        organization_id: new.organization_id.clone(),
                        unified_code: None,
                        unified_message: None,
                        processor_refund_data: new.processor_refund_data.clone(),
                        processor_transaction_data: new.processor_transaction_data.clone(),
                        issuer_error_code: None,
                        issuer_error_message: None,
                        // Below fields are deprecated. Please add any new fields above this line.
                        connector_refund_data: None,
                        connector_transaction_data: None,
                    };

                    let field = format!(
                        "pa_{}_ref_{}",
                        &created_refund.attempt_id, &created_refund.refund_id
                    );

                    let redis_entry = kv::TypedSql {
                        op: kv::DBOperation::Insert {
                            insertable: Box::new(kv::Insertable::Refund(new)),
                        },
                    };

                    let mut reverse_lookups = vec![
                        storage_types::ReverseLookupNew {
                            sk_id: field.clone(),
                            lookup_id: format!(
                                "ref_ref_id_{}_{}",
                                created_refund.merchant_id.get_string_repr(),
                                created_refund.refund_id
                            ),
                            pk_id: key_str.clone(),
                            source: "refund".to_string(),
                            updated_by: storage_scheme.to_string(),
                        },
                        // [#492]: A discussion is required on whether this is required?
                        storage_types::ReverseLookupNew {
                            sk_id: field.clone(),
                            lookup_id: format!(
                                "ref_inter_ref_{}_{}",
                                created_refund.merchant_id.get_string_repr(),
                                created_refund.internal_reference_id
                            ),
                            pk_id: key_str.clone(),
                            source: "refund".to_string(),
                            updated_by: storage_scheme.to_string(),
                        },
                    ];
                    if let Some(connector_refund_id) =
                        created_refund.to_owned().get_optional_connector_refund_id()
                    {
                        reverse_lookups.push(storage_types::ReverseLookupNew {
                            sk_id: field.clone(),
                            lookup_id: format!(
                                "ref_connector_{}_{}_{}",
                                created_refund.merchant_id.get_string_repr(),
                                connector_refund_id,
                                created_refund.connector
                            ),
                            pk_id: key_str.clone(),
                            source: "refund".to_string(),
                            updated_by: storage_scheme.to_string(),
                        })
                    };
                    let rev_look = reverse_lookups
                        .into_iter()
                        .map(|rev| self.insert_reverse_lookup(rev, storage_scheme));

                    futures::future::try_join_all(rev_look).await?;

                    match Box::pin(kv_wrapper::<diesel_refund::Refund, _, _>(
                        self,
                        KvOperation::<diesel_refund::Refund>::HSetNx(
                            &field,
                            &created_refund,
                            redis_entry,
                        ),
                        key,
                    ))
                    .await
                    .map_err(|err| err.to_redis_failed_response(&key_str))?
                    .try_into_hsetnx()
                    {
                        Ok(HsetnxReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue {
                            entity: "refund",
                            key: Some(created_refund.refund_id),
                        }
                        .into()),
                        Ok(HsetnxReply::KeySet) => Ok(created_refund),
                        Err(er) => Err(er).change_context(errors::StorageError::KVError),
                    }
                }
            }
        }

        #[cfg(feature = "v2")]
        #[instrument(skip_all)]
        async fn insert_refund(
            &self,
            new: diesel_refund::RefundNew,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            new.insert(&conn)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(feature = "v1")]
        #[instrument(skip_all)]
        async fn find_refund_by_merchant_id_connector_transaction_id(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            connector_transaction_id: &str,
            storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<Vec<diesel_refund::Refund>, errors::StorageError> {
            let database_call = || async {
                let conn = connection::pg_connection_read(self).await?;
                diesel_refund::Refund::find_by_merchant_id_connector_transaction_id(
                    &conn,
                    merchant_id,
                    connector_transaction_id,
                )
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
            };
            let storage_scheme = Box::pin(decide_storage_scheme::<_, diesel_refund::Refund>(
                self,
                storage_scheme,
                Op::Find,
            ))
            .await;
            match storage_scheme {
                enums::MerchantStorageScheme::PostgresOnly => database_call().await,
                enums::MerchantStorageScheme::RedisKv => {
                    let lookup_id = format!(
                        "pa_conn_trans_{}_{connector_transaction_id}",
                        merchant_id.get_string_repr()
                    );
                    let lookup = fallback_reverse_lookup_not_found!(
                        self.get_lookup_by_lookup_id(&lookup_id, storage_scheme)
                            .await,
                        database_call().await
                    );

                    let key = PartitionKey::CombinationKey {
                        combination: &lookup.pk_id,
                    };

                    let pattern = db_utils::generate_hscan_pattern_for_refund(&lookup.sk_id);

                    Box::pin(db_utils::try_redis_get_else_try_database_get(
                        async {
                            Box::pin(kv_wrapper(
                                self,
                                KvOperation::<diesel_refund::Refund>::Scan(&pattern),
                                key,
                            ))
                            .await?
                            .try_into_scan()
                        },
                        database_call,
                    ))
                    .await
                }
            }
        }

        #[cfg(feature = "v2")]
        #[instrument(skip_all)]
        async fn find_refund_by_merchant_id_connector_transaction_id(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            connector_transaction_id: &str,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<Vec<diesel_refund::Refund>, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            diesel_refund::Refund::find_by_merchant_id_connector_transaction_id(
                &conn,
                merchant_id,
                connector_transaction_id,
            )
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(feature = "v1")]
        #[instrument(skip_all)]
        async fn update_refund(
            &self,
            this: diesel_refund::Refund,
            refund: diesel_refund::RefundUpdate,
            storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let merchant_id = this.merchant_id.clone();
            let payment_id = this.payment_id.clone();
            let key = PartitionKey::MerchantIdPaymentId {
                merchant_id: &merchant_id,
                payment_id: &payment_id,
            };
            let field = format!("pa_{}_ref_{}", &this.attempt_id, &this.refund_id);
            let storage_scheme = Box::pin(decide_storage_scheme::<_, diesel_refund::Refund>(
                self,
                storage_scheme,
                Op::Update(key.clone(), &field, Some(&this.updated_by)),
            ))
            .await;
            match storage_scheme {
                enums::MerchantStorageScheme::PostgresOnly => {
                    let conn = connection::pg_connection_write(self).await?;
                    this.update(&conn, refund)
                        .await
                        .map_err(|error| report!(errors::StorageError::from(error)))
                }
                enums::MerchantStorageScheme::RedisKv => {
                    let key_str = key.to_string();
                    let updated_refund = refund.clone().apply_changeset(this.clone());

                    let redis_value = updated_refund
                        .encode_to_string_of_json()
                        .change_context(errors::StorageError::SerializationFailed)?;

                    let redis_entry = kv::TypedSql {
                        op: kv::DBOperation::Update {
                            updatable: Box::new(kv::Updateable::RefundUpdate(Box::new(
                                kv::RefundUpdateMems {
                                    orig: this,
                                    update_data: refund,
                                },
                            ))),
                        },
                    };

                    Box::pin(kv_wrapper::<(), _, _>(
                        self,
                        KvOperation::Hset::<diesel_refund::Refund>(
                            (&field, redis_value),
                            redis_entry,
                        ),
                        key,
                    ))
                    .await
                    .map_err(|err| err.to_redis_failed_response(&key_str))?
                    .try_into_hset()
                    .change_context(errors::StorageError::KVError)?;

                    Ok(updated_refund)
                }
            }
        }

        #[cfg(feature = "v2")]
        #[instrument(skip_all)]
        async fn update_refund(
            &self,
            this: diesel_refund::Refund,
            refund: diesel_refund::RefundUpdate,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let conn = connection::pg_connection_write(self).await?;
            this.update_with_id(&conn, refund)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(feature = "v1")]
        #[instrument(skip_all)]
        async fn find_refund_by_merchant_id_refund_id(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            refund_id: &str,
            storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let database_call = || async {
                let conn = connection::pg_connection_read(self).await?;
                diesel_refund::Refund::find_by_merchant_id_refund_id(&conn, merchant_id, refund_id)
                    .await
                    .map_err(|error| report!(errors::StorageError::from(error)))
            };
            let storage_scheme = Box::pin(decide_storage_scheme::<_, diesel_refund::Refund>(
                self,
                storage_scheme,
                Op::Find,
            ))
            .await;
            match storage_scheme {
                enums::MerchantStorageScheme::PostgresOnly => database_call().await,
                enums::MerchantStorageScheme::RedisKv => {
                    let lookup_id =
                        format!("ref_ref_id_{}_{refund_id}", merchant_id.get_string_repr());
                    let lookup = fallback_reverse_lookup_not_found!(
                        self.get_lookup_by_lookup_id(&lookup_id, storage_scheme)
                            .await,
                        database_call().await
                    );

                    let key = PartitionKey::CombinationKey {
                        combination: &lookup.pk_id,
                    };
                    Box::pin(db_utils::try_redis_get_else_try_database_get(
                        async {
                            Box::pin(kv_wrapper(
                                self,
                                KvOperation::<diesel_refund::Refund>::HGet(&lookup.sk_id),
                                key,
                            ))
                            .await?
                            .try_into_hget()
                        },
                        database_call,
                    ))
                    .await
                }
            }
        }

        #[cfg(feature = "v1")]
        #[instrument(skip_all)]
        async fn find_refund_by_merchant_id_connector_refund_id_connector(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            connector_refund_id: &str,
            connector: &str,
            storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let database_call = || async {
                let conn = connection::pg_connection_read(self).await?;
                diesel_refund::Refund::find_by_merchant_id_connector_refund_id_connector(
                    &conn,
                    merchant_id,
                    connector_refund_id,
                    connector,
                )
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
            };
            let storage_scheme = Box::pin(decide_storage_scheme::<_, diesel_refund::Refund>(
                self,
                storage_scheme,
                Op::Find,
            ))
            .await;
            match storage_scheme {
                enums::MerchantStorageScheme::PostgresOnly => database_call().await,
                enums::MerchantStorageScheme::RedisKv => {
                    let lookup_id = format!(
                        "ref_connector_{}_{connector_refund_id}_{connector}",
                        merchant_id.get_string_repr()
                    );
                    let lookup = fallback_reverse_lookup_not_found!(
                        self.get_lookup_by_lookup_id(&lookup_id, storage_scheme)
                            .await,
                        database_call().await
                    );

                    let key = PartitionKey::CombinationKey {
                        combination: &lookup.pk_id,
                    };
                    Box::pin(db_utils::try_redis_get_else_try_database_get(
                        async {
                            Box::pin(kv_wrapper(
                                self,
                                KvOperation::<diesel_refund::Refund>::HGet(&lookup.sk_id),
                                key,
                            ))
                            .await?
                            .try_into_hget()
                        },
                        database_call,
                    ))
                    .await
                }
            }
        }

        #[cfg(feature = "v1")]
        #[instrument(skip_all)]
        async fn find_refund_by_payment_id_merchant_id(
            &self,
            payment_id: &common_utils::id_type::PaymentId,
            merchant_id: &common_utils::id_type::MerchantId,
            storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<Vec<diesel_refund::Refund>, errors::StorageError> {
            let database_call = || async {
                let conn = connection::pg_connection_read(self).await?;
                diesel_refund::Refund::find_by_payment_id_merchant_id(
                    &conn,
                    payment_id,
                    merchant_id,
                )
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
            };
            let storage_scheme = Box::pin(decide_storage_scheme::<_, diesel_refund::Refund>(
                self,
                storage_scheme,
                Op::Find,
            ))
            .await;
            match storage_scheme {
                enums::MerchantStorageScheme::PostgresOnly => database_call().await,
                enums::MerchantStorageScheme::RedisKv => {
                    let key = PartitionKey::MerchantIdPaymentId {
                        merchant_id,
                        payment_id,
                    };
                    Box::pin(db_utils::try_redis_get_else_try_database_get(
                        async {
                            Box::pin(kv_wrapper(
                                self,
                                KvOperation::<diesel_refund::Refund>::Scan("pa_*_ref_*"),
                                key,
                            ))
                            .await?
                            .try_into_scan()
                        },
                        database_call,
                    ))
                    .await
                }
            }
        }

        #[cfg(feature = "v2")]
        #[instrument(skip_all)]
        async fn find_refund_by_id(
            &self,
            id: &common_utils::id_type::GlobalRefundId,
            _storage_scheme: enums::MerchantStorageScheme,
        ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
            let conn = connection::pg_connection_read(self).await?;
            diesel_refund::Refund::find_by_global_id(&conn, id)
                .await
                .map_err(|error| report!(errors::StorageError::from(error)))
        }

        #[cfg(all(feature = "v1", feature = "olap"))]
        #[instrument(skip_all)]
        async fn filter_refund_by_constraints(
            &self,
            merchant_id: &common_utils::id_type::MerchantId,
            refund_details: &refunds::RefundListConstraints,
            _storage_scheme: enums::MerchantStorageScheme,
            limit: i64,


// File: crates/router/src/core/blocklist.rs
// Module: router
// Public functions: 4

pub mod transformers;
pub mod utils;

use api_models::blocklist as api_blocklist;

use crate::{
    core::errors::{self, RouterResponse},
    routes::SessionState,
    services,
    types::domain,
};

pub async fn add_entry_to_blocklist(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    body: api_blocklist::AddToBlocklistRequest,
) -> RouterResponse<api_blocklist::AddToBlocklistResponse> {
    utils::insert_entry_into_blocklist(
        &state,
        merchant_context.get_merchant_account().get_id(),
        body,
    )
    .await
    .map(services::ApplicationResponse::Json)
}

pub async fn remove_entry_from_blocklist(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    body: api_blocklist::DeleteFromBlocklistRequest,
) -> RouterResponse<api_blocklist::DeleteFromBlocklistResponse> {
    utils::delete_entry_from_blocklist(
        &state,
        merchant_context.get_merchant_account().get_id(),
        body,
    )
    .await
    .map(services::ApplicationResponse::Json)
}

pub async fn list_blocklist_entries(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    query: api_blocklist::ListBlocklistQuery,
) -> RouterResponse<Vec<api_blocklist::BlocklistResponse>> {
    utils::list_blocklist_entries_for_merchant(
        &state,
        merchant_context.get_merchant_account().get_id(),
        query,
    )
    .await
    .map(services::ApplicationResponse::Json)
}

pub async fn toggle_blocklist_guard(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    query: api_blocklist::ToggleBlocklistQuery,
) -> RouterResponse<api_blocklist::ToggleBlocklistResponse> {
    utils::toggle_blocklist_guard_for_merchant(
        &state,
        merchant_context.get_merchant_account().get_id(),
        query,
    )
    .await
    .map(services::ApplicationResponse::Json)
}


// Function: get_recovery_grpc_headers
// File: crates/router/src/routes/app.rs
// Module: router

pub fn get_recovery_grpc_headers(&self) -> GrpcRecoveryHeaders


// Struct: CreateFileResponse
// File: crates/api_models/src/files.rs
// Module: api_models
// Implementations: 0

pub struct CreateFileResponse


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

impl api::MandateSetup for for Stripe


// Struct: EpsInfo
// File: crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct EpsInfo


// Struct: ReturnArgs
// File: crates/test_utils/src/newman_runner.rs
// Module: test_utils
// Implementations: 0

pub struct ReturnArgs


// Struct: PaymentIncrementalAuthorization
// File: crates/router/src/core/payments/operations/payments_incremental_authorization.rs
// Module: router
// Implementations: 0

pub struct PaymentIncrementalAuthorization


// Struct: OrderInformation
// File: crates/hyperswitch_connectors/src/connectors/barclaycard/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct OrderInformation


// Struct: ReconStatus
// File: crates/api_models/src/user/dashboard_metadata.rs
// Module: api_models
// Implementations: 0

pub struct ReconStatus


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

impl api::RefundSync for for Peachpayments


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

pub struct MerchantDefinedInformation


// Struct: PazeDynamicData
// File: crates/hyperswitch_domain_models/src/router_data.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct PazeDynamicData


// Function: get_sdk_event_filter_for_dimension
// File: crates/analytics/src/sdk_events/filters.rs
// Module: analytics

pub fn get_sdk_event_filter_for_dimension<T>(
    dimension: SdkEventDimensions,
    publishable_key: &String,
    time_range: &TimeRange,
    pool: &T,
) -> FiltersResult<Vec<SdkEventFilter>>
where
    T: AnalyticsDataSource + SdkEventFilterAnalytics,
    PrimitiveDateTime: ToSql<T>,
    AnalyticsCollection: ToSql<T>,
    Granularity: GroupByClause<T>,
    Aggregate<&'static str>: ToSql<T>,
    Window<&'static str>: ToSql<T>,


// Struct: StoreGenericReq
// File: crates/router/src/core/payment_methods/transformers.rs
// Module: router
// Implementations: 0

pub struct StoreGenericReq


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

impl api::RefundSync for for HyperswitchVault


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

impl DecisionEngineSuccessRateData


// Function: redis_connection
// File: crates/router/src/connection.rs
// Module: router

pub fn redis_connection(
    conf: &crate::configs::Settings,
) -> redis_interface::RedisConnectionPool


// Trait: Tokenizable
// File: crates/router/src/types.rs
// Module: router

pub trait Tokenizable


// Function: transform_incoming_webhook
// File: crates/external_services/src/grpc_client/unified_connector_service.rs
// Module: external_services

// Documentation: Transforms incoming webhook through UCS

pub fn transform_incoming_webhook(
        &self,
        webhook_transform_request: PaymentServiceTransformRequest,
        connector_auth_metadata: ConnectorAuthMetadata,
        grpc_headers: GrpcHeadersUcs,
    ) -> UnifiedConnectorServiceResult<tonic::Response<PaymentServiceTransformResponse>>


// Implementation: impl Razorpay
// File: crates/hyperswitch_connectors/src/connectors/razorpay.rs
// Module: hyperswitch_connectors
// Methods: 1 total (1 public)

impl Razorpay


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

pub fn payouts_retrieve_core(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: Option<id_type::ProfileId>,
    req: payouts::PayoutRetrieveRequest,
) -> RouterResponse<payouts::PayoutCreateResponse>


// Module Structure
// File: crates/diesel_models/src/lib.rs
// Module: diesel_models

// Public submodules:
pub mod address;
pub mod api_keys;
pub mod blocklist_lookup;
pub mod business_profile;
pub mod capture;
pub mod cards_info;
pub mod configs;
pub mod authentication;
pub mod authorization;
pub mod blocklist;
pub mod blocklist_fingerprint;
pub mod callback_mapper;
pub mod customers;
pub mod dispute;
pub mod dynamic_routing_stats;
// ... and 41 more

// Public exports:
pub use self::{
    address::*, api_keys::*, callback_mapper::*, cards_info::*, configs::*, customers::*,
    dispute::*, ephemeral_key::*, events::*, file::*, generic_link::*,
    hyperswitch_ai_interaction::*, locker_mock_up::*, mandate::*, merchant_account::*,
    merchant_connector_account::*, payment_attempt::*, payment_intent::*, payment_method::*,
    payout_attempt::*, payouts::*, process_tracker::*, refund::*, reverse_lookup::*,
    user_authentication_method::*,
};


// Function: payment_method_update_api
// File: crates/openapi/src/routes/payment_method.rs
// Module: openapi

pub fn payment_method_update_api()


// Function: update_all_merchant_accounts
// File: crates/diesel_models/src/query/merchant_account.rs
// Module: diesel_models

pub fn update_all_merchant_accounts(
        conn: &PgPooledConn,
        merchant_account: MerchantAccountUpdateInternal,
    ) -> StorageResult<Vec<Self>>


// Struct: RefundResponse
// File: crates/hyperswitch_connectors/src/connectors/boku/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RefundResponse


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

impl api::PaymentVoid for for Taxjar


// Struct: RetrieveFileRequestData
// File: crates/hyperswitch_domain_models/src/router_request_types.rs
// Module: hyperswitch_domain_models
// Implementations: 0

pub struct RetrieveFileRequestData


// Struct: GetVaultFingerprint
// File: crates/router/src/types/payment_methods.rs
// Module: router
// Implementations: 1
// Traits: VaultingInterface

pub struct GetVaultFingerprint


// File: crates/router/src/compatibility/stripe/setup_intents.rs
// Module: router
// Public functions: 4

pub mod types;
#[cfg(feature = "v1")]
use actix_web::{web, HttpRequest, HttpResponse};
#[cfg(feature = "v1")]
use api_models::payments as payment_types;
#[cfg(feature = "v1")]
use error_stack::report;
#[cfg(feature = "v1")]
use router_env::{instrument, tracing, Flow};

#[cfg(feature = "v1")]
use crate::{
    compatibility::{
        stripe::{errors, payment_intents::types as stripe_payment_types},
        wrap,
    },
    core::{api_locking, payments},
    routes,
    services::{api, authentication as auth},
    types::{api as api_types, domain},
};

#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::PaymentsCreate))]
pub async fn setup_intents_create(
    state: web::Data<routes::AppState>,
    qs_config: web::Data<serde_qs::Config>,
    req: HttpRequest,
    form_payload: web::Bytes,
) -> HttpResponse {
    let payload: types::StripeSetupIntentRequest = match qs_config.deserialize_bytes(&form_payload)
    {
        Ok(p) => p,
        Err(err) => {
            return api::log_and_return_error_response(report!(errors::StripeErrorCode::from(err)))
        }
    };

    let create_payment_req: payment_types::PaymentsRequest =
        match payment_types::PaymentsRequest::try_from(payload) {
            Ok(req) => req,
            Err(err) => return api::log_and_return_error_response(err),
        };

    let flow = Flow::PaymentsCreate;

    Box::pin(wrap::compatibility_api_wrap::<
        _,
        _,
        _,
        _,
        _,
        types::StripeSetupIntentResponse,
        errors::StripeErrorCode,
        _,
    >(
        flow,
        state.into_inner(),
        &req,
        create_payment_req,
        |state, auth: auth::AuthenticationData, req, req_state| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payments::payments_core::<
                api_types::SetupMandate,
                api_types::PaymentsResponse,
                _,
                _,
                _,
                payments::PaymentData<api_types::SetupMandate>,
            >(
                state,
                req_state,
                merchant_context,
                None,
                payments::PaymentCreate,
                req,
                api::AuthFlow::Merchant,
                payments::CallConnectorAction::Trigger,
                None,
                hyperswitch_domain_models::payments::HeaderPayload::default(),
            )
        },
        &auth::HeaderAuth(auth::ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        }),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::PaymentsRetrieveForceSync))]
pub async fn setup_intents_retrieve(
    state: web::Data<routes::AppState>,
    req: HttpRequest,
    path: web::Path<common_utils::id_type::PaymentId>,
    query_payload: web::Query<stripe_payment_types::StripePaymentRetrieveBody>,
) -> HttpResponse {
    let payload = payment_types::PaymentsRetrieveRequest {
        resource_id: api_types::PaymentIdType::PaymentIntentId(path.into_inner()),
        merchant_id: None,
        force_sync: true,
        connector: None,
        param: None,
        merchant_connector_details: None,
        client_secret: query_payload.client_secret.clone(),
        expand_attempts: None,
        expand_captures: None,
        all_keys_required: None,
    };

    let api_auth = auth::ApiKeyAuth {
        is_connected_allowed: false,
        is_platform_allowed: false,
    };

    let (auth_type, auth_flow) =
        match auth::check_client_secret_and_get_auth(req.headers(), &payload, api_auth) {
            Ok(auth) => auth,
            Err(err) => return api::log_and_return_error_response(report!(err)),
        };

    let flow = Flow::PaymentsRetrieveForceSync;

    Box::pin(wrap::compatibility_api_wrap::<
        _,
        _,
        _,
        _,
        _,
        types::StripeSetupIntentResponse,
        errors::StripeErrorCode,
        _,
    >(
        flow,
        state.into_inner(),
        &req,
        payload,
        |state, auth, payload, req_state| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payments::payments_core::<
                api_types::PSync,
                api_types::PaymentsResponse,
                _,
                _,
                _,
                payments::PaymentData<api_types::PSync>,
            >(
                state,
                req_state,
                merchant_context,
                None,
                payments::PaymentStatus,
                payload,
                auth_flow,
                payments::CallConnectorAction::Trigger,
                None,
                hyperswitch_domain_models::payments::HeaderPayload::default(),
            )
        },
        &*auth_type,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::PaymentsUpdate))]
pub async fn setup_intents_update(
    state: web::Data<routes::AppState>,
    qs_config: web::Data<serde_qs::Config>,
    req: HttpRequest,
    form_payload: web::Bytes,
    path: web::Path<common_utils::id_type::PaymentId>,
) -> HttpResponse {
    let setup_id = path.into_inner();
    let stripe_payload: types::StripeSetupIntentRequest = match qs_config
        .deserialize_bytes(&form_payload)
    {
        Ok(p) => p,
        Err(err) => {
            return api::log_and_return_error_response(report!(errors::StripeErrorCode::from(err)))
        }
    };

    let mut payload: payment_types::PaymentsRequest =
        match payment_types::PaymentsRequest::try_from(stripe_payload) {
            Ok(req) => req,
            Err(err) => return api::log_and_return_error_response(err),
        };
    payload.payment_id = Some(api_types::PaymentIdType::PaymentIntentId(setup_id));

    let api_auth = auth::ApiKeyAuth {
        is_connected_allowed: false,
        is_platform_allowed: false,
    };

    let (auth_type, auth_flow) =
        match auth::check_client_secret_and_get_auth(req.headers(), &payload, api_auth) {
            Ok(auth) => auth,
            Err(err) => return api::log_and_return_error_response(err),
        };

    let flow = Flow::PaymentsUpdate;

    Box::pin(wrap::compatibility_api_wrap::<
        _,
        _,
        _,
        _,
        _,
        types::StripeSetupIntentResponse,
        errors::StripeErrorCode,
        _,
    >(
        flow,
        state.into_inner(),
        &req,
        payload,
        |state, auth, req, req_state| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payments::payments_core::<
                api_types::SetupMandate,
                api_types::PaymentsResponse,
                _,
                _,
                _,
                payments::PaymentData<api_types::SetupMandate>,
            >(
                state,
                req_state,
                merchant_context,
                None,
                payments::PaymentUpdate,
                req,
                auth_flow,
                payments::CallConnectorAction::Trigger,
                None,
                hyperswitch_domain_models::payments::HeaderPayload::default(),
            )
        },
        &*auth_type,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::PaymentsConfirm))]
pub async fn setup_intents_confirm(
    state: web::Data<routes::AppState>,
    qs_config: web::Data<serde_qs::Config>,
    req: HttpRequest,
    form_payload: web::Bytes,
    path: web::Path<common_utils::id_type::PaymentId>,
) -> HttpResponse {
    let setup_id = path.into_inner();
    let stripe_payload: types::StripeSetupIntentRequest = match qs_config
        .deserialize_bytes(&form_payload)
    {
        Ok(p) => p,
        Err(err) => {
            return api::log_and_return_error_response(report!(errors::StripeErrorCode::from(err)))
        }
    };

    let mut payload: payment_types::PaymentsRequest =
        match payment_types::PaymentsRequest::try_from(stripe_payload) {
            Ok(req) => req,
            Err(err) => return api::log_and_return_error_response(err),
        };
    payload.payment_id = Some(api_types::PaymentIdType::PaymentIntentId(setup_id));
    payload.confirm = Some(true);

    let api_auth = auth::ApiKeyAuth {
        is_connected_allowed: false,
        is_platform_allowed: false,
    };

    let (auth_type, auth_flow) =
        match auth::check_client_secret_and_get_auth(req.headers(), &payload, api_auth) {
            Ok(auth) => auth,
            Err(err) => return api::log_and_return_error_response(err),
        };

    let flow = Flow::PaymentsConfirm;

    Box::pin(wrap::compatibility_api_wrap::<
        _,
        _,
        _,
        _,
        _,
        types::StripeSetupIntentResponse,
        errors::StripeErrorCode,
        _,
    >(
        flow,
        state.into_inner(),
        &req,
        payload,
        |state, auth, req, req_state| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payments::payments_core::<
                api_types::SetupMandate,
                api_types::PaymentsResponse,
                _,
                _,
                _,
                payments::PaymentData<api_types::SetupMandate>,
            >(
                state,
                req_state,
                merchant_context,
                None,
                payments::PaymentConfirm,
                req,
                auth_flow,
                payments::CallConnectorAction::Trigger,
                None,
                hyperswitch_domain_models::payments::HeaderPayload::default(),
            )
        },
        &*auth_type,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


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

pub struct PaymentMethodResponse


// Function: reinitialize_limbo_processes
// File: crates/diesel_models/src/query/process_tracker.rs
// Module: diesel_models

pub fn reinitialize_limbo_processes(
        conn: &PgPooledConn,
        ids: Vec<String>,
        schedule_time: PrimitiveDateTime,
    ) -> StorageResult<usize>


// Function: check_two_factor_auth_status_with_attempts
// File: crates/router/src/routes/user.rs
// Module: router

pub fn check_two_factor_auth_status_with_attempts(
    state: web::Data<AppState>,
    req: HttpRequest,
) -> HttpResponse


// File: crates/hyperswitch_domain_models/src/api.rs
// Module: hyperswitch_domain_models
// Public functions: 1
// Public structs: 7

use std::{collections::HashSet, fmt::Display};

use common_utils::{
    events::{ApiEventMetric, ApiEventsType},
    impl_api_event_type,
};

use super::payment_method_data::PaymentMethodData;

#[derive(Debug, PartialEq)]
pub enum ApplicationResponse<R> {
    Json(R),
    StatusOk,
    TextPlain(String),
    JsonForRedirection(api_models::payments::RedirectionResponse),
    Form(Box<RedirectionFormData>),
    PaymentLinkForm(Box<PaymentLinkAction>),
    FileData((Vec<u8>, mime::Mime)),
    JsonWithHeaders((R, Vec<(String, masking::Maskable<String>)>)),
    GenericLinkForm(Box<GenericLinks>),
}

impl<R> ApplicationResponse<R> {
    /// Get the json response from response
    #[inline]
    pub fn get_json_body(
        self,
    ) -> common_utils::errors::CustomResult<R, common_utils::errors::ValidationError> {
        match self {
            Self::Json(body) | Self::JsonWithHeaders((body, _)) => Ok(body),
            Self::TextPlain(_)
            | Self::JsonForRedirection(_)
            | Self::Form(_)
            | Self::PaymentLinkForm(_)
            | Self::FileData(_)
            | Self::GenericLinkForm(_)
            | Self::StatusOk => Err(common_utils::errors::ValidationError::InvalidValue {
                message: "expected either Json or JsonWithHeaders Response".to_string(),
            }
            .into()),
        }
    }
}

impl<T: ApiEventMetric> ApiEventMetric for ApplicationResponse<T> {
    fn get_api_event_type(&self) -> Option<ApiEventsType> {
        match self {
            Self::Json(r) => r.get_api_event_type(),
            Self::JsonWithHeaders((r, _)) => r.get_api_event_type(),
            _ => None,
        }
    }
}

impl_api_event_type!(Miscellaneous, (PaymentLinkFormData, GenericLinkFormData));

#[derive(Debug, PartialEq)]
pub struct RedirectionFormData {
    pub redirect_form: crate::router_response_types::RedirectForm,
    pub payment_method_data: Option<PaymentMethodData>,
    pub amount: String,
    pub currency: String,
}

#[derive(Debug, Eq, PartialEq)]
pub enum PaymentLinkAction {
    PaymentLinkFormData(PaymentLinkFormData),
    PaymentLinkStatus(PaymentLinkStatusData),
}

#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct PaymentLinkFormData {
    pub js_script: String,
    pub css_script: String,
    pub sdk_url: url::Url,
    pub html_meta_tags: String,
}

#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct PaymentLinkStatusData {
    pub js_script: String,
    pub css_script: String,
}

#[derive(Debug, Eq, PartialEq)]
pub struct GenericLinks {
    pub allowed_domains: HashSet<String>,
    pub data: GenericLinksData,
    pub locale: String,
}

#[derive(Debug, Eq, PartialEq)]
pub enum GenericLinksData {
    ExpiredLink(GenericExpiredLinkData),
    PaymentMethodCollect(GenericLinkFormData),
    PayoutLink(GenericLinkFormData),
    PayoutLinkStatus(GenericLinkStatusData),
    PaymentMethodCollectStatus(GenericLinkStatusData),
    SecurePaymentLink(PaymentLinkFormData),
}

impl Display for GenericLinksData {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match *self {
                Self::ExpiredLink(_) => "ExpiredLink",
                Self::PaymentMethodCollect(_) => "PaymentMethodCollect",
                Self::PayoutLink(_) => "PayoutLink",
                Self::PayoutLinkStatus(_) => "PayoutLinkStatus",
                Self::PaymentMethodCollectStatus(_) => "PaymentMethodCollectStatus",
                Self::SecurePaymentLink(_) => "SecurePaymentLink",
            }
        )
    }
}

#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct GenericExpiredLinkData {
    pub title: String,
    pub message: String,
    pub theme: String,
}

#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct GenericLinkFormData {
    pub js_data: String,
    pub css_data: String,
    pub sdk_url: url::Url,
    pub html_meta_tags: String,
}

#[derive(Debug, Eq, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct GenericLinkStatusData {
    pub js_data: String,
    pub css_data: String,
}


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

pub struct AffirmRsyncResponse


        Ok(get_status(response.kind.as_str()))
    }

    fn get_webhook_resource_object(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        let notif = get_webhook_object_from_body(request.body)
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;

        let response = decode_webhook_payload(notif.bt_payload.replace('\n', "").as_bytes())?;

        Ok(Box::new(response))
    }

    fn get_webhook_api_response(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
        _error_kind: Option<IncomingWebhookFlowError>,
    ) -> CustomResult<ApplicationResponse<serde_json::Value>, errors::ConnectorError> {
        Ok(ApplicationResponse::TextPlain("[accepted]".to_string()))
    }

    fn get_dispute_details(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<DisputePayload, errors::ConnectorError> {
        let notif = get_webhook_object_from_body(request.body)
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;

        let response = decode_webhook_payload(notif.bt_payload.replace('\n', "").as_bytes())?;
        match response.dispute {
            Some(dispute_data) => Ok(DisputePayload {
                amount: convert_amount(
                    self.amount_converter_webhooks,
                    dispute_data.amount_disputed,
                    dispute_data.currency_iso_code,
                )?,
                currency: dispute_data.currency_iso_code,
                dispute_stage: transformers::get_dispute_stage(dispute_data.kind.as_str())?,
                connector_dispute_id: dispute_data.id,
                connector_reason: dispute_data.reason,
                connector_reason_code: dispute_data.reason_code,
                challenge_required_by: dispute_data.reply_by_date,
                connector_status: dispute_data.status,
                created_at: dispute_data.created_at,
                updated_at: dispute_data.updated_at,
            }),
            None => Err(errors::ConnectorError::WebhookResourceObjectNotFound)?,
        }
    }
}

fn get_matching_webhook_signature(
    signature_pairs: Vec<(&str, &str)>,
    secret: String,
) -> Option<String> {
    for (public_key, signature) in signature_pairs {
        if *public_key == secret {
            return Some(signature.to_string());
        }
    }
    None
}

fn get_webhook_object_from_body(
    body: &[u8],
) -> CustomResult<transformers::BraintreeWebhookResponse, ParsingError> {
    serde_urlencoded::from_bytes::<transformers::BraintreeWebhookResponse>(body)
        .change_context(ParsingError::StructParseFailure("BraintreeWebhookResponse"))
}

fn decode_webhook_payload(
    payload: &[u8],
) -> CustomResult<transformers::Notification, errors::ConnectorError> {
    let decoded_response = BASE64_ENGINE
        .decode(payload)
        .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;

    let xml_response = String::from_utf8(decoded_response)
        .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;

    xml_response
        .parse_xml::<transformers::Notification>()
        .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)
}

impl ConnectorRedirectResponse for Braintree {
    fn get_flow_type(
        &self,
        _query_params: &str,
        json_payload: Option<serde_json::Value>,
        action: PaymentAction,
    ) -> CustomResult<CallConnectorAction, errors::ConnectorError> {
        match action {
            PaymentAction::PSync => match json_payload {
                Some(payload) => {
                    let redirection_response: transformers::BraintreeRedirectionResponse =
                        serde_json::from_value(payload).change_context(
                            errors::ConnectorError::MissingConnectorRedirectionPayload {
                                field_name: "redirection_response",
                            },
                        )?;
                    let braintree_payload =
                        serde_json::from_str::<transformers::BraintreeThreeDsErrorResponse>(
                            &redirection_response.authentication_response,
                        );
                    let (error_code, error_message) = match braintree_payload {
                        Ok(braintree_response_payload) => (
                            braintree_response_payload.code,
                            braintree_response_payload.message,
                        ),
                        Err(_) => (
                            NO_ERROR_CODE.to_string(),
                            redirection_response.authentication_response,
                        ),
                    };
                    Ok(CallConnectorAction::StatusUpdate {
                        status: enums::AttemptStatus::AuthenticationFailed,
                        error_code: Some(error_code),
                        error_message: Some(error_message),
                    })
                }
                None => Ok(CallConnectorAction::Avoid),
            },
            PaymentAction::CompleteAuthorize
            | PaymentAction::PaymentAuthenticateCompleteAuthorize => {
                Ok(CallConnectorAction::Trigger)
            }
        }
    }
}

impl ConnectorIntegration<CompleteAuthorize, CompleteAuthorizeData, PaymentsResponseData>
    for Braintree
{
    fn get_headers(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }
    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }
    fn get_url(
        &self,
        _req: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(self.base_url(connectors).to_string())
    }
    fn get_request_body(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_converter,
            req.request.minor_amount,
            req.request.currency,
        )?;
        let connector_router_data = braintree::BraintreeRouterData::try_from((amount, req))?;

        let connector_req =
            transformers::BraintreePaymentsRequest::try_from(&connector_router_data)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsCompleteAuthorizeType::get_url(
                    self, req, connectors,
                )?)
                .attach_default_headers()
                .headers(PaymentsCompleteAuthorizeType::get_headers(
                    self, req, connectors,
                )?)
                .set_body(PaymentsCompleteAuthorizeType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }
    fn handle_response(
        &self,
        data: &PaymentsCompleteAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCompleteAuthorizeRouterData, errors::ConnectorError> {
        match PaymentsCompleteAuthorizeRequestData::is_auto_capture(&data.request)? {
            true => {
                let response: transformers::BraintreeCompleteChargeResponse = res
                    .response
                    .parse_struct("Braintree PaymentsResponse")
                    .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
                event_builder.map(|i| i.set_response_body(&response));
                router_env::logger::info!(connector_response=?response);
                RouterData::try_from(ResponseRouterData {
                    response,
                    data: data.clone(),
                    http_code: res.status_code,
                })
            }
            false => {
                let response: transformers::BraintreeCompleteAuthResponse = res
                    .response
                    .parse_struct("Braintree AuthResponse")
                    .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
                event_builder.map(|i| i.set_response_body(&response));
                router_env::logger::info!(connector_response=?response);
                RouterData::try_from(ResponseRouterData {
                    response,
                    data: data.clone(),
                    http_code: res.status_code,
                })
            }
        }
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        self.build_error_response(res, event_builder)
    }
}

static BRAINTREE_SUPPORTED_PAYMENT_METHODS: LazyLock<SupportedPaymentMethods> =
    LazyLock::new(|| {
        let supported_capture_methods = vec![
            enums::CaptureMethod::Automatic,
            enums::CaptureMethod::Manual,
            enums::CaptureMethod::SequentialAutomatic,
        ];

        let supported_card_network = vec![
            common_enums::CardNetwork::AmericanExpress,
            common_enums::CardNetwork::Discover,
            common_enums::CardNetwork::JCB,
            common_enums::CardNetwork::UnionPay,
            common_enums::CardNetwork::Mastercard,
            common_enums::CardNetwork::Visa,
        ];

        let mut braintree_supported_payment_methods = SupportedPaymentMethods::new();

        braintree_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Credit,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: Some(
                    api_models::feature_matrix::PaymentMethodSpecificFeatures::Card({
                        api_models::feature_matrix::CardSpecificFeatures {
                            three_ds: common_enums::FeatureStatus::Supported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network.clone(),
                        }
                    }),
                ),
            },
        );

        braintree_supported_payment_methods.add(
            enums::PaymentMethod::Card,
            enums::PaymentMethodType::Debit,
            PaymentMethodDetails {
                mandates: enums::FeatureStatus::Supported,
                refunds: enums::FeatureStatus::Supported,
                supported_capture_methods: supported_capture_methods.clone(),
                specific_features: Some(
                    api_models::feature_matrix::PaymentMethodSpecificFeatures::Card({
                        api_models::feature_matrix::CardSpecificFeatures {
                            three_ds: common_enums::FeatureStatus::Supported,
                            no_three_ds: common_enums::FeatureStatus::Supported,
                            supported_card_networks: supported_card_network.clone(),
                        }
                    }),
                ),
            },
        );
        braintree_supported_payment_methods
    });

static BRAINTREE_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
    display_name: "Braintree",
    description:
        "Braintree, a PayPal service, offers a full-stack payment platform that simplifies accepting payments in your app or website, supporting various payment methods including credit cards and PayPal.",
    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
    integration_status: enums::ConnectorIntegrationStatus::Live,
};

static BRAINTREE_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 2] =
    [enums::EventClass::Payments, enums::EventClass::Refunds];

impl ConnectorSpecifications for Braintree {
    fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
        Some(&BRAINTREE_CONNECTOR_INFO)
    }

    fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
        Some(&*BRAINTREE_SUPPORTED_PAYMENT_METHODS)
    }

    fn get_supported_webhook_flows(&self) -> Option<&'static [enums::EventClass]> {
        Some(&BRAINTREE_SUPPORTED_WEBHOOK_FLOWS)
    }
}


// Struct: EncryptDataResponse
// File: crates/common_utils/src/types/keymanager.rs
// Module: common_utils
// Implementations: 0

pub struct EncryptDataResponse


// Struct: CreditorAccount
// File: crates/hyperswitch_connectors/src/connectors/nordea/requests.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CreditorAccount


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

pub fn new() -> &'static Self


// Module Structure
// File: crates/hyperswitch_connectors/src/connectors/bluecode.rs
// Module: hyperswitch_connectors

// Public submodules:
pub mod transformers;


// Function: migrate_cards_info
// File: crates/router/src/routes/cards_info.rs
// Module: router

pub fn migrate_cards_info(
    state: web::Data<AppState>,
    req: HttpRequest,
    MultipartForm(form)


// File: crates/diesel_models/src/query/user.rs
// Module: diesel_models
// Public functions: 7

use common_utils::pii;
use diesel::{associations::HasTable, ExpressionMethods};

pub mod sample_data;
pub mod theme;

use crate::{
    query::generics, schema::users::dsl as users_dsl, user::*, PgPooledConn, StorageResult,
};

impl UserNew {
    pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<User> {
        generics::generic_insert(conn, self).await
    }
}

impl User {
    pub async fn find_by_user_email(
        conn: &PgPooledConn,
        user_email: &pii::Email,
    ) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            users_dsl::email.eq(user_email.to_owned()),
        )
        .await
    }

    pub async fn find_by_user_id(conn: &PgPooledConn, user_id: &str) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            users_dsl::user_id.eq(user_id.to_owned()),
        )
        .await
    }

    pub async fn update_by_user_id(
        conn: &PgPooledConn,
        user_id: &str,
        user_update: UserUpdate,
    ) -> StorageResult<Self> {
        generics::generic_update_with_unique_predicate_get_result::<
            <Self as HasTable>::Table,
            _,
            _,
            _,
        >(
            conn,
            users_dsl::user_id.eq(user_id.to_owned()),
            UserUpdateInternal::from(user_update),
        )
        .await
    }

    pub async fn update_by_user_email(
        conn: &PgPooledConn,
        user_email: &pii::Email,
        user_update: UserUpdate,
    ) -> StorageResult<Self> {
        generics::generic_update_with_unique_predicate_get_result::<
            <Self as HasTable>::Table,
            _,
            _,
            _,
        >(
            conn,
            users_dsl::email.eq(user_email.to_owned()),
            UserUpdateInternal::from(user_update),
        )
        .await
    }

    pub async fn delete_by_user_id(conn: &PgPooledConn, user_id: &str) -> StorageResult<bool> {
        generics::generic_delete::<<Self as HasTable>::Table, _>(
            conn,
            users_dsl::user_id.eq(user_id.to_owned()),
        )
        .await
    }

    pub async fn find_users_by_user_ids(
        conn: &PgPooledConn,
        user_ids: Vec<String>,
    ) -> StorageResult<Vec<Self>> {
        generics::generic_filter::<
            <Self as HasTable>::Table,
            _,
            <<Self as HasTable>::Table as diesel::Table>::PrimaryKey,
            _,
        >(conn, users_dsl::user_id.eq_any(user_ids), None, None, None)
        .await
    }
}


// Implementation: impl UserRoleInterface for for MockDb
// File: crates/router/src/db/user_role.rs
// Module: router
// Methods: 7 total (0 public)

impl UserRoleInterface for for MockDb


// Implementation: impl ConstraintGraph
// File: crates/hyperswitch_constraint_graph/src/graph.rs
// Module: hyperswitch_constraint_graph
// Methods: 5 total (2 public)

impl ConstraintGraph


// Function: get_connector_data_if_separate_authn_supported
// File: crates/router/src/core/authentication/utils.rs
// Module: router

pub fn get_connector_data_if_separate_authn_supported(
    connector_call_type: &api::ConnectorCallType,
) -> Option<api::ConnectorData>


// Struct: OpennodePaymentsResponse
// File: crates/hyperswitch_connectors/src/connectors/opennode/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct OpennodePaymentsResponse


// Function: payouts_retrieve
// File: crates/openapi/src/routes/payouts.rs
// Module: openapi

pub fn payouts_retrieve()


// Function: find_by_address_id
// File: crates/diesel_models/src/query/address.rs
// Module: diesel_models

pub fn find_by_address_id(conn: &PgPooledConn, address_id: &str) -> StorageResult<Self>


// Struct: RefundResponse
// File: crates/hyperswitch_connectors/src/connectors/bamboraapac/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct RefundResponse