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

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

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

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

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

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

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

#[async_trait::async_trait]
impl RefundInterface for MockDb {
    #[cfg(feature = "v1")]
    async fn find_refund_by_internal_reference_id_merchant_id(
        &self,
        internal_reference_id: &str,
        merchant_id: &common_utils::id_type::MerchantId,
        _storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
        let refunds = self.refunds.lock().await;
        refunds
            .iter()
            .find(|refund| {
                refund.merchant_id == *merchant_id
                    && refund.internal_reference_id == internal_reference_id
            })
            .cloned()
            .ok_or_else(|| {
                errors::StorageError::DatabaseError(DatabaseError::NotFound.into()).into()
            })
    }

    #[cfg(feature = "v1")]
    async fn insert_refund(
        &self,
        new: diesel_refund::RefundNew,
        _storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
        let mut refunds = self.refunds.lock().await;
        let current_time = common_utils::date_time::now();

        let refund = diesel_refund::Refund {
            internal_reference_id: new.internal_reference_id,
            refund_id: new.refund_id,
            payment_id: new.payment_id,
            merchant_id: new.merchant_id,
            attempt_id: new.attempt_id,
            connector_transaction_id: new.connector_transaction_id,
            connector: new.connector,
            connector_refund_id: new.connector_refund_id,
            external_reference_id: new.external_reference_id,
            refund_type: new.refund_type,
            total_amount: new.total_amount,
            currency: new.currency,
            refund_amount: new.refund_amount,
            refund_status: new.refund_status,
            sent_to_gateway: new.sent_to_gateway,
            refund_error_message: None,
            refund_error_code: None,
            metadata: new.metadata,
            refund_arn: new.refund_arn.clone(),
            created_at: new.created_at,
            modified_at: current_time,
            description: new.description,
            refund_reason: new.refund_reason.clone(),
            profile_id: new.profile_id,
            updated_by: new.updated_by,
            merchant_connector_id: new.merchant_connector_id,
            charges: new.charges,
            split_refunds: new.split_refunds,
            organization_id: new.organization_id,
            unified_code: None,
            unified_message: None,
            processor_refund_data: new.processor_refund_data.clone(),
            processor_transaction_data: new.processor_transaction_data.clone(),
            issuer_error_code: None,
            issuer_error_message: None,
            // Below fields are deprecated. Please add any new fields above this line.
            connector_refund_data: None,
            connector_transaction_data: None,
        };
        refunds.push(refund.clone());
        Ok(refund)
    }

    #[cfg(feature = "v2")]
    async fn insert_refund(
        &self,
        new: diesel_refund::RefundNew,
        _storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
        let mut refunds = self.refunds.lock().await;
        let current_time = common_utils::date_time::now();

        let refund = diesel_refund::Refund {
            id: new.id,
            merchant_reference_id: new.merchant_reference_id,
            payment_id: new.payment_id,
            merchant_id: new.merchant_id,
            attempt_id: new.attempt_id,
            connector_transaction_id: new.connector_transaction_id,
            connector: new.connector,
            connector_refund_id: new.connector_refund_id,
            external_reference_id: new.external_reference_id,
            refund_type: new.refund_type,
            total_amount: new.total_amount,
            currency: new.currency,
            refund_amount: new.refund_amount,
            refund_status: new.refund_status,
            sent_to_gateway: new.sent_to_gateway,
            refund_error_message: None,
            refund_error_code: None,
            metadata: new.metadata,
            refund_arn: new.refund_arn.clone(),
            created_at: new.created_at,
            modified_at: current_time,
            description: new.description,
            refund_reason: new.refund_reason.clone(),
            profile_id: new.profile_id,
            updated_by: new.updated_by,
            connector_id: new.connector_id,
            charges: new.charges,
            split_refunds: new.split_refunds,
            organization_id: new.organization_id,
            unified_code: None,
            unified_message: None,
            processor_refund_data: new.processor_refund_data.clone(),
            processor_transaction_data: new.processor_transaction_data.clone(),
        };
        refunds.push(refund.clone());
        Ok(refund)
    }

    async fn find_refund_by_merchant_id_connector_transaction_id(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_transaction_id: &str,
        _storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<Vec<diesel_refund::Refund>, errors::StorageError> {
        let refunds = self.refunds.lock().await;

        Ok(refunds
            .iter()
            .take_while(|refund| {
                refund.merchant_id == *merchant_id
                    && refund.get_connector_transaction_id() == connector_transaction_id
            })
            .cloned()
            .collect::<Vec<_>>())
    }

    #[cfg(feature = "v1")]
    async fn update_refund(
        &self,
        this: diesel_refund::Refund,
        refund: diesel_refund::RefundUpdate,
        _storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
        self.refunds
            .lock()
            .await
            .iter_mut()
            .find(|refund| this.refund_id == refund.refund_id)
            .map(|r| {
                let refund_updated =
                    diesel_refund::RefundUpdateInternal::from(refund).create_refund(r.clone());
                *r = refund_updated.clone();
                refund_updated
            })
            .ok_or_else(|| {
                errors::StorageError::ValueNotFound("cannot find refund to update".to_string())
                    .into()
            })
    }

    #[cfg(feature = "v2")]
    async fn update_refund(
        &self,
        this: diesel_refund::Refund,
        refund: diesel_refund::RefundUpdate,
        _storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<diesel_refund::Refund, errors::StorageError> {
        self.refunds
            .lock()
            .await
            .iter_mut()
            .find(|refund| this.merchant_reference_id == refund.merchant_reference_id)
            .map(|r| {
                let refund_updated =
                    diesel_refund::RefundUpdateInternal::from(refund).create_refund(r.clone());
                *r = refund_updated.clone();
                refund_updated
            })
            .ok_or_else(|| {
                errors::StorageError::ValueNotFound("cannot find refund to update".to_string())
                    .into()
            })
    }

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

        refunds
            .iter()
            .find(|refund| refund.merchant_id == *merchant_id && refund.refund_id == refund_id)
            .cloned()
            .ok_or_else(|| {
                errors::StorageError::DatabaseError(DatabaseError::NotFound.into()).into()
            })
    }

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

        refunds
            .iter()
            .find(|refund| {
                refund.merchant_id == *merchant_id
                    && refund
                        .get_optional_connector_refund_id()
                        .map(|refund_id| refund_id.as_str())
                        == Some(connector_refund_id)
                    && refund.connector == connector
            })
            .cloned()
            .ok_or_else(|| {
                errors::StorageError::DatabaseError(DatabaseError::NotFound.into()).into()
            })
    }

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

