        key_store: &domain::MerchantKeyStore,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
        limit: Option<i64>,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<domain::PaymentMethod>, errors::StorageError> {
        self.diesel_store
            .find_payment_method_by_customer_id_merchant_id_status(
                state,
                key_store,
                customer_id,
                merchant_id,
                status,
                limit,
                storage_scheme,
            )
            .await
    }

    #[cfg(feature = "v2")]
    async fn find_payment_method_by_global_customer_id_merchant_id_status(
        &self,
        state: &KeyManagerState,
        key_store: &domain::MerchantKeyStore,
        customer_id: &id_type::GlobalCustomerId,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
        limit: Option<i64>,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<domain::PaymentMethod>, errors::StorageError> {
        self.diesel_store
            .find_payment_method_by_global_customer_id_merchant_id_status(
                state,
                key_store,
                customer_id,
                merchant_id,
                status,
                limit,
                storage_scheme,
            )
            .await
    }

    #[cfg(feature = "v1")]
    async fn get_payment_method_count_by_customer_id_merchant_id_status(
        &self,
        customer_id: &id_type::CustomerId,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
    ) -> CustomResult<i64, errors::StorageError> {
        self.diesel_store
            .get_payment_method_count_by_customer_id_merchant_id_status(
                customer_id,
                merchant_id,
                status,
            )
            .await
    }

    async fn get_payment_method_count_by_merchant_id_status(
        &self,
        merchant_id: &id_type::MerchantId,
        status: common_enums::PaymentMethodStatus,
    ) -> CustomResult<i64, errors::StorageError> {
        self.diesel_store
            .get_payment_method_count_by_merchant_id_status(merchant_id, status)
            .await
    }

    #[cfg(feature = "v1")]
    async fn find_payment_method_by_locker_id(
        &self,
        state: &KeyManagerState,
        key_store: &domain::MerchantKeyStore,
        locker_id: &str,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<domain::PaymentMethod, errors::StorageError> {
        self.diesel_store
            .find_payment_method_by_locker_id(state, key_store, locker_id, storage_scheme)
            .await
    }

    async fn insert_payment_method(
        &self,
        state: &KeyManagerState,
        key_store: &domain::MerchantKeyStore,
        m: domain::PaymentMethod,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<domain::PaymentMethod, errors::StorageError> {
        self.diesel_store
            .insert_payment_method(state, key_store, m, storage_scheme)
            .await
    }

    async fn update_payment_method(
        &self,
        state: &KeyManagerState,
        key_store: &domain::MerchantKeyStore,
        payment_method: domain::PaymentMethod,
        payment_method_update: storage::PaymentMethodUpdate,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<domain::PaymentMethod, errors::StorageError> {
        self.diesel_store
            .update_payment_method(
                state,
                key_store,
                payment_method,
                payment_method_update,
                storage_scheme,
            )
            .await
    }

    #[cfg(feature = "v1")]
    async fn delete_payment_method_by_merchant_id_payment_method_id(
        &self,
        state: &KeyManagerState,
        key_store: &domain::MerchantKeyStore,
        merchant_id: &id_type::MerchantId,
        payment_method_id: &str,
    ) -> CustomResult<domain::PaymentMethod, errors::StorageError> {
        self.diesel_store
            .delete_payment_method_by_merchant_id_payment_method_id(
                state,
                key_store,
                merchant_id,
                payment_method_id,
            )
            .await
    }

    #[cfg(feature = "v2")]
    async fn delete_payment_method(
        &self,
        state: &KeyManagerState,
        key_store: &domain::MerchantKeyStore,
        payment_method: domain::PaymentMethod,
    ) -> CustomResult<domain::PaymentMethod, errors::StorageError> {
        self.diesel_store
            .delete_payment_method(state, key_store, payment_method)
            .await
    }

    #[cfg(feature = "v2")]
    async fn find_payment_method_by_fingerprint_id(
        &self,
        state: &KeyManagerState,
        key_store: &domain::MerchantKeyStore,
        fingerprint_id: &str,
    ) -> CustomResult<domain::PaymentMethod, errors::StorageError> {
        self.diesel_store
            .find_payment_method_by_fingerprint_id(state, key_store, fingerprint_id)
            .await
    }
}

#[cfg(not(feature = "payouts"))]
impl PayoutAttemptInterface for KafkaStore {}

#[cfg(feature = "payouts")]
#[async_trait::async_trait]
impl PayoutAttemptInterface for KafkaStore {
    type Error = errors::StorageError;

    async fn find_payout_attempt_by_merchant_id_merchant_order_reference_id(
        &self,
        merchant_id: &id_type::MerchantId,
        merchant_order_reference_id: &str,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::PayoutAttempt, errors::StorageError> {
        self.diesel_store
            .find_payout_attempt_by_merchant_id_merchant_order_reference_id(
                merchant_id,
                merchant_order_reference_id,
                storage_scheme,
            )
            .await
    }

    async fn find_payout_attempt_by_merchant_id_payout_attempt_id(
        &self,
        merchant_id: &id_type::MerchantId,
        payout_attempt_id: &str,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::PayoutAttempt, errors::StorageError> {
        self.diesel_store
            .find_payout_attempt_by_merchant_id_payout_attempt_id(
                merchant_id,
                payout_attempt_id,
                storage_scheme,
            )
            .await
    }

    async fn find_payout_attempt_by_merchant_id_connector_payout_id(
        &self,
        merchant_id: &id_type::MerchantId,
        connector_payout_id: &str,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::PayoutAttempt, errors::StorageError> {
        self.diesel_store
            .find_payout_attempt_by_merchant_id_connector_payout_id(
                merchant_id,
                connector_payout_id,
                storage_scheme,
            )
            .await
    }

    async fn update_payout_attempt(
        &self,
        this: &storage::PayoutAttempt,
        payout_attempt_update: storage::PayoutAttemptUpdate,
        payouts: &storage::Payouts,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::PayoutAttempt, errors::StorageError> {
        let updated_payout_attempt = self
            .diesel_store
            .update_payout_attempt(this, payout_attempt_update, payouts, storage_scheme)
            .await?;
        if let Err(err) = self
            .kafka_producer
            .log_payout(
                &KafkaPayout::from_storage(payouts, &updated_payout_attempt),
                Some(KafkaPayout::from_storage(payouts, this)),
                self.tenant_id.clone(),
            )
            .await
        {
            logger::error!(message="Failed to update analytics entry for Payouts {payouts:?}\n{updated_payout_attempt:?}", error_message=?err);
        };

        Ok(updated_payout_attempt)
    }

    async fn insert_payout_attempt(
        &self,
        payout_attempt: storage::PayoutAttemptNew,
        payouts: &storage::Payouts,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::PayoutAttempt, errors::StorageError> {
        let payout_attempt_new = self
            .diesel_store
            .insert_payout_attempt(payout_attempt, payouts, storage_scheme)
            .await?;
        if let Err(err) = self
            .kafka_producer
            .log_payout(
                &KafkaPayout::from_storage(payouts, &payout_attempt_new),
                None,
                self.tenant_id.clone(),
            )
            .await
        {
            logger::error!(message="Failed to add analytics entry for Payouts {payouts:?}\n{payout_attempt_new:?}", error_message=?err);
        };

        Ok(payout_attempt_new)
    }

    async fn get_filters_for_payouts(
        &self,
        payouts: &[hyperswitch_domain_models::payouts::payouts::Payouts],
        merchant_id: &id_type::MerchantId,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<
        hyperswitch_domain_models::payouts::payout_attempt::PayoutListFilters,
        errors::StorageError,
    > {
        self.diesel_store
            .get_filters_for_payouts(payouts, merchant_id, storage_scheme)
            .await
    }
}

#[cfg(not(feature = "payouts"))]
impl PayoutsInterface for KafkaStore {}

#[cfg(feature = "payouts")]
#[async_trait::async_trait]
impl PayoutsInterface for KafkaStore {
    type Error = errors::StorageError;
    async fn find_payout_by_merchant_id_payout_id(
        &self,
        merchant_id: &id_type::MerchantId,
        payout_id: &id_type::PayoutId,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::Payouts, errors::StorageError> {
        self.diesel_store
            .find_payout_by_merchant_id_payout_id(merchant_id, payout_id, storage_scheme)
            .await
    }

    async fn update_payout(
        &self,
        this: &storage::Payouts,
        payout_update: storage::PayoutsUpdate,
        payout_attempt: &storage::PayoutAttempt,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::Payouts, errors::StorageError> {
        let payout = self
            .diesel_store
            .update_payout(this, payout_update, payout_attempt, storage_scheme)
            .await?;
        if let Err(err) = self
            .kafka_producer
            .log_payout(
                &KafkaPayout::from_storage(&payout, payout_attempt),
                Some(KafkaPayout::from_storage(this, payout_attempt)),
                self.tenant_id.clone(),
            )
            .await
        {
            logger::error!(message="Failed to update analytics entry for Payouts {payout:?}\n{payout_attempt:?}", error_message=?err);
        };
        Ok(payout)
    }

    async fn insert_payout(
        &self,
        payout: storage::PayoutsNew,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::Payouts, errors::StorageError> {
        self.diesel_store
            .insert_payout(payout, storage_scheme)
            .await
    }

    async fn find_optional_payout_by_merchant_id_payout_id(
        &self,
        merchant_id: &id_type::MerchantId,
        payout_id: &id_type::PayoutId,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Option<storage::Payouts>, errors::StorageError> {
        self.diesel_store
            .find_optional_payout_by_merchant_id_payout_id(merchant_id, payout_id, storage_scheme)
            .await
    }

    #[cfg(feature = "olap")]
    async fn filter_payouts_by_constraints(
        &self,
        merchant_id: &id_type::MerchantId,
        filters: &hyperswitch_domain_models::payouts::PayoutFetchConstraints,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<storage::Payouts>, errors::StorageError> {
        self.diesel_store
            .filter_payouts_by_constraints(merchant_id, filters, storage_scheme)
            .await
    }

    #[cfg(feature = "olap")]
    async fn filter_payouts_and_attempts(
        &self,
        merchant_id: &id_type::MerchantId,
        filters: &hyperswitch_domain_models::payouts::PayoutFetchConstraints,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<
        Vec<(
            storage::Payouts,
            storage::PayoutAttempt,
            Option<diesel_models::Customer>,
            Option<diesel_models::Address>,
        )>,
        errors::StorageError,
    > {
        self.diesel_store
            .filter_payouts_and_attempts(merchant_id, filters, storage_scheme)
            .await
    }

    #[cfg(feature = "olap")]
    async fn filter_payouts_by_time_range_constraints(
        &self,
        merchant_id: &id_type::MerchantId,
        time_range: &common_utils::types::TimeRange,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<storage::Payouts>, errors::StorageError> {
        self.diesel_store
            .filter_payouts_by_time_range_constraints(merchant_id, time_range, storage_scheme)
            .await
    }

    #[cfg(feature = "olap")]
    async fn get_total_count_of_filtered_payouts(
        &self,
        merchant_id: &id_type::MerchantId,
        active_payout_ids: &[id_type::PayoutId],
        connector: Option<Vec<api_models::enums::PayoutConnectors>>,
        currency: Option<Vec<enums::Currency>>,
        status: Option<Vec<enums::PayoutStatus>>,
        payout_method: Option<Vec<enums::PayoutType>>,
    ) -> CustomResult<i64, errors::StorageError> {
        self.diesel_store
            .get_total_count_of_filtered_payouts(
                merchant_id,
                active_payout_ids,
                connector,
                currency,
                status,
                payout_method,
            )
            .await
    }

    #[cfg(feature = "olap")]
    async fn filter_active_payout_ids_by_constraints(
        &self,
        merchant_id: &id_type::MerchantId,
        constraints: &hyperswitch_domain_models::payouts::PayoutFetchConstraints,
    ) -> CustomResult<Vec<id_type::PayoutId>, errors::StorageError> {
        self.diesel_store
            .filter_active_payout_ids_by_constraints(merchant_id, constraints)
            .await
    }
}

#[async_trait::async_trait]
impl ProcessTrackerInterface for KafkaStore {
    async fn reinitialize_limbo_processes(
        &self,
        ids: Vec<String>,
        schedule_time: PrimitiveDateTime,
    ) -> CustomResult<usize, errors::StorageError> {
        self.diesel_store
            .reinitialize_limbo_processes(ids, schedule_time)
            .await
    }

    async fn find_process_by_id(
        &self,
        id: &str,
    ) -> CustomResult<Option<storage::ProcessTracker>, errors::StorageError> {
        self.diesel_store.find_process_by_id(id).await
    }

    async fn update_process(
        &self,
        this: storage::ProcessTracker,
        process: storage::ProcessTrackerUpdate,
    ) -> CustomResult<storage::ProcessTracker, errors::StorageError> {
        self.diesel_store.update_process(this, process).await
    }

    async fn process_tracker_update_process_status_by_ids(
        &self,
        task_ids: Vec<String>,
        task_update: storage::ProcessTrackerUpdate,
    ) -> CustomResult<usize, errors::StorageError> {
        self.diesel_store
            .process_tracker_update_process_status_by_ids(task_ids, task_update)
            .await
    }

    async fn insert_process(
        &self,
        new: storage::ProcessTrackerNew,
    ) -> CustomResult<storage::ProcessTracker, errors::StorageError> {
        self.diesel_store.insert_process(new).await
    }

    async fn reset_process(
        &self,
        this: storage::ProcessTracker,
        schedule_time: PrimitiveDateTime,
    ) -> CustomResult<(), errors::StorageError> {
        self.diesel_store.reset_process(this, schedule_time).await
    }

    async fn retry_process(
        &self,
        this: storage::ProcessTracker,
        schedule_time: PrimitiveDateTime,
    ) -> CustomResult<(), errors::StorageError> {
        self.diesel_store.retry_process(this, schedule_time).await
    }

    async fn finish_process_with_business_status(
        &self,
        this: storage::ProcessTracker,
        business_status: &'static str,
    ) -> CustomResult<(), errors::StorageError> {
        self.diesel_store
            .finish_process_with_business_status(this, business_status)
            .await
    }
    async fn find_processes_by_time_status(
        &self,
        time_lower_limit: PrimitiveDateTime,
        time_upper_limit: PrimitiveDateTime,
        status: ProcessTrackerStatus,
        limit: Option<i64>,
    ) -> CustomResult<Vec<storage::ProcessTracker>, errors::StorageError> {
        self.diesel_store
            .find_processes_by_time_status(time_lower_limit, time_upper_limit, status, limit)
            .await
    }
}

#[async_trait::async_trait]
impl CaptureInterface for KafkaStore {
    async fn insert_capture(
        &self,
        capture: storage::CaptureNew,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::Capture, errors::StorageError> {
        self.diesel_store
            .insert_capture(capture, storage_scheme)
            .await
    }

    async fn update_capture_with_capture_id(
        &self,
        this: storage::Capture,
        capture: storage::CaptureUpdate,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::Capture, errors::StorageError> {
        self.diesel_store
            .update_capture_with_capture_id(this, capture, storage_scheme)
            .await
    }

    async fn find_all_captures_by_merchant_id_payment_id_authorized_attempt_id(
        &self,
        merchant_id: &id_type::MerchantId,
        payment_id: &id_type::PaymentId,
        authorized_attempt_id: &str,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<storage::Capture>, errors::StorageError> {
        self.diesel_store
            .find_all_captures_by_merchant_id_payment_id_authorized_attempt_id(
                merchant_id,
                payment_id,
                authorized_attempt_id,
                storage_scheme,
            )
            .await
    }
}

#[async_trait::async_trait]
impl RefundInterface for KafkaStore {
    #[cfg(feature = "v1")]
    async fn find_refund_by_internal_reference_id_merchant_id(
        &self,
        internal_reference_id: &str,
        merchant_id: &id_type::MerchantId,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
        self.diesel_store
            .find_refund_by_internal_reference_id_merchant_id(
                internal_reference_id,
                merchant_id,
                storage_scheme,
            )
            .await
    }

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

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

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

    async fn update_refund(
        &self,
        this: diesel_refund::Refund,
        refund: diesel_refund::RefundUpdate,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
        let refund = self
            .diesel_store
            .update_refund(this.clone(), refund, storage_scheme)
            .await?;

        if let Err(er) = self
            .kafka_producer
            .log_refund(&refund, Some(this), self.tenant_id.clone())
            .await
        {
            logger::error!(message="Failed to insert analytics event for Refund Update {refund?}", error_message=?er);
        }
        Ok(refund)
    }

    async fn find_refund_by_merchant_id_connector_transaction_id(
        &self,
        merchant_id: &id_type::MerchantId,
        connector_transaction_id: &str,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<diesel_refund::Refund>, errors::StorageError> {
        self.diesel_store
            .find_refund_by_merchant_id_connector_transaction_id(
                merchant_id,
                connector_transaction_id,
                storage_scheme,
            )
            .await
    }

    #[cfg(feature = "v2")]
    async fn find_refund_by_id(
        &self,
        id: &id_type::GlobalRefundId,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
        self.diesel_store
            .find_refund_by_id(id, storage_scheme)
            .await
    }

    async fn insert_refund(
        &self,
        new: diesel_refund::RefundNew,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
        let refund = self.diesel_store.insert_refund(new, storage_scheme).await?;

        if let Err(er) = self
            .kafka_producer
            .log_refund(&refund, None, self.tenant_id.clone())
            .await
        {
            logger::error!(message="Failed to insert analytics event for Refund Create {refund?}", error_message=?er);
        }
        Ok(refund)
    }

    #[cfg(all(feature = "v1", feature = "olap"))]
    async fn filter_refund_by_constraints(
        &self,
        merchant_id: &id_type::MerchantId,
        refund_details: &refunds::RefundListConstraints,
        storage_scheme: MerchantStorageScheme,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<diesel_refund::Refund>, errors::StorageError> {
        self.diesel_store
            .filter_refund_by_constraints(
                merchant_id,
                refund_details,
                storage_scheme,
                limit,
                offset,
            )
            .await
    }

    #[cfg(feature = "v2")]
    async fn filter_refund_by_constraints(
        &self,
        merchant_id: &id_type::MerchantId,
        refund_details: refunds::RefundListConstraints,
        storage_scheme: MerchantStorageScheme,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<diesel_refund::Refund>, errors::StorageError> {
        self.diesel_store
            .filter_refund_by_constraints(
                merchant_id,
                refund_details,
                storage_scheme,
                limit,
                offset,
            )
            .await
    }

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

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

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

    #[cfg(feature = "v2")]
    async fn get_total_count_of_refunds(
        &self,
        merchant_id: &id_type::MerchantId,
        refund_details: refunds::RefundListConstraints,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<i64, errors::StorageError> {
        self.diesel_store
            .get_total_count_of_refunds(merchant_id, refund_details, storage_scheme)
            .await
    }
}

#[async_trait::async_trait]
impl MerchantKeyStoreInterface for KafkaStore {
    async fn insert_merchant_key_store(
        &self,
        state: &KeyManagerState,
        merchant_key_store: domain::MerchantKeyStore,
        key: &Secret<Vec<u8>>,
    ) -> CustomResult<domain::MerchantKeyStore, errors::StorageError> {
        self.diesel_store
            .insert_merchant_key_store(state, merchant_key_store, key)
            .await
    }

    async fn get_merchant_key_store_by_merchant_id(
        &self,
        state: &KeyManagerState,
        merchant_id: &id_type::MerchantId,
        key: &Secret<Vec<u8>>,
    ) -> CustomResult<domain::MerchantKeyStore, errors::StorageError> {
        self.diesel_store
            .get_merchant_key_store_by_merchant_id(state, merchant_id, key)
            .await
    }

    async fn delete_merchant_key_store_by_merchant_id(
        &self,
        merchant_id: &id_type::MerchantId,
    ) -> CustomResult<bool, errors::StorageError> {
        self.diesel_store
            .delete_merchant_key_store_by_merchant_id(merchant_id)
            .await
    }

    #[cfg(feature = "olap")]
    async fn list_multiple_key_stores(
        &self,
        state: &KeyManagerState,
        merchant_ids: Vec<id_type::MerchantId>,
        key: &Secret<Vec<u8>>,
    ) -> CustomResult<Vec<domain::MerchantKeyStore>, errors::StorageError> {
        self.diesel_store
            .list_multiple_key_stores(state, merchant_ids, key)
            .await
    }
    async fn get_all_key_stores(
        &self,
        state: &KeyManagerState,
        key: &Secret<Vec<u8>>,
        from: u32,
        to: u32,
    ) -> CustomResult<Vec<domain::MerchantKeyStore>, errors::StorageError> {
        self.diesel_store
            .get_all_key_stores(state, key, from, to)
            .await
    }
}

#[async_trait::async_trait]
impl ProfileInterface for KafkaStore {
    async fn insert_business_profile(
        &self,
        key_manager_state: &KeyManagerState,
        merchant_key_store: &domain::MerchantKeyStore,
        business_profile: domain::Profile,
    ) -> CustomResult<domain::Profile, errors::StorageError> {
        self.diesel_store
            .insert_business_profile(key_manager_state, merchant_key_store, business_profile)
            .await
    }

    async fn find_business_profile_by_profile_id(
        &self,
        key_manager_state: &KeyManagerState,
        merchant_key_store: &domain::MerchantKeyStore,
        profile_id: &id_type::ProfileId,
    ) -> CustomResult<domain::Profile, errors::StorageError> {
        self.diesel_store
            .find_business_profile_by_profile_id(key_manager_state, merchant_key_store, profile_id)
            .await
    }

    async fn find_business_profile_by_merchant_id_profile_id(
        &self,
        key_manager_state: &KeyManagerState,
        merchant_key_store: &domain::MerchantKeyStore,
        merchant_id: &id_type::MerchantId,
        profile_id: &id_type::ProfileId,
    ) -> CustomResult<domain::Profile, errors::StorageError> {
        self.diesel_store
            .find_business_profile_by_merchant_id_profile_id(
                key_manager_state,
                merchant_key_store,
                merchant_id,
                profile_id,
            )
            .await
    }

    async fn update_profile_by_profile_id(
        &self,
        key_manager_state: &KeyManagerState,
        merchant_key_store: &domain::MerchantKeyStore,
        current_state: domain::Profile,
        business_profile_update: domain::ProfileUpdate,
    ) -> CustomResult<domain::Profile, errors::StorageError> {
        self.diesel_store
            .update_profile_by_profile_id(
                key_manager_state,
                merchant_key_store,
                current_state,
                business_profile_update,
            )
            .await
    }

    async fn delete_profile_by_profile_id_merchant_id(
        &self,
        profile_id: &id_type::ProfileId,
        merchant_id: &id_type::MerchantId,
    ) -> CustomResult<bool, errors::StorageError> {
        self.diesel_store
            .delete_profile_by_profile_id_merchant_id(profile_id, merchant_id)
            .await
    }

    async fn list_profile_by_merchant_id(
        &self,
        key_manager_state: &KeyManagerState,
        merchant_key_store: &domain::MerchantKeyStore,
        merchant_id: &id_type::MerchantId,
    ) -> CustomResult<Vec<domain::Profile>, errors::StorageError> {
        self.diesel_store
            .list_profile_by_merchant_id(key_manager_state, merchant_key_store, merchant_id)
            .await
    }

    async fn find_business_profile_by_profile_name_merchant_id(
        &self,
        key_manager_state: &KeyManagerState,
        merchant_key_store: &domain::MerchantKeyStore,
        profile_name: &str,
        merchant_id: &id_type::MerchantId,
    ) -> CustomResult<domain::Profile, errors::StorageError> {
        self.diesel_store
            .find_business_profile_by_profile_name_merchant_id(
                key_manager_state,
                merchant_key_store,
                profile_name,
                merchant_id,
            )
            .await
    }
}

#[async_trait::async_trait]
impl ReverseLookupInterface for KafkaStore {
    async fn insert_reverse_lookup(
        &self,
        new: ReverseLookupNew,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<ReverseLookup, errors::StorageError> {
        self.diesel_store
            .insert_reverse_lookup(new, storage_scheme)
            .await
    }

    async fn get_lookup_by_lookup_id(
        &self,
        id: &str,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<ReverseLookup, errors::StorageError> {
        self.diesel_store
            .get_lookup_by_lookup_id(id, storage_scheme)
            .await
    }
}

#[async_trait::async_trait]
impl RoutingAlgorithmInterface for KafkaStore {
    async fn insert_routing_algorithm(
        &self,
        routing_algorithm: storage::RoutingAlgorithm,
    ) -> CustomResult<storage::RoutingAlgorithm, errors::StorageError> {
        self.diesel_store
            .insert_routing_algorithm(routing_algorithm)
            .await
    }

    async fn find_routing_algorithm_by_profile_id_algorithm_id(
        &self,
        profile_id: &id_type::ProfileId,
        algorithm_id: &id_type::RoutingId,
    ) -> CustomResult<storage::RoutingAlgorithm, errors::StorageError> {
        self.diesel_store
            .find_routing_algorithm_by_profile_id_algorithm_id(profile_id, algorithm_id)
            .await
    }

    async fn find_routing_algorithm_by_algorithm_id_merchant_id(
        &self,
        algorithm_id: &id_type::RoutingId,
        merchant_id: &id_type::MerchantId,
    ) -> CustomResult<storage::RoutingAlgorithm, errors::StorageError> {
        self.diesel_store
            .find_routing_algorithm_by_algorithm_id_merchant_id(algorithm_id, merchant_id)
            .await
    }

    async fn find_routing_algorithm_metadata_by_algorithm_id_profile_id(
        &self,
        algorithm_id: &id_type::RoutingId,
        profile_id: &id_type::ProfileId,
    ) -> CustomResult<storage::RoutingProfileMetadata, errors::StorageError> {
        self.diesel_store
            .find_routing_algorithm_metadata_by_algorithm_id_profile_id(algorithm_id, profile_id)
            .await
    }

    async fn list_routing_algorithm_metadata_by_profile_id(
        &self,
        profile_id: &id_type::ProfileId,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<storage::RoutingProfileMetadata>, errors::StorageError> {
        self.diesel_store
            .list_routing_algorithm_metadata_by_profile_id(profile_id, limit, offset)
            .await
    }

    async fn list_routing_algorithm_metadata_by_merchant_id(
        &self,
        merchant_id: &id_type::MerchantId,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<storage::RoutingProfileMetadata>, errors::StorageError> {
        self.diesel_store
            .list_routing_algorithm_metadata_by_merchant_id(merchant_id, limit, offset)
            .await
    }

    async fn list_routing_algorithm_metadata_by_merchant_id_transaction_type(
        &self,
        merchant_id: &id_type::MerchantId,
        transaction_type: &enums::TransactionType,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<storage::RoutingProfileMetadata>, errors::StorageError> {
        self.diesel_store
            .list_routing_algorithm_metadata_by_merchant_id_transaction_type(
                merchant_id,
                transaction_type,
                limit,
                offset,
            )
            .await
    }
}

#[async_trait::async_trait]
impl GsmInterface for KafkaStore {
    async fn add_gsm_rule(
        &self,
        rule: hyperswitch_domain_models::gsm::GatewayStatusMap,
    ) -> CustomResult<hyperswitch_domain_models::gsm::GatewayStatusMap, errors::StorageError> {
        self.diesel_store.add_gsm_rule(rule).await
    }

    async fn find_gsm_decision(
        &self,
        connector: String,
        flow: String,
        sub_flow: String,
        code: String,
        message: String,
    ) -> CustomResult<String, errors::StorageError> {
        self.diesel_store
            .find_gsm_decision(connector, flow, sub_flow, code, message)
            .await
    }

    async fn find_gsm_rule(
        &self,
        connector: String,
        flow: String,
        sub_flow: String,
        code: String,
        message: String,
    ) -> CustomResult<hyperswitch_domain_models::gsm::GatewayStatusMap, errors::StorageError> {
        self.diesel_store
            .find_gsm_rule(connector, flow, sub_flow, code, message)
            .await
    }

    async fn update_gsm_rule(
        &self,
        connector: String,
        flow: String,
        sub_flow: String,
        code: String,
        message: String,
        data: hyperswitch_domain_models::gsm::GatewayStatusMappingUpdate,
    ) -> CustomResult<hyperswitch_domain_models::gsm::GatewayStatusMap, errors::StorageError> {
        self.diesel_store
            .update_gsm_rule(connector, flow, sub_flow, code, message, data)
            .await
    }

    async fn delete_gsm_rule(
        &self,
        connector: String,
        flow: String,
        sub_flow: String,
        code: String,
        message: String,
    ) -> CustomResult<bool, errors::StorageError> {
        self.diesel_store
            .delete_gsm_rule(connector, flow, sub_flow, code, message)


// Struct: TransactionBankAccountInfo
// File: crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct TransactionBankAccountInfo


// Function: update_storage_scheme
// File: crates/diesel_models/src/mandate.rs
// Module: diesel_models

pub fn update_storage_scheme(&mut self, storage_scheme: MerchantStorageScheme)


// File: crates/router/src/core/payment_methods/surcharge_decision_configs.rs
// Module: router
// Public functions: 8
// Public structs: 1

use api_models::{
    payment_methods::SurchargeDetailsResponse,
    payments, routing,
    surcharge_decision_configs::{self, SurchargeDecisionConfigs, SurchargeDecisionManagerRecord},
};
#[cfg(feature = "v1")]
use common_utils::{ext_traits::StringExt, types as common_utils_types};
#[cfg(feature = "v2")]
use common_utils::{
    ext_traits::{OptionExt, StringExt},
    types as common_utils_types,
};
use error_stack::{self, ResultExt};
use euclid::{
    backend,
    backend::{inputs as dsl_inputs, EuclidBackend},
};
use router_env::{instrument, logger, tracing};
use serde::{Deserialize, Serialize};
use storage_impl::redis::cache::{self, SURCHARGE_CACHE};

use crate::{
    core::{
        errors::{self, ConditionalConfigError as ConfigError},
        payments::{
            conditional_configs::ConditionalConfigResult, routing::make_dsl_input_for_surcharge,
            types,
        },
    },
    db::StorageInterface,
    types::{
        storage::{self, payment_attempt::PaymentAttemptExt},
        transformers::ForeignTryFrom,
    },
    SessionState,
};

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct VirInterpreterBackendCacheWrapper {
    cached_algorithm: backend::VirInterpreterBackend<SurchargeDecisionConfigs>,
    merchant_surcharge_configs: surcharge_decision_configs::MerchantSurchargeConfigs,
}

impl TryFrom<SurchargeDecisionManagerRecord> for VirInterpreterBackendCacheWrapper {
    type Error = error_stack::Report<ConfigError>;

    fn try_from(value: SurchargeDecisionManagerRecord) -> Result<Self, Self::Error> {
        let cached_algorithm = backend::VirInterpreterBackend::with_program(value.algorithm)
            .change_context(ConfigError::DslBackendInitError)
            .attach_printable("Error initializing DSL interpreter backend")?;
        let merchant_surcharge_configs = value.merchant_surcharge_configs;
        Ok(Self {
            cached_algorithm,
            merchant_surcharge_configs,
        })
    }
}

enum SurchargeSource {
    /// Surcharge will be generated through the surcharge rules
    Generate(VirInterpreterBackendCacheWrapper),
    /// Surcharge is predefined by the merchant through payment create request
    Predetermined(payments::RequestSurchargeDetails),
}

impl SurchargeSource {
    pub fn generate_surcharge_details_and_populate_surcharge_metadata(
        &self,
        backend_input: &backend::BackendInput,
        payment_attempt: &storage::PaymentAttempt,
        surcharge_metadata_and_key: (&mut types::SurchargeMetadata, types::SurchargeKey),
    ) -> ConditionalConfigResult<Option<types::SurchargeDetails>> {
        match self {
            Self::Generate(interpreter) => {
                let surcharge_output = execute_dsl_and_get_conditional_config(
                    backend_input.clone(),
                    &interpreter.cached_algorithm,
                )?;
                Ok(surcharge_output
                    .surcharge_details
                    .map(|surcharge_details| {
                        get_surcharge_details_from_surcharge_output(
                            surcharge_details,
                            payment_attempt,
                        )
                    })
                    .transpose()?
                    .inspect(|surcharge_details| {
                        let (surcharge_metadata, surcharge_key) = surcharge_metadata_and_key;
                        surcharge_metadata
                            .insert_surcharge_details(surcharge_key, surcharge_details.clone());
                    }))
            }
            Self::Predetermined(request_surcharge_details) => Ok(Some(
                types::SurchargeDetails::from((request_surcharge_details, payment_attempt)),
            )),
        }
    }
}

#[cfg(feature = "v2")]
pub async fn perform_surcharge_decision_management_for_payment_method_list(
    _state: &SessionState,
    _algorithm_ref: routing::RoutingAlgorithmRef,
    _payment_attempt: &storage::PaymentAttempt,
    _payment_intent: &storage::PaymentIntent,
    _billing_address: Option<payments::Address>,
    _response_payment_method_types: &mut [api_models::payment_methods::ResponsePaymentMethodsEnabled],
) -> ConditionalConfigResult<(
    types::SurchargeMetadata,
    surcharge_decision_configs::MerchantSurchargeConfigs,
)> {
    todo!()
}

#[cfg(feature = "v1")]
pub async fn perform_surcharge_decision_management_for_payment_method_list(
    state: &SessionState,
    algorithm_ref: routing::RoutingAlgorithmRef,
    payment_attempt: &storage::PaymentAttempt,
    payment_intent: &storage::PaymentIntent,
    billing_address: Option<hyperswitch_domain_models::address::Address>,
    response_payment_method_types: &mut [api_models::payment_methods::ResponsePaymentMethodsEnabled],
) -> ConditionalConfigResult<(
    types::SurchargeMetadata,
    surcharge_decision_configs::MerchantSurchargeConfigs,
)> {
    let mut surcharge_metadata = types::SurchargeMetadata::new(payment_attempt.attempt_id.clone());

    let (surcharge_source, merchant_surcharge_configs) = match (
        payment_attempt.get_surcharge_details(),
        algorithm_ref.surcharge_config_algo_id,
    ) {
        (Some(request_surcharge_details), _) => (
            SurchargeSource::Predetermined(request_surcharge_details),
            surcharge_decision_configs::MerchantSurchargeConfigs::default(),
        ),
        (None, Some(algorithm_id)) => {
            let cached_algo = ensure_algorithm_cached(
                &*state.store,
                &payment_attempt.merchant_id,
                algorithm_id.as_str(),
            )
            .await?;

            let merchant_surcharge_config = cached_algo.merchant_surcharge_configs.clone();
            (
                SurchargeSource::Generate(cached_algo),
                merchant_surcharge_config,
            )
        }
        (None, None) => {
            return Ok((
                surcharge_metadata,
                surcharge_decision_configs::MerchantSurchargeConfigs::default(),
            ))
        }
    };
    let surcharge_source_log_message = match &surcharge_source {
        SurchargeSource::Generate(_) => "Surcharge was calculated through surcharge rules",
        SurchargeSource::Predetermined(_) => "Surcharge was sent in payment create request",
    };
    logger::debug!(payment_method_list_surcharge_source = surcharge_source_log_message);

    let mut backend_input =
        make_dsl_input_for_surcharge(payment_attempt, payment_intent, billing_address)
            .change_context(ConfigError::InputConstructionError)?;

    for payment_methods_enabled in response_payment_method_types.iter_mut() {
        for payment_method_type_response in
            &mut payment_methods_enabled.payment_method_types.iter_mut()
        {
            let payment_method_type = payment_method_type_response.payment_method_type;
            backend_input.payment_method.payment_method_type = Some(payment_method_type);
            backend_input.payment_method.payment_method =
                Some(payment_methods_enabled.payment_method);

            if let Some(card_network_list) = &mut payment_method_type_response.card_networks {
                for card_network_type in card_network_list.iter_mut() {
                    backend_input.payment_method.card_network =
                        Some(card_network_type.card_network.clone());
                    let surcharge_details = surcharge_source
                        .generate_surcharge_details_and_populate_surcharge_metadata(
                            &backend_input,
                            payment_attempt,
                            (
                                &mut surcharge_metadata,
                                types::SurchargeKey::PaymentMethodData(
                                    payment_methods_enabled.payment_method,
                                    payment_method_type_response.payment_method_type,
                                    Some(card_network_type.card_network.clone()),
                                ),
                            ),
                        )?;
                    card_network_type.surcharge_details = surcharge_details
                        .map(|surcharge_details| {
                            SurchargeDetailsResponse::foreign_try_from((
                                &surcharge_details,
                                payment_attempt,
                            ))
                            .change_context(ConfigError::DslExecutionError)
                            .attach_printable("Error while constructing Surcharge response type")
                        })
                        .transpose()?;
                }
            } else {
                let surcharge_details = surcharge_source
                    .generate_surcharge_details_and_populate_surcharge_metadata(
                        &backend_input,
                        payment_attempt,
                        (
                            &mut surcharge_metadata,
                            types::SurchargeKey::PaymentMethodData(
                                payment_methods_enabled.payment_method,
                                payment_method_type_response.payment_method_type,
                                None,
                            ),
                        ),
                    )?;
                payment_method_type_response.surcharge_details = surcharge_details
                    .map(|surcharge_details| {
                        SurchargeDetailsResponse::foreign_try_from((
                            &surcharge_details,
                            payment_attempt,
                        ))
                        .change_context(ConfigError::DslExecutionError)
                        .attach_printable("Error while constructing Surcharge response type")
                    })
                    .transpose()?;
            }
        }
    }
    Ok((surcharge_metadata, merchant_surcharge_configs))
}

#[cfg(feature = "v1")]
pub async fn perform_surcharge_decision_management_for_session_flow(
    state: &SessionState,
    algorithm_ref: routing::RoutingAlgorithmRef,
    payment_attempt: &storage::PaymentAttempt,
    payment_intent: &storage::PaymentIntent,
    billing_address: Option<hyperswitch_domain_models::address::Address>,
    payment_method_type_list: &Vec<common_enums::PaymentMethodType>,
) -> ConditionalConfigResult<types::SurchargeMetadata> {
    let mut surcharge_metadata = types::SurchargeMetadata::new(payment_attempt.attempt_id.clone());
    let surcharge_source = match (
        payment_attempt.get_surcharge_details(),
        algorithm_ref.surcharge_config_algo_id,
    ) {
        (Some(request_surcharge_details), _) => {
            SurchargeSource::Predetermined(request_surcharge_details)
        }
        (None, Some(algorithm_id)) => {
            let cached_algo = ensure_algorithm_cached(
                &*state.store,
                &payment_attempt.merchant_id,
                algorithm_id.as_str(),
            )
            .await?;

            SurchargeSource::Generate(cached_algo)
        }
        (None, None) => return Ok(surcharge_metadata),
    };
    let mut backend_input =
        make_dsl_input_for_surcharge(payment_attempt, payment_intent, billing_address)
            .change_context(ConfigError::InputConstructionError)?;
    for payment_method_type in payment_method_type_list {
        backend_input.payment_method.payment_method_type = Some(*payment_method_type);
        // in case of session flow, payment_method will always be wallet
        backend_input.payment_method.payment_method = Some(payment_method_type.to_owned().into());
        surcharge_source.generate_surcharge_details_and_populate_surcharge_metadata(
            &backend_input,
            payment_attempt,
            (
                &mut surcharge_metadata,
                types::SurchargeKey::PaymentMethodData(
                    payment_method_type.to_owned().into(),
                    *payment_method_type,
                    None,
                ),
            ),
        )?;
    }
    Ok(surcharge_metadata)
}

#[cfg(feature = "v1")]
pub async fn perform_surcharge_decision_management_for_saved_cards(
    state: &SessionState,
    algorithm_ref: routing::RoutingAlgorithmRef,
    payment_attempt: &storage::PaymentAttempt,
    payment_intent: &storage::PaymentIntent,
    customer_payment_method_list: &mut [api_models::payment_methods::CustomerPaymentMethod],
) -> ConditionalConfigResult<types::SurchargeMetadata> {
    let mut surcharge_metadata = types::SurchargeMetadata::new(payment_attempt.attempt_id.clone());
    let surcharge_source = match (
        payment_attempt.get_surcharge_details(),
        algorithm_ref.surcharge_config_algo_id,
    ) {
        (Some(request_surcharge_details), _) => {
            SurchargeSource::Predetermined(request_surcharge_details)
        }
        (None, Some(algorithm_id)) => {
            let cached_algo = ensure_algorithm_cached(
                &*state.store,
                &payment_attempt.merchant_id,
                algorithm_id.as_str(),
            )
            .await?;

            SurchargeSource::Generate(cached_algo)
        }
        (None, None) => return Ok(surcharge_metadata),
    };
    let surcharge_source_log_message = match &surcharge_source {
        SurchargeSource::Generate(_) => "Surcharge was calculated through surcharge rules",
        SurchargeSource::Predetermined(_) => "Surcharge was sent in payment create request",
    };
    logger::debug!(customer_saved_card_list_surcharge_source = surcharge_source_log_message);
    let mut backend_input = make_dsl_input_for_surcharge(payment_attempt, payment_intent, None)
        .change_context(ConfigError::InputConstructionError)?;

    for customer_payment_method in customer_payment_method_list.iter_mut() {
        let payment_token = customer_payment_method.payment_token.clone();

        backend_input.payment_method.payment_method = Some(customer_payment_method.payment_method);
        backend_input.payment_method.payment_method_type =
            customer_payment_method.payment_method_type;

        let card_network = customer_payment_method
            .card
            .as_ref()
            .and_then(|card| card.scheme.as_ref())
            .map(|scheme| {
                scheme
                    .clone()
                    .parse_enum("CardNetwork")
                    .change_context(ConfigError::DslExecutionError)
            })
            .transpose()?;

        backend_input.payment_method.card_network = card_network;

        let surcharge_details = surcharge_source
            .generate_surcharge_details_and_populate_surcharge_metadata(
                &backend_input,
                payment_attempt,
                (
                    &mut surcharge_metadata,
                    types::SurchargeKey::Token(payment_token),
                ),
            )?;
        customer_payment_method.surcharge_details = surcharge_details
            .map(|surcharge_details| {
                SurchargeDetailsResponse::foreign_try_from((&surcharge_details, payment_attempt))
                    .change_context(ConfigError::DslParsingError)
            })
            .transpose()?;
    }
    Ok(surcharge_metadata)
}

// TODO: uncomment and resolve compiler error when required
// #[cfg(feature = "v2")]
// pub async fn perform_surcharge_decision_management_for_saved_cards(
//     state: &SessionState,
//     algorithm_ref: routing::RoutingAlgorithmRef,
//     payment_attempt: &storage::PaymentAttempt,
//     payment_intent: &storage::PaymentIntent,
//     customer_payment_method_list: &mut [api_models::payment_methods::CustomerPaymentMethod],
// ) -> ConditionalConfigResult<types::SurchargeMetadata> {
//     // let mut surcharge_metadata = types::SurchargeMetadata::new(payment_attempt.id.clone());
//     let mut surcharge_metadata = todo!();

//     let surcharge_source = match (
//         payment_attempt.get_surcharge_details(),
//         algorithm_ref.surcharge_config_algo_id,
//     ) {
//         (Some(request_surcharge_details), _) => {
//             SurchargeSource::Predetermined(request_surcharge_details)
//         }
//         (None, Some(algorithm_id)) => {
//             let cached_algo = ensure_algorithm_cached(
//                 &*state.store,
//                 &payment_attempt.merchant_id,
//                 algorithm_id.as_str(),
//             )
//             .await?;

//             SurchargeSource::Generate(cached_algo)
//         }
//         (None, None) => return Ok(surcharge_metadata),
//     };
//     let surcharge_source_log_message = match &surcharge_source {
//         SurchargeSource::Generate(_) => "Surcharge was calculated through surcharge rules",
//         SurchargeSource::Predetermined(_) => "Surcharge was sent in payment create request",
//     };
//     logger::debug!(customer_saved_card_list_surcharge_source = surcharge_source_log_message);
//     let mut backend_input = make_dsl_input_for_surcharge(payment_attempt, payment_intent, None)
//         .change_context(ConfigError::InputConstructionError)?;

//     for customer_payment_method in customer_payment_method_list.iter_mut() {
//         let payment_token = customer_payment_method
//             .payment_token
//             .clone()
//             .get_required_value("payment_token")
//             .change_context(ConfigError::InputConstructionError)?;

//         backend_input.payment_method.payment_method =
//             Some(customer_payment_method.payment_method_type);
//         backend_input.payment_method.payment_method_type =
//             customer_payment_method.payment_method_subtype;

//         let card_network = match customer_payment_method.payment_method_data.as_ref() {
//             Some(api_models::payment_methods::PaymentMethodListData::Card(card)) => {
//                 card.card_network.clone()
//             }
//             _ => None,
//         };
//         backend_input.payment_method.card_network = card_network;

//         let surcharge_details = surcharge_source
//             .generate_surcharge_details_and_populate_surcharge_metadata(
//                 &backend_input,
//                 payment_attempt,
//                 (
//                     &mut surcharge_metadata,
//                     types::SurchargeKey::Token(payment_token),
//                 ),
//             )?;
//         customer_payment_method.surcharge_details = surcharge_details
//             .map(|surcharge_details| {
//                 SurchargeDetailsResponse::foreign_try_from((&surcharge_details, payment_attempt))
//                     .change_context(ConfigError::DslParsingError)
//             })
//             .transpose()?;
//     }
//     Ok(surcharge_metadata)
// }

#[cfg(feature = "v2")]
fn get_surcharge_details_from_surcharge_output(
    _surcharge_details: surcharge_decision_configs::SurchargeDetailsOutput,
    _payment_attempt: &storage::PaymentAttempt,
) -> ConditionalConfigResult<types::SurchargeDetails> {
    todo!()
}

#[cfg(feature = "v1")]
fn get_surcharge_details_from_surcharge_output(
    surcharge_details: surcharge_decision_configs::SurchargeDetailsOutput,
    payment_attempt: &storage::PaymentAttempt,
) -> ConditionalConfigResult<types::SurchargeDetails> {
    let surcharge_amount = match surcharge_details.surcharge.clone() {
        surcharge_decision_configs::SurchargeOutput::Fixed { amount } => amount,
        surcharge_decision_configs::SurchargeOutput::Rate(percentage) => percentage
            .apply_and_ceil_result(payment_attempt.net_amount.get_total_amount())
            .change_context(ConfigError::DslExecutionError)
            .attach_printable("Failed to Calculate surcharge amount by applying percentage")?,
    };
    let tax_on_surcharge_amount = surcharge_details
        .tax_on_surcharge
        .clone()
        .map(|tax_on_surcharge| {
            tax_on_surcharge
                .apply_and_ceil_result(surcharge_amount)
                .change_context(ConfigError::DslExecutionError)
                .attach_printable("Failed to Calculate tax amount")
        })
        .transpose()?
        .unwrap_or_default();
    Ok(types::SurchargeDetails {
        original_amount: payment_attempt.net_amount.get_order_amount(),
        surcharge: match surcharge_details.surcharge {
            surcharge_decision_configs::SurchargeOutput::Fixed { amount } => {
                common_utils_types::Surcharge::Fixed(amount)
            }
            surcharge_decision_configs::SurchargeOutput::Rate(percentage) => {
                common_utils_types::Surcharge::Rate(percentage)
            }
        },
        tax_on_surcharge: surcharge_details.tax_on_surcharge,
        surcharge_amount,
        tax_on_surcharge_amount,
    })
}

#[instrument(skip_all)]
pub async fn ensure_algorithm_cached(
    store: &dyn StorageInterface,
    merchant_id: &common_utils::id_type::MerchantId,
    algorithm_id: &str,
) -> ConditionalConfigResult<VirInterpreterBackendCacheWrapper> {
    let key = merchant_id.get_surcharge_dsk_key();

    let value_to_cache = || async {
        let config: diesel_models::Config = store.find_config_by_key(algorithm_id).await?;
        let record: SurchargeDecisionManagerRecord = config
            .config
            .parse_struct("Program")
            .change_context(errors::StorageError::DeserializationFailed)
            .attach_printable("Error parsing routing algorithm from configs")?;
        VirInterpreterBackendCacheWrapper::try_from(record)
            .change_context(errors::StorageError::ValueNotFound("Program".to_string()))
            .attach_printable("Error initializing DSL interpreter backend")
    };
    let interpreter = cache::get_or_populate_in_memory(
        store.get_cache_store().as_ref(),
        &key,
        value_to_cache,
        &SURCHARGE_CACHE,
    )
    .await
    .change_context(ConfigError::CacheMiss)
    .attach_printable("Unable to retrieve cached routing algorithm even after refresh")?;
    Ok(interpreter)
}

pub fn execute_dsl_and_get_conditional_config(
    backend_input: dsl_inputs::BackendInput,
    interpreter: &backend::VirInterpreterBackend<SurchargeDecisionConfigs>,
) -> ConditionalConfigResult<SurchargeDecisionConfigs> {
    let routing_output = interpreter
        .execute(backend_input)
        .map(|out| out.connector_selection)
        .change_context(ConfigError::DslExecutionError)?;
    Ok(routing_output)
}


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

impl ConnectorCommon for for Billwerk


// Function: profiles_list
// File: crates/router/src/routes/profiles.rs
// Module: router

pub fn profiles_list(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<common_utils::id_type::MerchantId>,
) -> HttpResponse


// File: crates/router/src/services/kafka/fraud_check_event.rs
// Module: router
// Public functions: 1
// Public structs: 1

use diesel_models::{
    enums as storage_enums,
    enums::{FraudCheckLastStep, FraudCheckStatus, FraudCheckType},
    fraud_check::FraudCheck,
};
use time::OffsetDateTime;

#[derive(serde::Serialize, Debug)]
pub struct KafkaFraudCheckEvent<'a> {
    pub frm_id: &'a String,
    pub payment_id: &'a common_utils::id_type::PaymentId,
    pub merchant_id: &'a common_utils::id_type::MerchantId,
    pub attempt_id: &'a String,
    #[serde(with = "time::serde::timestamp::nanoseconds")]
    pub created_at: OffsetDateTime,
    pub frm_name: &'a String,
    pub frm_transaction_id: Option<&'a String>,
    pub frm_transaction_type: FraudCheckType,
    pub frm_status: FraudCheckStatus,
    pub frm_score: Option<i32>,
    pub frm_reason: Option<serde_json::Value>,
    pub frm_error: Option<&'a String>,
    pub payment_details: Option<serde_json::Value>,
    pub metadata: Option<serde_json::Value>,
    #[serde(with = "time::serde::timestamp::nanoseconds")]
    pub modified_at: OffsetDateTime,
    pub last_step: FraudCheckLastStep,
    pub payment_capture_method: Option<storage_enums::CaptureMethod>, // In postFrm, we are updating capture method from automatic to manual. To store the merchant actual capture method, we are storing the actual capture method in payment_capture_method. It will be useful while approving the FRM decision.
}

impl<'a> KafkaFraudCheckEvent<'a> {
    pub fn from_storage(check: &'a FraudCheck) -> Self {
        Self {
            frm_id: &check.frm_id,
            payment_id: &check.payment_id,
            merchant_id: &check.merchant_id,
            attempt_id: &check.attempt_id,
            created_at: check.created_at.assume_utc(),
            frm_name: &check.frm_name,
            frm_transaction_id: check.frm_transaction_id.as_ref(),
            frm_transaction_type: check.frm_transaction_type,
            frm_status: check.frm_status,
            frm_score: check.frm_score,
            frm_reason: check.frm_reason.clone(),
            frm_error: check.frm_error.as_ref(),
            payment_details: check.payment_details.clone(),
            metadata: check.metadata.clone(),
            modified_at: check.modified_at.assume_utc(),
            last_step: check.last_step,
            payment_capture_method: check.payment_capture_method,
        }
    }
}

impl super::KafkaMessage for KafkaFraudCheckEvent<'_> {
    fn key(&self) -> String {
        format!(
            "{}_{}_{}_{}",
            self.merchant_id.get_string_repr(),
            self.payment_id.get_string_repr(),
            self.attempt_id,
            self.frm_id
        )
    }

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


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

use api_models::{enums::FrmSuggestion, payments::PaymentsRetrieveRequest};
use async_trait::async_trait;
use common_utils::ext_traits::AsyncExt;
use error_stack::ResultExt;
use hyperswitch_domain_models::payments::PaymentStatusData;
use router_env::{instrument, tracing};

use super::{Domain, GetTracker, Operation, UpdateTracker, ValidateRequest};
use crate::{
    core::{
        errors::{self, CustomResult, RouterResult, StorageErrorExt},
        payments::{
            helpers,
            operations::{self, ValidateStatusForOperation},
        },
    },
    routes::{app::ReqState, SessionState},
    types::{
        api::{self, ConnectorCallType},
        domain::{self},
        storage::{self, enums as storage_enums},
    },
    utils::OptionExt,
};

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

impl ValidateStatusForOperation for PaymentGet {
    /// Validate if the current operation can be performed on the current status of the payment intent
    fn validate_status_for_operation(
        &self,
        intent_status: common_enums::IntentStatus,
    ) -> Result<(), errors::ApiErrorResponse> {
        match intent_status {
            common_enums::IntentStatus::RequiresCapture
            | common_enums::IntentStatus::PartiallyAuthorizedAndRequiresCapture
            | common_enums::IntentStatus::RequiresCustomerAction
            | common_enums::IntentStatus::RequiresMerchantAction
            | common_enums::IntentStatus::Processing
            | common_enums::IntentStatus::Succeeded
            | common_enums::IntentStatus::Failed
            | common_enums::IntentStatus::PartiallyCapturedAndCapturable
            | common_enums::IntentStatus::PartiallyCaptured
            | common_enums::IntentStatus::Cancelled
            | common_enums::IntentStatus::CancelledPostCapture
            | common_enums::IntentStatus::Conflicted
            | common_enums::IntentStatus::Expired => Ok(()),
            // These statuses are not valid for this operation
            common_enums::IntentStatus::RequiresConfirmation
            | common_enums::IntentStatus::RequiresPaymentMethod => {
                Err(errors::ApiErrorResponse::PaymentUnexpectedState {
                    current_flow: format!("{self:?}"),
                    field_name: "status".to_string(),
                    current_value: intent_status.to_string(),
                    states: [
                        common_enums::IntentStatus::RequiresCapture,
                        common_enums::IntentStatus::PartiallyAuthorizedAndRequiresCapture,
                        common_enums::IntentStatus::RequiresCustomerAction,
                        common_enums::IntentStatus::RequiresMerchantAction,
                        common_enums::IntentStatus::Processing,
                        common_enums::IntentStatus::Succeeded,
                        common_enums::IntentStatus::Failed,
                        common_enums::IntentStatus::PartiallyCapturedAndCapturable,
                        common_enums::IntentStatus::PartiallyCaptured,
                        common_enums::IntentStatus::Cancelled,
                    ]
                    .map(|enum_value| enum_value.to_string())
                    .join(", "),
                })
            }
        }
    }
}

type BoxedConfirmOperation<'b, F> =
    super::BoxedOperation<'b, F, PaymentsRetrieveRequest, PaymentStatusData<F>>;

// TODO: change the macro to include changes for v2
// TODO: PaymentData in the macro should be an input
impl<F: Send + Clone + Sync> Operation<F, PaymentsRetrieveRequest> for &PaymentGet {
    type Data = PaymentStatusData<F>;
    fn to_validate_request(
        &self,
    ) -> RouterResult<&(dyn ValidateRequest<F, PaymentsRetrieveRequest, Self::Data> + Send + Sync)>
    {
        Ok(*self)
    }
    fn to_get_tracker(
        &self,
    ) -> RouterResult<&(dyn GetTracker<F, Self::Data, PaymentsRetrieveRequest> + Send + Sync)> {
        Ok(*self)
    }
    fn to_domain(&self) -> RouterResult<&(dyn Domain<F, PaymentsRetrieveRequest, Self::Data>)> {
        Ok(*self)
    }
    fn to_update_tracker(
        &self,
    ) -> RouterResult<&(dyn UpdateTracker<F, Self::Data, PaymentsRetrieveRequest> + Send + Sync)>
    {
        Ok(*self)
    }
}
#[automatically_derived]
impl<F: Send + Clone + Sync> Operation<F, PaymentsRetrieveRequest> for PaymentGet {
    type Data = PaymentStatusData<F>;
    fn to_validate_request(
        &self,
    ) -> RouterResult<&(dyn ValidateRequest<F, PaymentsRetrieveRequest, Self::Data> + Send + Sync)>
    {
        Ok(self)
    }
    fn to_get_tracker(
        &self,
    ) -> RouterResult<&(dyn GetTracker<F, Self::Data, PaymentsRetrieveRequest> + Send + Sync)> {
        Ok(self)
    }
    fn to_domain(&self) -> RouterResult<&dyn Domain<F, PaymentsRetrieveRequest, Self::Data>> {
        Ok(self)
    }
    fn to_update_tracker(
        &self,
    ) -> RouterResult<&(dyn UpdateTracker<F, Self::Data, PaymentsRetrieveRequest> + Send + Sync)>
    {
        Ok(self)
    }
}

impl<F: Send + Clone + Sync> ValidateRequest<F, PaymentsRetrieveRequest, PaymentStatusData<F>>
    for PaymentGet
{
    #[instrument(skip_all)]
    fn validate_request<'a, 'b>(
        &'b self,
        _request: &PaymentsRetrieveRequest,
        merchant_context: &'a domain::MerchantContext,
    ) -> RouterResult<operations::ValidateResult> {
        let validate_result = operations::ValidateResult {
            merchant_id: merchant_context.get_merchant_account().get_id().to_owned(),
            storage_scheme: merchant_context.get_merchant_account().storage_scheme,
            requeue: false,
        };

        Ok(validate_result)
    }
}

#[async_trait]
impl<F: Send + Clone + Sync> GetTracker<F, PaymentStatusData<F>, PaymentsRetrieveRequest>
    for PaymentGet
{
    #[instrument(skip_all)]
    async fn get_trackers<'a>(
        &'a self,
        state: &'a SessionState,
        payment_id: &common_utils::id_type::GlobalPaymentId,
        request: &PaymentsRetrieveRequest,
        merchant_context: &domain::MerchantContext,
        _profile: &domain::Profile,
        _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
    ) -> RouterResult<operations::GetTrackerResponse<PaymentStatusData<F>>> {
        let db = &*state.store;
        let key_manager_state = &state.into();

        let storage_scheme = merchant_context.get_merchant_account().storage_scheme;

        let payment_intent = db
            .find_payment_intent_by_id(
                key_manager_state,
                payment_id,
                merchant_context.get_merchant_key_store(),
                storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

        self.validate_status_for_operation(payment_intent.status)?;

        let active_attempt_id = payment_intent.active_attempt_id.as_ref().ok_or_else(|| {
            errors::ApiErrorResponse::MissingRequiredField {
                field_name: ("active_attempt_id"),
            }
        })?;

        let mut payment_attempt = db
            .find_payment_attempt_by_id(
                key_manager_state,
                merchant_context.get_merchant_key_store(),
                active_attempt_id,
                storage_scheme,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Could not find payment attempt given the attempt id")?;

        payment_attempt.encoded_data = request
            .param
            .as_ref()
            .map(|val| masking::Secret::new(val.clone()));

        let should_sync_with_connector =
            request.force_sync && payment_intent.status.should_force_sync_with_connector();

        // We need the address here to send it in the response
        let payment_address = hyperswitch_domain_models::payment_address::PaymentAddress::new(
            payment_intent
                .shipping_address
                .clone()
                .map(|address| address.into_inner()),
            payment_intent
                .billing_address
                .clone()
                .map(|address| address.into_inner()),
            payment_attempt
                .payment_method_billing_address
                .clone()
                .map(|address| address.into_inner()),
            Some(true),
        );

        let attempts = match request.expand_attempts {
            true => payment_intent
                .active_attempt_id
                .as_ref()
                .async_map(|active_attempt| async {
                    db.find_payment_attempts_by_payment_intent_id(
                        key_manager_state,
                        payment_id,
                        merchant_context.get_merchant_key_store(),
                        storage_scheme,
                    )
                    .await
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Could not find payment attempts for the given the intent id")
                })
                .await
                .transpose()?,
            false => None,
        };

        let merchant_connector_details = request.merchant_connector_details.clone();

        let payment_data = PaymentStatusData {
            flow: std::marker::PhantomData,
            payment_intent,
            payment_attempt,
            payment_address,
            attempts,
            should_sync_with_connector,
            merchant_connector_details,
        };

        let get_trackers_response = operations::GetTrackerResponse { payment_data };

        Ok(get_trackers_response)
    }
}

#[async_trait]
impl<F: Clone + Send + Sync> Domain<F, PaymentsRetrieveRequest, PaymentStatusData<F>>
    for PaymentGet
{
    async fn get_customer_details<'a>(
        &'a self,
        state: &SessionState,
        payment_data: &mut PaymentStatusData<F>,
        merchant_key_store: &domain::MerchantKeyStore,
        storage_scheme: storage_enums::MerchantStorageScheme,
    ) -> CustomResult<(BoxedConfirmOperation<'a, F>, Option<domain::Customer>), errors::StorageError>
    {
        match payment_data.payment_intent.customer_id.clone() {
            Some(id) => {
                let customer = state
                    .store
                    .find_customer_by_global_id(
                        &state.into(),
                        &id,
                        merchant_key_store,
                        storage_scheme,
                    )
                    .await?;

                Ok((Box::new(self), Some(customer)))
            }
            None => Ok((Box::new(self), None)),
        }
    }

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

    #[instrument(skip_all)]
    async fn perform_routing<'a>(
        &'a self,
        _merchant_context: &domain::MerchantContext,
        _business_profile: &domain::Profile,
        state: &SessionState,
        // TODO: do not take the whole payment data here
        payment_data: &mut PaymentStatusData<F>,
    ) -> CustomResult<ConnectorCallType, errors::ApiErrorResponse> {
        let payment_attempt = &payment_data.payment_attempt;

        if payment_data.should_sync_with_connector {
            let connector = payment_attempt
                .connector
                .as_ref()
                .get_required_value("connector")
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Connector is none when constructing response")?;

            let merchant_connector_id = payment_attempt
                .merchant_connector_id
                .as_ref()
                .get_required_value("merchant_connector_id")
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Merchant connector id is none when constructing response")?;

            let connector_data = api::ConnectorData::get_connector_by_name(
                &state.conf.connectors,
                connector,
                api::GetToken::Connector,
                Some(merchant_connector_id.to_owned()),
            )
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Invalid connector name received")?;

            Ok(ConnectorCallType::PreDetermined(
                api::ConnectorRoutingData::from(connector_data),
            ))
        } else {
            Ok(ConnectorCallType::Skip)
        }
    }

    #[cfg(feature = "v2")]
    async fn get_connector_from_request<'a>(
        &'a self,
        state: &SessionState,
        request: &PaymentsRetrieveRequest,
        payment_data: &mut PaymentStatusData<F>,
    ) -> CustomResult<api::ConnectorData, errors::ApiErrorResponse> {
        use crate::core::payments::OperationSessionSetters;

        let connector_data = helpers::get_connector_data_from_request(
            state,
            request.merchant_connector_details.clone(),
        )
        .await?;

        payment_data
            .set_connector_in_payment_attempt(Some(connector_data.connector_name.to_string()));
        Ok(connector_data)
    }
}

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


// Implementation: impl CustomerAcceptance
// File: crates/common_types/src/payments.rs
// Module: common_types
// Methods: 3 total (3 public)

impl CustomerAcceptance


// Function: get_default_customer_shipping_address
// File: crates/api_models/src/customers.rs
// Module: api_models

pub fn get_default_customer_shipping_address(&self) -> Option<payments::AddressDetails>


// Struct: NoAuth
// File: crates/router/src/services/authentication.rs
// Module: router
// Implementations: 0

pub struct NoAuth


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

use masking::Secret;
use router::types::{self, api, domain, storage::enums};
use test_utils::connector_auth;

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

#[derive(Clone, Copy)]
struct BarclaycardTest;
impl ConnectorActions for BarclaycardTest {}
impl utils::Connector for BarclaycardTest {
    fn get_data(&self) -> api::ConnectorData {
        use router::connector::Barclaycard;
        utils::construct_connector_data_old(
            Box::new(Barclaycard::new()),
            types::Connector::DummyConnector1,
            api::GetToken::Connector,
            None,
        )
    }

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

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

static CONNECTOR: BarclaycardTest = BarclaycardTest {};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// Cards Negative scenarios
// Creates a payment with incorrect CVC.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_cvc() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_cvc: Secret::new("12345".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's security code is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry month.
#[actix_web::test]
async fn should_fail_payment_for_invalid_exp_month() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_exp_month: Secret::new("20".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration month is invalid.".to_string(),
    );
}

// Creates a payment with incorrect expiry year.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_expiry_year() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_exp_year: Secret::new("2000".to_string()),
                    ..utils::CCardType::default().0
                }),
                ..utils::PaymentAuthorizeType::default().0
            }),
            get_default_payment_info(),
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Your card's expiration year is invalid.".to_string(),
    );
}

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

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

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

// Connector dependent test cases goes here

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


// File: crates/router/src/types/storage/generic_link.rs
// Module: router

pub use diesel_models::generic_link::{
    GenericLink, GenericLinkData, GenericLinkNew, GenericLinkState, GenericLinkUpdateInternal,
    PaymentMethodCollectLink, PayoutLink, PayoutLinkUpdate,
};


// File: crates/diesel_models/src/query/payment_link.rs
// Module: diesel_models
// Public functions: 2

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

use super::generics;
use crate::{
    payment_link::{PaymentLink, PaymentLinkNew},
    schema::payment_link::dsl,
    PgPooledConn, StorageResult,
};

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

impl PaymentLink {
    pub async fn find_link_by_payment_link_id(
        conn: &PgPooledConn,
        payment_link_id: &str,
    ) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::payment_link_id.eq(payment_link_id.to_owned()),
        )
        .await
    }
}


// File: crates/diesel_models/src/query/unified_translations.rs
// Module: diesel_models
// Public functions: 4

use diesel::{associations::HasTable, BoolExpressionMethods, ExpressionMethods};
use error_stack::report;

use crate::{
    errors,
    query::generics,
    schema::unified_translations::dsl,
    unified_translations::{UnifiedTranslationsUpdateInternal, *},
    PgPooledConn, StorageResult,
};

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

impl UnifiedTranslations {
    pub async fn find_by_unified_code_unified_message_locale(
        conn: &PgPooledConn,
        unified_code: String,
        unified_message: String,
        locale: String,
    ) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::unified_code
                .eq(unified_code)
                .and(dsl::unified_message.eq(unified_message))
                .and(dsl::locale.eq(locale)),
        )
        .await
    }

    pub async fn update_by_unified_code_unified_message_locale(
        conn: &PgPooledConn,
        unified_code: String,
        unified_message: String,
        locale: String,
        data: UnifiedTranslationsUpdate,
    ) -> StorageResult<Self> {
        generics::generic_update_with_results::<
            <Self as HasTable>::Table,
            UnifiedTranslationsUpdateInternal,
            _,
            _,
        >(
            conn,
            dsl::unified_code
                .eq(unified_code)
                .and(dsl::unified_message.eq(unified_message))
                .and(dsl::locale.eq(locale)),
            data.into(),
        )
        .await?
        .first()
        .cloned()
        .ok_or_else(|| {
            report!(errors::DatabaseError::NotFound)
                .attach_printable("Error while updating unified_translations entry")
        })
    }

    pub async fn delete_by_unified_code_unified_message_locale(
        conn: &PgPooledConn,
        unified_code: String,
        unified_message: String,
        locale: String,
    ) -> StorageResult<bool> {
        generics::generic_delete::<<Self as HasTable>::Table, _>(
            conn,
            dsl::unified_code
                .eq(unified_code)
                .and(dsl::unified_message.eq(unified_message))
                .and(dsl::locale.eq(locale)),
        )
        .await
    }
}


// Struct: Dlocal
// File: crates/hyperswitch_connectors/src/connectors/dlocal.rs
// Module: hyperswitch_connectors
// Implementations: 17
// Traits: api::Payment, api::PaymentToken, api::PaymentSession, api::ConnectorAccessToken, api::MandateSetup, api::PaymentAuthorize, api::PaymentSync, api::PaymentCapture, api::PaymentVoid, api::Refund, api::RefundExecute, api::RefundSync, ConnectorCommon, ConnectorValidation, webhooks::IncomingWebhook, ConnectorSpecifications

pub struct Dlocal

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


// Implementation: impl AwsSes
// File: crates/external_services/src/email/ses.rs
// Module: external_services
// Methods: 4 total (0 public)

impl AwsSes


// Implementation: impl ApiEventMetric for for ConfirmSubscriptionRequest
// File: crates/api_models/src/subscription.rs
// Module: api_models
// Methods: 0 total (0 public)

impl ApiEventMetric for for ConfirmSubscriptionRequest


// Function: is_for_internal_use_only
// File: crates/common_enums/src/enums.rs
// Module: common_enums

pub fn is_for_internal_use_only(self) -> bool


// Function: get_refunds_filters
// File: crates/router/src/routes/refunds.rs
// Module: router

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


// Struct: Address
// File: crates/router_derive/src/lib.rs
// Module: router_derive
// Implementations: 0

pub struct Address


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

pub struct RequiredFields


// Struct: CheckoutShippingAddress
// File: crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs
// Module: hyperswitch_connectors
// Implementations: 0

pub struct CheckoutShippingAddress


// Function: separate_metadata_type_based_on_scope
// File: crates/router/src/utils/user/dashboard_metadata.rs
// Module: router

pub fn separate_metadata_type_based_on_scope(
    metadata_keys: Vec<DBEnum>,
) -> (Vec<DBEnum>, Vec<DBEnum>)


// Function: call_decide_gateway_open_router
// File: crates/openapi/src/routes/routing.rs
// Module: openapi

pub fn call_decide_gateway_open_router()