        Ok(refunds
            .iter()
            .filter(|refund| refund.merchant_id == *merchant_id && refund.payment_id == *payment_id)
            .cloned()
            .collect::<Vec<_>>())
    }

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

        refunds
            .iter()
            .find(|refund| refund.id == *id)
            .cloned()
            .ok_or_else(|| {
                errors::StorageError::DatabaseError(DatabaseError::NotFound.into()).into()
            })
    }

    #[cfg(all(feature = "v1", feature = "olap"))]
    async fn filter_refund_by_constraints(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_details: &refunds::RefundListConstraints,
        _storage_scheme: enums::MerchantStorageScheme,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<diesel_models::refund::Refund>, errors::StorageError> {
        let mut unique_connectors = HashSet::new();
        let mut unique_merchant_connector_ids = HashSet::new();
        let mut unique_currencies = HashSet::new();
        let mut unique_statuses = HashSet::new();
        let mut unique_profile_ids = HashSet::new();

        // Fill the hash sets with data from refund_details
        if let Some(connectors) = &refund_details.connector {
            connectors.iter().for_each(|connector| {
                unique_connectors.insert(connector);
            });
        }

        if let Some(merchant_connector_ids) = &refund_details.merchant_connector_id {
            merchant_connector_ids
                .iter()
                .for_each(|unique_merchant_connector_id| {
                    unique_merchant_connector_ids.insert(unique_merchant_connector_id);
                });
        }

        if let Some(currencies) = &refund_details.currency {
            currencies.iter().for_each(|currency| {
                unique_currencies.insert(currency);
            });
        }

        if let Some(refund_statuses) = &refund_details.refund_status {
            refund_statuses.iter().for_each(|refund_status| {
                unique_statuses.insert(refund_status);
            });
        }

        if let Some(profile_id_list) = &refund_details.profile_id {
            unique_profile_ids = profile_id_list.iter().collect();
        }

        let refunds = self.refunds.lock().await;
        let filtered_refunds = refunds
            .iter()
            .filter(|refund| refund.merchant_id == *merchant_id)
            .filter(|refund| {
                refund_details
                    .payment_id
                    .clone()
                    .map_or(true, |id| id == refund.payment_id)
            })
            .filter(|refund| {
                refund_details
                    .refund_id
                    .clone()
                    .map_or(true, |id| id == refund.refund_id)
            })
            .filter(|refund| {
                refund.profile_id.as_ref().is_some_and(|profile_id| {
                    unique_profile_ids.is_empty() || unique_profile_ids.contains(profile_id)
                })
            })
            .filter(|refund| {
                refund.created_at
                    >= refund_details.time_range.map_or(
                        common_utils::date_time::now() - time::Duration::days(60),
                        |range| range.start_time,
                    )
                    && refund.created_at
                        <= refund_details
                            .time_range
                            .map_or(common_utils::date_time::now(), |range| {
                                range.end_time.unwrap_or_else(common_utils::date_time::now)
                            })
            })
            .filter(|refund| {
                refund_details
                    .amount_filter
                    .as_ref()
                    .map_or(true, |amount| {
                        refund.refund_amount
                            >= MinorUnit::new(amount.start_amount.unwrap_or(i64::MIN))
                            && refund.refund_amount
                                <= MinorUnit::new(amount.end_amount.unwrap_or(i64::MAX))
                    })
            })
            .filter(|refund| {
                unique_connectors.is_empty() || unique_connectors.contains(&refund.connector)
            })
            .filter(|refund| {
                unique_merchant_connector_ids.is_empty()
                    || refund
                        .merchant_connector_id
                        .as_ref()
                        .is_some_and(|id| unique_merchant_connector_ids.contains(id))
            })
            .filter(|refund| {
                unique_currencies.is_empty() || unique_currencies.contains(&refund.currency)
            })
            .filter(|refund| {
                unique_statuses.is_empty() || unique_statuses.contains(&refund.refund_status)
            })
            .skip(usize::try_from(offset).unwrap_or_default())
            .take(usize::try_from(limit).unwrap_or(MAX_LIMIT))
            .cloned()
            .collect::<Vec<_>>();

        Ok(filtered_refunds)
    }

    #[cfg(all(feature = "v2", feature = "olap"))]
    async fn filter_refund_by_constraints(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_details: refunds::RefundListConstraints,
        _storage_scheme: enums::MerchantStorageScheme,
        limit: i64,
        offset: i64,
    ) -> CustomResult<Vec<diesel_models::refund::Refund>, errors::StorageError> {
        let mut unique_connectors = HashSet::new();
        let mut unique_connector_ids = HashSet::new();
        let mut unique_currencies = HashSet::new();
        let mut unique_statuses = HashSet::new();

        // Fill the hash sets with data from refund_details
        if let Some(connectors) = &refund_details.connector {
            connectors.iter().for_each(|connector| {
                unique_connectors.insert(connector);
            });
        }

        if let Some(connector_id_list) = &refund_details.connector_id_list {
            connector_id_list.iter().for_each(|unique_connector_id| {
                unique_connector_ids.insert(unique_connector_id);
            });
        }

        if let Some(currencies) = &refund_details.currency {
            currencies.iter().for_each(|currency| {
                unique_currencies.insert(currency);
            });
        }

        if let Some(refund_statuses) = &refund_details.refund_status {
            refund_statuses.iter().for_each(|refund_status| {
                unique_statuses.insert(refund_status);
            });
        }

        let refunds = self.refunds.lock().await;
        let filtered_refunds = refunds
            .iter()
            .filter(|refund| refund.merchant_id == *merchant_id)
            .filter(|refund| {
                refund_details
                    .payment_id
                    .clone()
                    .map_or(true, |id| id == refund.payment_id)
            })
            .filter(|refund| {
                refund_details
                    .refund_id
                    .clone()
                    .map_or(true, |id| id == refund.id)
            })
            .filter(|refund| {
                refund
                    .profile_id
                    .as_ref()
                    .is_some_and(|profile_id| profile_id == &refund_details.profile_id)
            })
            .filter(|refund| {
                refund.created_at
                    >= refund_details.time_range.map_or(
                        common_utils::date_time::now() - time::Duration::days(60),
                        |range| range.start_time,
                    )
                    && refund.created_at
                        <= refund_details
                            .time_range
                            .map_or(common_utils::date_time::now(), |range| {
                                range.end_time.unwrap_or_else(common_utils::date_time::now)
                            })
            })
            .filter(|refund| {
                refund_details
                    .amount_filter
                    .as_ref()
                    .map_or(true, |amount| {
                        refund.refund_amount
                            >= MinorUnit::new(amount.start_amount.unwrap_or(i64::MIN))
                            && refund.refund_amount
                                <= MinorUnit::new(amount.end_amount.unwrap_or(i64::MAX))
                    })
            })
            .filter(|refund| {
                unique_connectors.is_empty() || unique_connectors.contains(&refund.connector)
            })
            .filter(|refund| {
                unique_connector_ids.is_empty()
                    || refund
                        .connector_id
                        .as_ref()
                        .is_some_and(|id| unique_connector_ids.contains(id))
            })
            .filter(|refund| {
                unique_currencies.is_empty() || unique_currencies.contains(&refund.currency)
            })
            .filter(|refund| {
                unique_statuses.is_empty() || unique_statuses.contains(&refund.refund_status)
            })
            .skip(usize::try_from(offset).unwrap_or_default())
            .take(usize::try_from(limit).unwrap_or(MAX_LIMIT))
            .cloned()
            .collect::<Vec<_>>();

        Ok(filtered_refunds)
    }

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

        let start_time = refund_details.start_time;
        let end_time = refund_details
            .end_time
            .unwrap_or_else(common_utils::date_time::now);

        let filtered_refunds = refunds
            .iter()
            .filter(|refund| refund.created_at >= start_time && refund.created_at <= end_time)
            .cloned()
            .collect::<Vec<diesel_models::refund::Refund>>();

        let mut refund_meta_data = api_models::refunds::RefundListMetaData {
            connector: vec![],
            currency: vec![],
            refund_status: vec![],
        };

        let mut unique_connectors = HashSet::new();
        let mut unique_currencies = HashSet::new();
        let mut unique_statuses = HashSet::new();

        for refund in filtered_refunds.into_iter() {
            unique_connectors.insert(refund.connector);

            let currency: api_models::enums::Currency = refund.currency;
            unique_currencies.insert(currency);

            let status: api_models::enums::RefundStatus = refund.refund_status;
            unique_statuses.insert(status);
        }

        refund_meta_data.connector = unique_connectors.into_iter().collect();
        refund_meta_data.currency = unique_currencies.into_iter().collect();
        refund_meta_data.refund_status = unique_statuses.into_iter().collect();

        Ok(refund_meta_data)
    }

    #[cfg(all(feature = "v1", feature = "olap"))]
    async fn get_refund_status_with_count(
        &self,
        _merchant_id: &common_utils::id_type::MerchantId,
        profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
        time_range: &common_utils::types::TimeRange,
        _storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<Vec<(api_models::enums::RefundStatus, i64)>, errors::StorageError> {
        let refunds = self.refunds.lock().await;

        let start_time = time_range.start_time;
        let end_time = time_range
            .end_time
            .unwrap_or_else(common_utils::date_time::now);

        let filtered_refunds = refunds
            .iter()
            .filter(|refund| {
                refund.created_at >= start_time
                    && refund.created_at <= end_time
                    && profile_id_list
                        .as_ref()
                        .zip(refund.profile_id.as_ref())
                        .map(|(received_profile_list, received_profile_id)| {
                            received_profile_list.contains(received_profile_id)
                        })
                        .unwrap_or(true)
            })
            .cloned()
            .collect::<Vec<diesel_models::refund::Refund>>();

        let mut refund_status_counts: HashMap<api_models::enums::RefundStatus, i64> =
            HashMap::new();

        for refund in filtered_refunds {
            *refund_status_counts
                .entry(refund.refund_status)
                .or_insert(0) += 1;
        }

        let result: Vec<(api_models::enums::RefundStatus, i64)> =
            refund_status_counts.into_iter().collect();

        Ok(result)
    }

    #[cfg(all(feature = "v1", feature = "olap"))]
    async fn get_total_count_of_refunds(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_details: &refunds::RefundListConstraints,
        _storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<i64, errors::StorageError> {
        let mut unique_connectors = HashSet::new();
        let mut unique_merchant_connector_ids = HashSet::new();
        let mut unique_currencies = HashSet::new();
        let mut unique_statuses = HashSet::new();
        let mut unique_profile_ids = HashSet::new();

        // Fill the hash sets with data from refund_details
        if let Some(connectors) = &refund_details.connector {
            connectors.iter().for_each(|connector| {
                unique_connectors.insert(connector);
            });
        }

        if let Some(merchant_connector_ids) = &refund_details.merchant_connector_id {
            merchant_connector_ids
                .iter()
                .for_each(|unique_merchant_connector_id| {
                    unique_merchant_connector_ids.insert(unique_merchant_connector_id);
                });
        }

        if let Some(currencies) = &refund_details.currency {
            currencies.iter().for_each(|currency| {
                unique_currencies.insert(currency);
            });
        }

        if let Some(refund_statuses) = &refund_details.refund_status {
            refund_statuses.iter().for_each(|refund_status| {
                unique_statuses.insert(refund_status);
            });
        }

        if let Some(profile_id_list) = &refund_details.profile_id {
            unique_profile_ids = profile_id_list.iter().collect();
        }

        let refunds = self.refunds.lock().await;
        let filtered_refunds = refunds
            .iter()
            .filter(|refund| refund.merchant_id == *merchant_id)
            .filter(|refund| {
                refund_details
                    .payment_id
                    .clone()
                    .map_or(true, |id| id == refund.payment_id)
            })
            .filter(|refund| {
                refund_details
                    .refund_id
                    .clone()
                    .map_or(true, |id| id == refund.refund_id)
            })
            .filter(|refund| {
                refund.profile_id.as_ref().is_some_and(|profile_id| {
                    unique_profile_ids.is_empty() || unique_profile_ids.contains(profile_id)
                })
            })
            .filter(|refund| {
                refund.created_at
                    >= refund_details.time_range.map_or(
                        common_utils::date_time::now() - time::Duration::days(60),
                        |range| range.start_time,
                    )
                    && refund.created_at
                        <= refund_details
                            .time_range
                            .map_or(common_utils::date_time::now(), |range| {
                                range.end_time.unwrap_or_else(common_utils::date_time::now)
                            })
            })
            .filter(|refund| {
                refund_details
                    .amount_filter
                    .as_ref()
                    .map_or(true, |amount| {
                        refund.refund_amount
                            >= MinorUnit::new(amount.start_amount.unwrap_or(i64::MIN))
                            && refund.refund_amount
                                <= MinorUnit::new(amount.end_amount.unwrap_or(i64::MAX))
                    })
            })
            .filter(|refund| {
                unique_connectors.is_empty() || unique_connectors.contains(&refund.connector)
            })
            .filter(|refund| {
                unique_merchant_connector_ids.is_empty()
                    || refund
                        .merchant_connector_id
                        .as_ref()
                        .is_some_and(|id| unique_merchant_connector_ids.contains(id))
            })
            .filter(|refund| {
                unique_currencies.is_empty() || unique_currencies.contains(&refund.currency)
            })
            .filter(|refund| {
                unique_statuses.is_empty() || unique_statuses.contains(&refund.refund_status)
            })
            .cloned()
            .collect::<Vec<_>>();

        let filtered_refunds_count = filtered_refunds.len().try_into().unwrap_or_default();

        Ok(filtered_refunds_count)
    }

    #[cfg(all(feature = "v2", feature = "olap"))]
    async fn get_total_count_of_refunds(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        refund_details: refunds::RefundListConstraints,
        _storage_scheme: enums::MerchantStorageScheme,
    ) -> CustomResult<i64, errors::StorageError> {
        let mut unique_connectors = HashSet::new();
        let mut unique_connector_ids = HashSet::new();
        let mut unique_currencies = HashSet::new();
        let mut unique_statuses = HashSet::new();

        // Fill the hash sets with data from refund_details
        if let Some(connectors) = &refund_details.connector {
            connectors.iter().for_each(|connector| {
                unique_connectors.insert(connector);
            });
        }

        if let Some(connector_id_list) = &refund_details.connector_id_list {
            connector_id_list.iter().for_each(|unique_connector_id| {
                unique_connector_ids.insert(unique_connector_id);
            });
        }

        if let Some(currencies) = &refund_details.currency {
            currencies.iter().for_each(|currency| {
                unique_currencies.insert(currency);
            });
        }

        if let Some(refund_statuses) = &refund_details.refund_status {
            refund_statuses.iter().for_each(|refund_status| {
                unique_statuses.insert(refund_status);
            });
        }

        let refunds = self.refunds.lock().await;
        let filtered_refunds = refunds
            .iter()
            .filter(|refund| refund.merchant_id == *merchant_id)
            .filter(|refund| {
                refund_details
                    .payment_id
                    .clone()
                    .map_or(true, |id| id == refund.payment_id)
            })
            .filter(|refund| {
                refund_details
                    .refund_id
                    .clone()
                    .map_or(true, |id| id == refund.id)
            })
            .filter(|refund| {
                refund
                    .profile_id
                    .as_ref()
                    .is_some_and(|profile_id| profile_id == &refund_details.profile_id)
            })
            .filter(|refund| {
                refund.created_at
                    >= refund_details.time_range.map_or(
                        common_utils::date_time::now() - time::Duration::days(60),
                        |range| range.start_time,
                    )
                    && refund.created_at
                        <= refund_details
                            .time_range
                            .map_or(common_utils::date_time::now(), |range| {
                                range.end_time.unwrap_or_else(common_utils::date_time::now)
                            })
            })
            .filter(|refund| {
                refund_details
                    .amount_filter
                    .as_ref()
                    .map_or(true, |amount| {
                        refund.refund_amount
                            >= MinorUnit::new(amount.start_amount.unwrap_or(i64::MIN))
                            && refund.refund_amount
                                <= MinorUnit::new(amount.end_amount.unwrap_or(i64::MAX))
                    })
            })
            .filter(|refund| {
                unique_connectors.is_empty() || unique_connectors.contains(&refund.connector)
            })
            .filter(|refund| {
                unique_connector_ids.is_empty()
                    || refund
                        .connector_id
                        .as_ref()
                        .is_some_and(|id| unique_connector_ids.contains(id))
            })
            .filter(|refund| {
                unique_currencies.is_empty() || unique_currencies.contains(&refund.currency)
            })
            .filter(|refund| {
                unique_statuses.is_empty() || unique_statuses.contains(&refund.refund_status)
            })
            .cloned()
            .collect::<Vec<_>>();

        let filtered_refunds_count = filtered_refunds.len().try_into().unwrap_or_default();

        Ok(filtered_refunds_count)
    }
}


impl api::RefundExecute for Globepay {}

impl api::RefundExecute for for Globepay


File: crates/router/src/core/relay.rs
 Public functions: 5
 Public structs: 2

use std::marker::PhantomData;

use api_models::relay as relay_api_models;
use async_trait::async_trait;
use common_enums::RelayStatus;
use common_utils::{
    self, fp_utils,
    id_type::{self, GenerateId},
};
use error_stack::ResultExt;
use hyperswitch_domain_models::relay;

use super::errors::{self, ConnectorErrorExt, RouterResponse, RouterResult, StorageErrorExt};
use crate::{
    core::payments,
    routes::SessionState,
    services,
    types::{
        api::{self},
        domain,
    },
    utils::OptionExt,
};

pub mod utils;

pub trait Validate {
    type Error: error_stack::Context;
    fn validate(&self) -> Result<(), Self::Error>;
}

impl Validate for relay_api_models::RelayRefundRequestData {
    type Error = errors::ApiErrorResponse;
    fn validate(&self) -> Result<(), Self::Error> {
        fp_utils::when(self.amount.get_amount_as_i64() <= 0, || {
            Err(errors::ApiErrorResponse::PreconditionFailed {
                message: "Amount should be greater than 0".to_string(),
            })
        })?;
        Ok(())
    }
}

#[async_trait]
pub trait RelayInterface {
    type Request: Validate;
    fn validate_relay_request(req: &Self::Request) -> RouterResult<()> {
        req.validate()
            .change_context(errors::ApiErrorResponse::PreconditionFailed {
                message: "Invalid relay request".to_string(),
            })
    }

    fn get_domain_models(
        relay_request: RelayRequestInner<Self>,
        merchant_id: &id_type::MerchantId,
        profile_id: &id_type::ProfileId,
    ) -> relay::Relay;

    async fn process_relay(
        state: &SessionState,
        merchant_context: domain::MerchantContext,
        connector_account: domain::MerchantConnectorAccount,
        relay_record: &relay::Relay,
    ) -> RouterResult<relay::RelayUpdate>;

    fn generate_response(value: relay::Relay) -> RouterResult<api_models::relay::RelayResponse>;
}

pub struct RelayRequestInner<T: RelayInterface + ?Sized> {
    pub connector_resource_id: String,
    pub connector_id: id_type::MerchantConnectorAccountId,
    pub relay_type: PhantomData<T>,
    pub data: T::Request,
}

impl RelayRequestInner<RelayRefund> {
    pub fn from_relay_request(relay_request: relay_api_models::RelayRequest) -> RouterResult<Self> {
        match relay_request.data {
            Some(relay_api_models::RelayData::Refund(ref_data)) => Ok(Self {
                connector_resource_id: relay_request.connector_resource_id,
                connector_id: relay_request.connector_id,
                relay_type: PhantomData,
                data: ref_data,
            }),
            None => Err(errors::ApiErrorResponse::InvalidRequestData {
                message: "Relay data is required for relay type refund".to_string(),
            })?,
        }
    }
}

pub struct RelayRefund;

#[async_trait]
impl RelayInterface for RelayRefund {
    type Request = relay_api_models::RelayRefundRequestData;

    fn get_domain_models(
        relay_request: RelayRequestInner<Self>,
        merchant_id: &id_type::MerchantId,
        profile_id: &id_type::ProfileId,
    ) -> relay::Relay {
        let relay_id = id_type::RelayId::generate();
        let relay_refund: relay::RelayRefundData = relay_request.data.into();
        relay::Relay {
            id: relay_id.clone(),
            connector_resource_id: relay_request.connector_resource_id.clone(),
            connector_id: relay_request.connector_id.clone(),
            profile_id: profile_id.clone(),
            merchant_id: merchant_id.clone(),
            relay_type: common_enums::RelayType::Refund,
            request_data: Some(relay::RelayData::Refund(relay_refund)),
            status: RelayStatus::Created,
            connector_reference_id: None,
            error_code: None,
            error_message: None,
            created_at: common_utils::date_time::now(),
            modified_at: common_utils::date_time::now(),
            response_data: None,
        }
    }

    async fn process_relay(
        state: &SessionState,
        merchant_context: domain::MerchantContext,
        connector_account: domain::MerchantConnectorAccount,
        relay_record: &relay::Relay,
    ) -> RouterResult<relay::RelayUpdate> {
        let connector_id = &relay_record.connector_id;

        let merchant_id = merchant_context.get_merchant_account().get_id();

        let connector_name = &connector_account.get_connector_name_as_string();

        let connector_data = api::ConnectorData::get_connector_by_name(
            &state.conf.connectors,
            connector_name,
            api::GetToken::Connector,
            Some(connector_id.clone()),
        )?;

        let connector_integration: services::BoxedRefundConnectorIntegrationInterface<
            api::Execute,
            hyperswitch_domain_models::router_request_types::RefundsData,
            hyperswitch_domain_models::router_response_types::RefundsResponseData,
        > = connector_data.connector.get_connector_integration();

        let router_data = utils::construct_relay_refund_router_data(
            state,
            merchant_id,
            &connector_account,
            relay_record,
        )
        .await?;

        let router_data_res = services::execute_connector_processing_step(
            state,
            connector_integration,
            &router_data,
            payments::CallConnectorAction::Trigger,
            None,
            None,
        )
        .await
        .to_refund_failed_response()?;

        let relay_update = relay::RelayUpdate::from(router_data_res.response);

        Ok(relay_update)
    }

    fn generate_response(value: relay::Relay) -> RouterResult<api_models::relay::RelayResponse> {
        let error = value
            .error_code
            .zip(value.error_message)
            .map(
                |(error_code, error_message)| api_models::relay::RelayError {
                    code: error_code,
                    message: error_message,
                },
            );

        let data =
            api_models::relay::RelayData::from(value.request_data.get_required_value("RelayData")?);

        Ok(api_models::relay::RelayResponse {
            id: value.id,
            status: value.status,
            error,
            connector_resource_id: value.connector_resource_id,
            connector_id: value.connector_id,
            profile_id: value.profile_id,
            relay_type: value.relay_type,
            data: Some(data),
            connector_reference_id: value.connector_reference_id,
        })
    }
}

pub async fn relay_flow_decider(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id_optional: Option<id_type::ProfileId>,
    request: relay_api_models::RelayRequest,
) -> RouterResponse<relay_api_models::RelayResponse> {
    let relay_flow_request = match request.relay_type {
        common_enums::RelayType::Refund => {
            RelayRequestInner::<RelayRefund>::from_relay_request(request)?
        }
    };
    relay(
        state,
        merchant_context,
        profile_id_optional,
        relay_flow_request,
    )
    .await
}

pub async fn relay<T: RelayInterface>(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id_optional: Option<id_type::ProfileId>,
    req: RelayRequestInner<T>,
) -> RouterResponse<relay_api_models::RelayResponse> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let merchant_id = merchant_context.get_merchant_account().get_id();
    let connector_id = &req.connector_id;

    let profile_id_from_auth_layer = profile_id_optional.get_required_value("ProfileId")?;

    let profile = db
        .find_business_profile_by_merchant_id_profile_id(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            merchant_id,
            &profile_id_from_auth_layer,
        )
        .await
        .change_context(errors::ApiErrorResponse::ProfileNotFound {
            id: profile_id_from_auth_layer.get_string_repr().to_owned(),
        })?;

    #[cfg(feature = "v1")]
    let connector_account = db
        .find_by_merchant_connector_account_merchant_id_merchant_connector_id(
            key_manager_state,
            merchant_id,
            connector_id,
            merchant_context.get_merchant_key_store(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: connector_id.get_string_repr().to_string(),
        })?;

    #[cfg(feature = "v2")]
    let connector_account = db
        .find_merchant_connector_account_by_id(
            key_manager_state,
            connector_id,
            merchant_context.get_merchant_key_store(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: connector_id.get_string_repr().to_string(),
        })?;

    T::validate_relay_request(&req.data)?;

    let relay_domain = T::get_domain_models(req, merchant_id, profile.get_id());

    let relay_record = db
        .insert_relay(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            relay_domain,
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to insert a relay record in db")?;

    let relay_response = T::process_relay(
        &state,
        merchant_context.clone(),
        connector_account,
        &relay_record,
    )
    .await
    .attach_printable("Failed to process relay")?;

    let relay_update_record = db
        .update_relay(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            relay_record,
            relay_response,
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)?;

    let response = T::generate_response(relay_update_record)
        .attach_printable("Failed to generate relay response")?;

    Ok(hyperswitch_domain_models::api::ApplicationResponse::Json(
        response,
    ))
}

pub async fn relay_retrieve(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id_optional: Option<id_type::ProfileId>,
    req: relay_api_models::RelayRetrieveRequest,
) -> RouterResponse<relay_api_models::RelayResponse> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let merchant_id = merchant_context.get_merchant_account().get_id();
    let relay_id = &req.id;

    let profile_id_from_auth_layer = profile_id_optional.get_required_value("ProfileId")?;

    db.find_business_profile_by_merchant_id_profile_id(
        key_manager_state,
        merchant_context.get_merchant_key_store(),
        merchant_id,
        &profile_id_from_auth_layer,
    )
    .await
    .change_context(errors::ApiErrorResponse::ProfileNotFound {
        id: profile_id_from_auth_layer.get_string_repr().to_owned(),
    })?;

    let relay_record_result = db
        .find_relay_by_id(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            relay_id,
        )
        .await;

    let relay_record = match relay_record_result {
        Err(error) => {
            if error.current_context().is_db_not_found() {
                Err(error).change_context(errors::ApiErrorResponse::GenericNotFoundError {
                    message: "relay not found".to_string(),
                })?
            } else {
                Err(error)
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("error while fetch relay record")?
            }
        }
        Ok(relay) => relay,
    };

    #[cfg(feature = "v1")]
    let connector_account = db
        .find_by_merchant_connector_account_merchant_id_merchant_connector_id(
            key_manager_state,
            merchant_id,
            &relay_record.connector_id,
            merchant_context.get_merchant_key_store(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: relay_record.connector_id.get_string_repr().to_string(),
        })?;

    #[cfg(feature = "v2")]
    let connector_account = db
        .find_merchant_connector_account_by_id(
            key_manager_state,
            &relay_record.connector_id,
            merchant_context.get_merchant_key_store(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: relay_record.connector_id.get_string_repr().to_string(),
        })?;

    let relay_response = match relay_record.relay_type {
        common_enums::RelayType::Refund => {
            if should_call_connector_for_relay_refund_status(&relay_record, req.force_sync) {
                let relay_response = sync_relay_refund_with_gateway(
                    &state,
                    &merchant_context,
                    &relay_record,
                    connector_account,
                )
                .await?;

                db.update_relay(
                    key_manager_state,
                    merchant_context.get_merchant_key_store(),
                    relay_record,
                    relay_response,
                )
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed to update the relay record")?
            } else {
                relay_record
            }
        }
    };

    let response = relay_api_models::RelayResponse::from(relay_response);

    Ok(hyperswitch_domain_models::api::ApplicationResponse::Json(
        response,
    ))
}

fn should_call_connector_for_relay_refund_status(relay: &relay::Relay, force_sync: bool) -> bool {
    // This allows refund sync at connector level if force_sync is enabled, or
    // check if the refund is in terminal state
    !matches!(relay.status, RelayStatus::Failure | RelayStatus::Success) && force_sync
}

pub async fn sync_relay_refund_with_gateway(
    state: &SessionState,
    merchant_context: &domain::MerchantContext,
    relay_record: &relay::Relay,
    connector_account: domain::MerchantConnectorAccount,
) -> RouterResult<relay::RelayUpdate> {
    let connector_id = &relay_record.connector_id;
    let merchant_id = merchant_context.get_merchant_account().get_id();

    #[cfg(feature = "v1")]
    let connector_name = &connector_account.connector_name;

    #[cfg(feature = "v2")]
    let connector_name = &connector_account.connector_name.to_string();

    let connector_data: api::ConnectorData = api::ConnectorData::get_connector_by_name(
        &state.conf.connectors,
        connector_name,
        api::GetToken::Connector,
        Some(connector_id.clone()),
    )
    .change_context(errors::ApiErrorResponse::InternalServerError)
    .attach_printable("Failed to get the connector")?;

    let router_data = utils::construct_relay_refund_router_data(
        state,
        merchant_id,
        &connector_account,
        relay_record,
    )
    .await?;

    let connector_integration: services::BoxedRefundConnectorIntegrationInterface<
        api::RSync,
        hyperswitch_domain_models::router_request_types::RefundsData,
        hyperswitch_domain_models::router_response_types::RefundsResponseData,
    > = connector_data.connector.get_connector_integration();

    let router_data_res = services::execute_connector_processing_step(
        state,
        connector_integration,
        &router_data,
        payments::CallConnectorAction::Trigger,
        None,
        None,
    )
    .await
    .to_refund_failed_response()?;

    let relay_response = relay::RelayUpdate::from(router_data_res.response);

    Ok(relay_response)
}


OpenAPI Block Path: components.schemas.OutgoingWebhook
{
  "type": "object",
  "required": [
    "merchant_id",
    "event_id",
    "event_type",
    "content"
  ],
  "properties": {
    "merchant_id": {
      "type": "string",
      "description": "The merchant id of the merchant"
    },
    "event_id": {
      "type": "string",
      "description": "The unique event id for each webhook"
    },
    "event_type": {
      "$ref": "#/components/schemas/EventType"
    },
    "content": {
      "$ref": "#/components/schemas/OutgoingWebhookContent"
    },
    "timestamp": {
      "type": "string",
      "format": "date-time",
      "description": "The time at which webhook was sent"
    }
  }
}


impl api::PaymentToken for Inespay {}


pub async fn update_payment_method_connector_mandate_details(
    state: &routes::SessionState,
    key_store: &domain::MerchantKeyStore,
    db: &dyn db::StorageInterface,
    pm: domain::PaymentMethod,
    connector_mandate_details: Option<CommonMandateReference>,
    storage_scheme: MerchantStorageScheme,
) -> errors::CustomResult<(), errors::VaultError> {
    let pm_update = payment_method::PaymentMethodUpdate::ConnectorMandateDetailsUpdate {
        connector_mandate_details: connector_mandate_details.map(|cmd| cmd.into()),
    };

    db.update_payment_method(&(state.into()), key_store, pm, pm_update, storage_scheme)
        .await
        .change_context(errors::VaultError::UpdateInPaymentMethodDataTableFailed)?;
    Ok(())
}


pub struct PaytmErrorResponse {
    pub status_code: u16,
    pub code: String,
    pub message: String,
    pub reason: Option<String>,
    pub network_advice_code: Option<String>,
    pub network_decline_code: Option<String>,
    pub network_error_message: Option<String>,
}


pub async fn routing_retrieve_default_config_for_profiles() {}


impl api::Payment for Adyenplatform {}


File: crates/diesel_models/src/query/dynamic_routing_stats.rs
 Public functions: 3

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

use super::generics;
use crate::{
    dynamic_routing_stats::{
        DynamicRoutingStats, DynamicRoutingStatsNew, DynamicRoutingStatsUpdate,
    },
    errors,
    schema::dynamic_routing_stats::dsl,
    PgPooledConn, StorageResult,
};

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

impl DynamicRoutingStats {
    pub async fn find_optional_by_attempt_id_merchant_id(
        conn: &PgPooledConn,
        attempt_id: String,
        merchant_id: &common_utils::id_type::MerchantId,
    ) -> StorageResult<Option<Self>> {
        generics::generic_find_one_optional::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::attempt_id.eq(attempt_id.to_owned())),
        )
        .await
    }

    pub async fn update(
        conn: &PgPooledConn,
        attempt_id: String,
        merchant_id: &common_utils::id_type::MerchantId,
        dynamic_routing_stat: DynamicRoutingStatsUpdate,
    ) -> StorageResult<Self> {
        generics::generic_update_with_results::<
            <Self as HasTable>::Table,
            DynamicRoutingStatsUpdate,
            _,
            _,
        >(
            conn,
            dsl::merchant_id
                .eq(merchant_id.to_owned())
                .and(dsl::attempt_id.eq(attempt_id.to_owned())),
            dynamic_routing_stat,
        )
        .await?
        .first()
        .cloned()
        .ok_or_else(|| {
            report!(errors::DatabaseError::NotFound)
                .attach_printable("Error while updating dynamic_routing_stats entry")
        })
    }
}


pub struct UserKeyTransferRequest {
    pub from: u32,
    pub limit: u32,
}


pub fn get_method(&self) -> common_utils::request::Method {
        self.0.method
    }


pub struct ResultCode {
    pub(super) code: String,
    pub(super) description: String,
    pub(super) parameter_errors: Option<Vec<ErrorParameters>>,
}


impl api::PaymentAuthorize for Shift4 {}

impl api::PaymentAuthorize for for Shift4


impl CustomerUpdateRequest {
    pub fn get_default_customer_billing_address(&self) -> Option<payments::AddressDetails> {
        self.default_billing_address.clone()
    }

    pub fn get_default_customer_shipping_address(&self) -> Option<payments::AddressDetails> {
        self.default_shipping_address.clone()
    }
}


File: crates/analytics/src/frm/accumulator.rs
 Public functions: 1
 Public structs: 3

use api_models::analytics::frm::FrmMetricsBucketValue;
use common_enums::enums as storage_enums;

use super::metrics::FrmMetricRow;
#[derive(Debug, Default)]
pub struct FrmMetricsAccumulator {
    pub frm_triggered_attempts: TriggeredAttemptsAccumulator,
    pub frm_blocked_rate: BlockedRateAccumulator,
}

#[derive(Debug, Default)]
#[repr(transparent)]
pub struct TriggeredAttemptsAccumulator {
    pub count: Option<i64>,
}

#[derive(Debug, Default)]
pub struct BlockedRateAccumulator {
    pub fraud: i64,
    pub total: i64,
}

pub trait FrmMetricAccumulator {
    type MetricOutput;

    fn add_metrics_bucket(&mut self, metrics: &FrmMetricRow);

    fn collect(self) -> Self::MetricOutput;
}

impl FrmMetricAccumulator for TriggeredAttemptsAccumulator {
    type MetricOutput = Option<u64>;
    #[inline]
    fn add_metrics_bucket(&mut self, metrics: &FrmMetricRow) {
        self.count = match (self.count, metrics.count) {
            (None, None) => None,
            (None, i @ Some(_)) | (i @ Some(_), None) => i,
            (Some(a), Some(b)) => Some(a + b),
        }
    }
    #[inline]
    fn collect(self) -> Self::MetricOutput {
        self.count.and_then(|i| u64::try_from(i).ok())
    }
}

impl FrmMetricAccumulator for BlockedRateAccumulator {
    type MetricOutput = Option<f64>;

    fn add_metrics_bucket(&mut self, metrics: &FrmMetricRow) {
        if let Some(ref frm_status) = metrics.frm_status {
            if frm_status.as_ref() == &storage_enums::FraudCheckStatus::Fraud {
                self.fraud += metrics.count.unwrap_or_default();
            }
        };
        self.total += metrics.count.unwrap_or_default();
    }

    fn collect(self) -> Self::MetricOutput {
        if self.total <= 0 {
            None
        } else {
            Some(
                f64::from(u32::try_from(self.fraud).ok()?) * 100.0
                    / f64::from(u32::try_from(self.total).ok()?),
            )
        }
    }
}

impl FrmMetricsAccumulator {
    pub fn collect(self) -> FrmMetricsBucketValue {
        FrmMetricsBucketValue {
            frm_blocked_rate: self.frm_blocked_rate.collect(),
            frm_triggered_attempts: self.frm_triggered_attempts.collect(),
        }
    }
}


pub struct Datatrans3DSResponse {
    pub transaction_id: String,
    #[serde(rename = "3D")]
    pub three_ds_enrolled: ThreeDSEnolled,
}


impl api::RefundSync for HyperswitchVault {}

impl api::RefundSync for for HyperswitchVault


/// Reopen calculate workflow when payment fails
pub async fn reopen_calculate_workflow_on_payment_failure(
    state: &SessionState,
    process: &storage::ProcessTracker,
    profile: &domain::Profile,
    merchant_context: domain::MerchantContext,
    payment_intent: &PaymentIntent,
    revenue_recovery_payment_data: &storage::revenue_recovery::RevenueRecoveryPaymentData,
) -> RecoveryResult<()> {
    let db = &*state.store;
    let id = payment_intent.id.clone();
    let task = revenue_recovery_core::CALCULATE_WORKFLOW;
    let runner = storage::ProcessTrackerRunner::PassiveRecoveryWorkflow;

    // Construct the process tracker ID for CALCULATE_WORKFLOW
    let process_tracker_id = format!("{}_{}_{}", runner, task, id.get_string_repr());

    logger::info!(
        payment_id = %id.get_string_repr(),
        process_tracker_id = %process_tracker_id,
        "Attempting to reopen CALCULATE_WORKFLOW on payment failure"
    );

    // Find the existing CALCULATE_WORKFLOW process tracker
    let calculate_process = db
        .find_process_by_id(&process_tracker_id)
        .await
        .change_context(errors::RecoveryError::ProcessTrackerFailure)
        .attach_printable("Failed to find CALCULATE_WORKFLOW process tracker")?;

    match calculate_process {
        Some(process) => {
            logger::info!(
                payment_id = %id.get_string_repr(),
                process_tracker_id = %process_tracker_id,
                current_status = %process.business_status,
                current_retry_count = process.retry_count,
                "Found existing CALCULATE_WORKFLOW, updating status and retry count"
            );

            // Update the process tracker to reopen the calculate workflow
            // 1. Change status from "finish" to "pending"
            // 2. Increase retry count by 1
            // 3. Set business status to QUEUED
            // 4. Schedule for immediate execution
            let new_retry_count = process.retry_count + 1;
            let new_schedule_time = common_utils::date_time::now()
                + time::Duration::seconds(
                    state
                        .conf
                        .revenue_recovery
                        .recovery_timestamp
                        .reopen_workflow_buffer_time_in_seconds,
                );

            let pt_update = storage::ProcessTrackerUpdate::Update {
                name: Some(task.to_string()),
                retry_count: Some(new_retry_count),
                schedule_time: Some(new_schedule_time),
                tracking_data: Some(process.clone().tracking_data),
                business_status: Some(String::from(business_status::PENDING)),
                status: Some(common_enums::ProcessTrackerStatus::Pending),
                updated_at: Some(common_utils::date_time::now()),
            };

            db.update_process(process.clone(), pt_update)
                .await
                .change_context(errors::RecoveryError::ProcessTrackerFailure)
                .attach_printable("Failed to update CALCULATE_WORKFLOW process tracker")?;

            logger::info!(
                payment_id = %id.get_string_repr(),
                process_tracker_id = %process_tracker_id,
                new_retry_count = new_retry_count,
                new_schedule_time = %new_schedule_time,
                "Successfully reopened CALCULATE_WORKFLOW with increased retry count"
            );
        }
        None => {
            logger::info!(
                payment_id = %id.get_string_repr(),
                process_tracker_id = %process_tracker_id,
                "CALCULATE_WORKFLOW process tracker not found, creating new entry"
            );

            let task = "CALCULATE_WORKFLOW";

            let db = &*state.store;

            // Create process tracker ID in the format: CALCULATE_WORKFLOW_{payment_intent_id}
            let process_tracker_id = format!("{runner}_{task}_{}", id.get_string_repr());

            // Set scheduled time to 1 hour from now
            let schedule_time = common_utils::date_time::now() + time::Duration::hours(1);

            // Check if a process tracker entry already exists for this payment intent
            let existing_entry = db
                .as_scheduler()
                .find_process_by_id(&process_tracker_id)
                .await
                .change_context(errors::RecoveryError::ProcessTrackerFailure)
                .attach_printable(
                    "Failed to check for existing calculate workflow process tracker entry",
                )?;

            match existing_entry {
                Some(existing_process) => {
                    router_env::logger::error!(
                        "Found existing CALCULATE_WORKFLOW task with  id: {}",
                        existing_process.id
                    );
                }
                None => {
                    // No entry exists - create a new one
                    router_env::logger::info!(
                    "No existing CALCULATE_WORKFLOW task found for payment_intent_id: {}, creating new entry scheduled for 1 hour from now",
                    id.get_string_repr()
                );

                    let tag = ["PCR"];
                    let task = "CALCULATE_WORKFLOW";
                    let runner = storage::ProcessTrackerRunner::PassiveRecoveryWorkflow;

                    let process_tracker_entry = storage::ProcessTrackerNew::new(
                        &process_tracker_id,
                        task,
                        runner,
                        tag,
                        process.tracking_data.clone(),
                        Some(process.retry_count),
                        schedule_time,
                        common_types::consts::API_VERSION,
                    )
                    .change_context(errors::RecoveryError::ProcessTrackerFailure)
                    .attach_printable(
                        "Failed to construct calculate workflow process tracker entry",
                    )?;

                    // Insert into process tracker with status New
                    db.as_scheduler()
                        .insert_process(process_tracker_entry)
                        .await
                        .change_context(errors::RecoveryError::ProcessTrackerFailure)
                        .attach_printable(
                            "Failed to enter calculate workflow process_tracker_entry in DB",
                        )?;

                    router_env::logger::info!(
                    "Successfully created new CALCULATE_WORKFLOW task for payment_intent_id: {}",
                    id.get_string_repr()
                );
                }
            }

            let tracking_data = serde_json::from_value(process.tracking_data.clone())
                .change_context(errors::RecoveryError::ValueNotFound)
                .attach_printable("Failed to deserialize the tracking data from process tracker")?;

            // Call the existing perform_calculate_workflow function
            perform_calculate_workflow(
                state,
                process,
                profile,
                merchant_context,
                &tracking_data,
                revenue_recovery_payment_data,
                payment_intent,
            )
            .await
            .change_context(errors::RecoveryError::ProcessTrackerFailure)
            .attach_printable("Failed to perform calculate workflow")?;

            logger::info!(
                payment_id = %id.get_string_repr(),
                process_tracker_id = %process_tracker_id,
                "Successfully created new CALCULATE_WORKFLOW entry using perform_calculate_workflow"
            );
        }
    }

    Ok(())
}


impl api::PayoutCancel for Adyen {}


OpenAPI Block Path: paths."/refunds/list"
{
  "post": {
    "tags": [
      "Refunds"
    ],
    "summary": "Refunds - List",
    "description": "Lists all the refunds associated with the merchant, or for a specific payment if payment_id is provided",
    "operationId": "List all Refunds",
    "requestBody": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/RefundListRequest"
          }
        }
      },
      "required": true
    },
    "responses": {
      "200": {
        "description": "List of refunds",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RefundListResponse"
            }
          }
        }
      }
    },
    "security": [
      {
        "api_key": []
      }
    ]
  }
}


pub struct ContractRoutingAlgorithm {
    pub algorithm_id_with_timestamp:
        DynamicAlgorithmWithTimestamp<common_utils::id_type::RoutingId>,
    #[serde(default)]
    pub enabled_feature: DynamicRoutingFeatures,
}


pub struct InputClientTokenData {
    client_token: ClientTokenInput,
}


pub async fn generate_merchant_payment_report(
        state: web::Data<AppState>,
        req: actix_web::HttpRequest,
        json_payload: web::Json<ReportRequest>,
    ) -> impl Responder {
        let flow = AnalyticsFlow::GeneratePaymentReport;
        Box::pin(api::server_wrap(
            flow,
            state.clone(),
            &req,
            json_payload.into_inner(),
            |state, (auth, user_id): auth::AuthenticationDataWithUserId, payload, _| async move {
                let user = UserInterface::find_user_by_id(&*state.global_store, &user_id)
                    .await
                    .change_context(AnalyticsError::UnknownError)?;

                let user_email = UserEmail::from_pii_email(user.email)
                    .change_context(AnalyticsError::UnknownError)?
                    .get_secret();

                let org_id = auth.merchant_account.get_org_id();
                let merchant_id = auth.merchant_account.get_id();
                let lambda_req = GenerateReportRequest {
                    request: payload,
                    merchant_id: Some(merchant_id.clone()),
                    auth: AuthInfo::MerchantLevel {
                        org_id: org_id.clone(),
                        merchant_ids: vec![merchant_id.clone()],
                    },
                    email: user_email,
                };

                let json_bytes =
                    serde_json::to_vec(&lambda_req).map_err(|_| AnalyticsError::UnknownError)?;
                invoke_lambda(
                    &state.conf.report_download_config.payment_function,
                    &state.conf.report_download_config.region,
                    &json_bytes,
                )
                .await
                .map(ApplicationResponse::Json)
            },
            &auth::JWTAuth {
                permission: Permission::MerchantReportRead,
            },
            api_locking::LockAction::NotApplicable,
        ))
        .await
    }


pub fn get_response_payload(input: JsValue) -> JsResult {
    let input: ConnectorApiIntegrationPayload = serde_wasm_bindgen::from_value(input)?;
    let result = ConnectorApiIntegrationPayload::get_transformed_response_payload(input);
    Ok(serde_wasm_bindgen::to_value(&result)?)
}


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

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

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

struct GlobalpaySeleniumTest;

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

async fn should_make_gpay_payment(driver: WebDriver) -> Result<(), WebDriverError> {
    let conn = GlobalpaySeleniumTest {};
    let pub_key = conn
        .get_configs()
        .automation_configs
        .unwrap()
        .globalpay_gateway_merchant_id
        .unwrap();
    conn.make_gpay_payment(driver,
        &format!("{CHECKOUT_BASE_URL}/gpay?amount=10.00&country=US&currency=USD&gatewayname=globalpayments&gatewaymerchantid={pub_key}"),
        vec![
        Event::Assert(Assert::IsPresent("succeeded")),
    ]).await?;
    Ok(())
}

async fn should_make_globalpay_paypal_payment(driver: WebDriver) -> Result<(), WebDriverError> {
    let conn = GlobalpaySeleniumTest {};
    conn.make_paypal_payment(
        driver,
        &format!("{CHECKOUT_BASE_URL}/saved/46"),
        vec![
            Event::Trigger(Trigger::Click(By::Id("payment-submit-btn"))),
            Event::Assert(Assert::IsPresent("Google")),
            Event::Assert(Assert::ContainsAny(
                Selector::QueryParamStr,
                vec!["status=succeeded"],
            )),
        ],
    )
    .await?;
    Ok(())
}

async fn should_make_globalpay_ideal_payment(driver: WebDriver) -> Result<(), WebDriverError> {
    let conn = GlobalpaySeleniumTest {};
    conn.make_redirection_payment(
        driver,
        vec![
            Event::Trigger(Trigger::Goto(&format!("{CHECKOUT_BASE_URL}/saved/53"))),
            Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
            Event::Assert(Assert::IsPresent("Choose your Bank")),
            Event::Trigger(Trigger::Click(By::Css("button.btn.btn-primary"))),
            Event::Assert(Assert::IsPresent("Login to your Online Banking Account")),
            Event::Trigger(Trigger::Click(By::Css("button.btn.btn-primary"))),
            Event::Assert(Assert::IsPresent("Transaction Authentication")),
            Event::Trigger(Trigger::Click(By::Css("button.btn.btn-primary"))),
            Event::Assert(Assert::IsPresent("Payment Successful")),
            Event::Trigger(Trigger::Click(By::Css("button.btn.btn-primary"))),
            Event::Assert(Assert::IsPresent("Google")),
            Event::Assert(Assert::ContainsAny(
                Selector::QueryParamStr,
                vec!["status=succeeded", "status=processing"],
            )),
        ],
    )
    .await?;
    Ok(())
}

async fn should_make_globalpay_giropay_payment(driver: WebDriver) -> Result<(), WebDriverError> {
    let conn = GlobalpaySeleniumTest {};
    conn.make_redirection_payment(
        driver,
        vec![
            Event::Trigger(Trigger::Goto(&format!("{CHECKOUT_BASE_URL}/saved/59"))),
            Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
            Event::Assert(Assert::IsPresent("Choose your Bank")),
            Event::Trigger(Trigger::Click(By::Css("button.btn.btn-primary"))),
            Event::Assert(Assert::IsPresent("Login to your Online Banking Account")),
            Event::Trigger(Trigger::Click(By::Css("button.btn.btn-primary"))),
            Event::Assert(Assert::IsPresent("Transaction Authentication")),
            Event::Trigger(Trigger::Click(By::Css("button.btn.btn-primary"))),
            Event::Assert(Assert::IsPresent("Payment Successful")),
            Event::Trigger(Trigger::Click(By::Css("button.btn.btn-primary"))),
            Event::Assert(Assert::IsPresent("Google")),
            Event::Assert(Assert::ContainsAny(
                Selector::QueryParamStr,
                vec!["status=succeeded", "status=processing"],
            )),
        ],
    )
    .await?;
    Ok(())
}

async fn should_make_globalpay_eps_payment(driver: WebDriver) -> Result<(), WebDriverError> {
    let conn = GlobalpaySeleniumTest {};
    conn.make_redirection_payment(
        driver,
        vec![
            Event::Trigger(Trigger::Goto(&format!("{CHECKOUT_BASE_URL}/saved/50"))),
            Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
            Event::Assert(Assert::IsPresent("Choose your Bank")),
            Event::Trigger(Trigger::Click(By::Css("button.btn.btn-primary"))),
            Event::Assert(Assert::IsPresent("Login to your Online Banking Account")),
            Event::Trigger(Trigger::Click(By::Css("button.btn.btn-primary"))),
            Event::Assert(Assert::IsPresent("Transaction Authentication")),
            Event::Trigger(Trigger::Click(By::Css("button.btn.btn-primary"))),
            Event::Assert(Assert::IsPresent("Payment Successful")),
            Event::Trigger(Trigger::Click(By::Css("button.btn.btn-primary"))),
            Event::Assert(Assert::IsPresent("Google")),
            Event::Assert(Assert::ContainsAny(
                Selector::QueryParamStr,
                vec!["status=succeeded", "status=processing"],
            )),
        ],
    )
    .await?;
    Ok(())
}

async fn should_make_globalpay_sofort_payment(driver: WebDriver) -> Result<(), WebDriverError> {
    let conn = GlobalpaySeleniumTest {};
    conn.make_redirection_payment(
        driver,
        vec![
            Event::Trigger(Trigger::Goto(&format!("{CHECKOUT_BASE_URL}/saved/63"))),
            Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
            Event::RunIf(
                Assert::IsPresent("Wählen"),
                vec![Event::Trigger(Trigger::Click(By::Css("p.description")))],
            ),
            Event::Assert(Assert::IsPresent("Demo Bank")),
            Event::Trigger(Trigger::SendKeys(
                By::Id("BackendFormLOGINNAMEUSERID"),
                "12345",
            )),
            Event::Trigger(Trigger::SendKeys(By::Id("BackendFormUSERPIN"), "1234")),
            Event::Trigger(Trigger::Click(By::Css(
                "button.button-right.primary.has-indicator",
            ))),
            Event::RunIf(
                Assert::IsPresent("Kontoauswahl"),
                vec![Event::Trigger(Trigger::Click(By::Css(
                    "button.button-right.primary.has-indicator",
                )))],
            ),
            Event::Assert(Assert::IsPresent("PPRO Payment Services Ltd.")),
            Event::Trigger(Trigger::SendKeys(By::Id("BackendFormTan"), "12345")),
            Event::Trigger(Trigger::Click(By::Css(
                "button.button-right.primary.has-indicator",
            ))),
            Event::Assert(Assert::IsPresent("Google")),
            Event::Assert(Assert::ContainsAny(
                Selector::QueryParamStr,
                vec!["status=succeeded", "status=processing"],
            )),
        ],
    )
    .await?;
    Ok(())
}

#[test]
#[serial]
fn should_make_gpay_payment_test() {
    tester!(should_make_gpay_payment);
}

#[test]
#[serial]
fn should_make_globalpay_paypal_payment_test() {
    tester!(should_make_globalpay_paypal_payment);
}

#[test]
#[serial]
fn should_make_globalpay_ideal_payment_test() {
    tester!(should_make_globalpay_ideal_payment);
}

#[test]
#[serial]
fn should_make_globalpay_giropay_payment_test() {
    tester!(should_make_globalpay_giropay_payment);
}

#[test]
#[serial]
fn should_make_globalpay_eps_payment_test() {
    tester!(should_make_globalpay_eps_payment);
}

#[test]
#[serial]
fn should_make_globalpay_sofort_payment_test() {
    tester!(should_make_globalpay_sofort_payment);
}


OpenAPI Block Path: paths."/gsm/update"
{
  "post": {
    "tags": [
      "Gsm"
    ],
    "summary": "Gsm - Update",
    "description": "Updates a Gsm Rule",
    "operationId": "Update Gsm Rule",
    "requestBody": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/GsmUpdateRequest"
          }
        }
      },
      "required": true
    },
    "responses": {
      "200": {
        "description": "Gsm updated",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/GsmResponse"
            }
          }
        }
      },
      "400": {
        "description": "Missing Mandatory fields"
      }
    },
    "security": [
      {
        "admin_api_key": []
      }
    ]
  }
}