mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 19:46:48 +08:00
feat(router): add filters for refunds (#1501)
Co-authored-by: Sampras Lopes <lsampras@protonmail.com>
This commit is contained in:
@ -507,10 +507,13 @@ pub enum WalletIssuer {
|
||||
Debug,
|
||||
Default,
|
||||
Eq,
|
||||
Hash,
|
||||
PartialEq,
|
||||
strum::Display,
|
||||
strum::EnumString,
|
||||
frunk::LabelledGeneric,
|
||||
serde::Deserialize,
|
||||
serde::Serialize,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum RefundStatus {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use common_utils::{custom_serde, pii};
|
||||
use common_utils::pii;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::PrimitiveDateTime;
|
||||
use utoipa::ToSchema;
|
||||
@ -132,29 +132,28 @@ pub struct RefundListRequest {
|
||||
pub payment_id: Option<String>,
|
||||
/// Limit on the number of objects to return
|
||||
pub limit: Option<i64>,
|
||||
/// The time at which refund is created
|
||||
#[serde(default, with = "custom_serde::iso8601::option")]
|
||||
pub created: Option<PrimitiveDateTime>,
|
||||
/// Time less than the refund created time
|
||||
#[serde(default, rename = "created.lt", with = "custom_serde::iso8601::option")]
|
||||
pub created_lt: Option<PrimitiveDateTime>,
|
||||
/// Time greater than the refund created time
|
||||
#[serde(default, rename = "created.gt", with = "custom_serde::iso8601::option")]
|
||||
pub created_gt: Option<PrimitiveDateTime>,
|
||||
/// Time less than or equals to the refund created time
|
||||
#[serde(
|
||||
default,
|
||||
rename = "created.lte",
|
||||
with = "custom_serde::iso8601::option"
|
||||
)]
|
||||
pub created_lte: Option<PrimitiveDateTime>,
|
||||
/// Time greater than or equals to the refund created time
|
||||
#[serde(
|
||||
default,
|
||||
rename = "created.gte",
|
||||
with = "custom_serde::iso8601::option"
|
||||
)]
|
||||
pub created_gte: Option<PrimitiveDateTime>,
|
||||
/// The starting point within a list of objects
|
||||
pub offset: Option<i64>,
|
||||
/// The time range for which objects are needed. TimeRange has two fields start_time and end_time from which objects can be filtered as per required scenarios (created_at, time less than, greater than etc).
|
||||
pub time_range: Option<TimeRange>,
|
||||
/// The list of connectors to filter refunds list
|
||||
pub connector: Option<Vec<String>>,
|
||||
/// The list of currencies to filter refunds list
|
||||
#[schema(value_type = Option<Vec<Currency>>)]
|
||||
pub currency: Option<Vec<enums::Currency>>,
|
||||
/// The list of refund statuses to filter refunds list
|
||||
#[schema(value_type = Option<Vec<RefundStatus>>)]
|
||||
pub refund_status: Option<Vec<enums::RefundStatus>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, ToSchema)]
|
||||
pub struct TimeRange {
|
||||
/// The start time to filter refunds list or to get list of filters. To get list of filters start time is needed to be passed
|
||||
#[serde(with = "common_utils::custom_serde::iso8601")]
|
||||
pub start_time: PrimitiveDateTime,
|
||||
/// The end time to filter refunds list or to get list of filters. If not passed the default time is now
|
||||
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
|
||||
pub end_time: Option<PrimitiveDateTime>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)]
|
||||
@ -165,9 +164,31 @@ pub struct RefundListResponse {
|
||||
pub data: Vec<RefundResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, ToSchema)]
|
||||
pub struct RefundListMetaData {
|
||||
/// The list of available connector filters
|
||||
pub connector: Vec<String>,
|
||||
/// The list of available currency filters
|
||||
#[schema(value_type = Vec<Currency>)]
|
||||
pub currency: Vec<enums::Currency>,
|
||||
/// The list of available refund status filters
|
||||
#[schema(value_type = Vec<RefundStatus>)]
|
||||
pub status: Vec<enums::RefundStatus>,
|
||||
}
|
||||
|
||||
/// The status for refunds
|
||||
#[derive(
|
||||
Debug, Eq, Clone, Copy, PartialEq, Default, Deserialize, Serialize, ToSchema, strum::Display,
|
||||
Debug,
|
||||
Eq,
|
||||
Clone,
|
||||
Copy,
|
||||
PartialEq,
|
||||
Default,
|
||||
Deserialize,
|
||||
Serialize,
|
||||
ToSchema,
|
||||
strum::Display,
|
||||
strum::EnumIter,
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum RefundStatus {
|
||||
|
||||
@ -24,6 +24,7 @@ use crate::{
|
||||
},
|
||||
utils::{self, OptionExt},
|
||||
};
|
||||
|
||||
// ********************************************** REFUND EXECUTE **********************************************
|
||||
|
||||
#[instrument(skip_all)]
|
||||
@ -646,20 +647,24 @@ pub async fn refund_list(
|
||||
req: api_models::refunds::RefundListRequest,
|
||||
) -> RouterResponse<api_models::refunds::RefundListResponse> {
|
||||
let limit = validator::validate_refund_list(req.limit)?;
|
||||
let offset = req.offset.unwrap_or_default();
|
||||
|
||||
let refund_list = db
|
||||
.filter_refund_by_constraints(
|
||||
&merchant_account.merchant_id,
|
||||
&req,
|
||||
merchant_account.storage_scheme,
|
||||
limit,
|
||||
offset,
|
||||
)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::RefundNotFound)?;
|
||||
.to_not_found_response(errors::ApiErrorResponse::RefundNotFound)?;
|
||||
|
||||
let data: Vec<refunds::RefundResponse> = refund_list
|
||||
.into_iter()
|
||||
.map(ForeignInto::foreign_into)
|
||||
.collect();
|
||||
|
||||
Ok(services::ApplicationResponse::Json(
|
||||
api_models::refunds::RefundListResponse {
|
||||
size: data.len(),
|
||||
@ -668,6 +673,25 @@ pub async fn refund_list(
|
||||
))
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
#[cfg(feature = "olap")]
|
||||
pub async fn refund_filter_list(
|
||||
db: &dyn db::StorageInterface,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
req: api_models::refunds::TimeRange,
|
||||
) -> RouterResponse<api_models::refunds::RefundListMetaData> {
|
||||
let filter_list = db
|
||||
.filter_refund_by_meta_constraints(
|
||||
&merchant_account.merchant_id,
|
||||
&req,
|
||||
merchant_account.storage_scheme,
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::RefundNotFound)?;
|
||||
|
||||
Ok(services::ApplicationResponse::Json(filter_list))
|
||||
}
|
||||
|
||||
impl ForeignFrom<storage::Refund> for api::RefundResponse {
|
||||
fn foreign_from(refund: storage::Refund) -> Self {
|
||||
let refund = refund;
|
||||
|
||||
@ -10,6 +10,11 @@ use crate::{
|
||||
utils::{self, OptionExt},
|
||||
};
|
||||
|
||||
// Limit constraints for refunds list flow
|
||||
pub const LOWER_LIMIT: i64 = 1;
|
||||
pub const UPPER_LIMIT: i64 = 100;
|
||||
pub const DEFAULT_LIMIT: i64 = 10;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum RefundValidationError {
|
||||
#[error("The payment attempt was not successful")]
|
||||
@ -125,7 +130,7 @@ pub async fn validate_uniqueness_of_refund_id_against_merchant_id(
|
||||
pub fn validate_refund_list(limit: Option<i64>) -> CustomResult<i64, errors::ApiErrorResponse> {
|
||||
match limit {
|
||||
Some(limit_val) => {
|
||||
if !(1..=100).contains(&limit_val) {
|
||||
if !(LOWER_LIMIT..=UPPER_LIMIT).contains(&limit_val) {
|
||||
Err(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: "limit should be in between 1 and 100".to_string(),
|
||||
}
|
||||
@ -134,7 +139,7 @@ pub fn validate_refund_list(limit: Option<i64>) -> CustomResult<i64, errors::Api
|
||||
Ok(limit_val)
|
||||
}
|
||||
}
|
||||
None => Ok(10),
|
||||
None => Ok(DEFAULT_LIMIT),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,19 @@
|
||||
#[cfg(feature = "olap")]
|
||||
use std::collections::HashSet;
|
||||
|
||||
use storage_models::{errors::DatabaseError, refund::RefundUpdateInternal};
|
||||
|
||||
use super::MockDb;
|
||||
#[cfg(feature = "olap")]
|
||||
use crate::types::transformers::ForeignInto;
|
||||
use crate::{
|
||||
core::errors::{self, CustomResult},
|
||||
types::storage::{self as storage_types, enums},
|
||||
};
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
const MAX_LIMIT: usize = 100;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait RefundInterface {
|
||||
async fn find_refund_by_internal_reference_id_merchant_id(
|
||||
@ -64,7 +72,16 @@ pub trait RefundInterface {
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
limit: i64,
|
||||
offset: i64,
|
||||
) -> CustomResult<Vec<storage_models::refund::Refund>, errors::StorageError>;
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
async fn filter_refund_by_meta_constraints(
|
||||
&self,
|
||||
merchant_id: &str,
|
||||
refund_details: &api_models::refunds::TimeRange,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
) -> CustomResult<api_models::refunds::RefundListMetaData, errors::StorageError>;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "kv_store"))]
|
||||
@ -189,6 +206,7 @@ mod storage {
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
_storage_scheme: enums::MerchantStorageScheme,
|
||||
limit: i64,
|
||||
offset: i64,
|
||||
) -> CustomResult<Vec<storage_models::refund::Refund>, errors::StorageError> {
|
||||
let conn = connection::pg_connection_read(self).await?;
|
||||
<storage_models::refund::Refund as storage_types::RefundDbExt>::filter_by_constraints(
|
||||
@ -196,6 +214,25 @@ mod storage {
|
||||
merchant_id,
|
||||
refund_details,
|
||||
limit,
|
||||
offset,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
}
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
async fn filter_refund_by_meta_constraints(
|
||||
&self,
|
||||
merchant_id: &str,
|
||||
refund_details: &api_models::refunds::TimeRange,
|
||||
_storage_scheme: enums::MerchantStorageScheme,
|
||||
) -> CustomResult<api_models::refunds::RefundListMetaData, errors::StorageError> {
|
||||
let conn = connection::pg_connection_read(self).await?;
|
||||
<storage_models::refund::Refund as storage_types::RefundDbExt>::filter_by_meta_constraints(
|
||||
&conn,
|
||||
merchant_id,
|
||||
refund_details,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
@ -584,11 +621,32 @@ mod storage {
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
limit: i64,
|
||||
offset: i64,
|
||||
) -> CustomResult<Vec<storage_models::refund::Refund>, errors::StorageError> {
|
||||
match storage_scheme {
|
||||
enums::MerchantStorageScheme::PostgresOnly => {
|
||||
let conn = connection::pg_connection_read(self).await?;
|
||||
<storage_models::refund::Refund as storage_types::RefundDbExt>::filter_by_constraints(&conn, merchant_id, refund_details, limit)
|
||||
<storage_models::refund::Refund as storage_types::RefundDbExt>::filter_by_constraints(&conn, merchant_id, refund_details, limit, offset)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
}
|
||||
|
||||
enums::MerchantStorageScheme::RedisKv => Err(errors::StorageError::KVError.into()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
async fn filter_refund_by_meta_constraints(
|
||||
&self,
|
||||
merchant_id: &str,
|
||||
refund_details: &api_models::refunds::TimeRange,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
) -> CustomResult<api_models::refunds::RefundListMetaData, errors::StorageError> {
|
||||
match storage_scheme {
|
||||
enums::MerchantStorageScheme::PostgresOnly => {
|
||||
let conn = connection::pg_connection_read(self).await?;
|
||||
<storage_models::refund::Refund as storage_types::RefundDbExt>::filter_by_meta_constraints(&conn, merchant_id, refund_details)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
@ -760,14 +818,64 @@ impl RefundInterface for MockDb {
|
||||
_refund_details: &api_models::refunds::RefundListRequest,
|
||||
_storage_scheme: enums::MerchantStorageScheme,
|
||||
limit: i64,
|
||||
offset: i64,
|
||||
) -> CustomResult<Vec<storage_models::refund::Refund>, errors::StorageError> {
|
||||
let refunds = self.refunds.lock().await;
|
||||
|
||||
Ok(refunds
|
||||
Ok(self
|
||||
.refunds
|
||||
.lock()
|
||||
.await
|
||||
.iter()
|
||||
.filter(|refund| refund.merchant_id == merchant_id)
|
||||
.take(usize::try_from(limit).unwrap_or(usize::MAX))
|
||||
.skip(usize::try_from(offset).unwrap_or_default())
|
||||
.take(usize::try_from(limit).unwrap_or(MAX_LIMIT))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
async fn filter_refund_by_meta_constraints(
|
||||
&self,
|
||||
_merchant_id: &str,
|
||||
refund_details: &api_models::refunds::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<storage_models::refund::Refund>>();
|
||||
|
||||
let mut refund_meta_data = api_models::refunds::RefundListMetaData {
|
||||
connector: vec![],
|
||||
currency: vec![],
|
||||
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.foreign_into();
|
||||
unique_currencies.insert(currency);
|
||||
|
||||
let status: api_models::enums::RefundStatus = refund.refund_status.foreign_into();
|
||||
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.status = unique_statuses.into_iter().collect();
|
||||
|
||||
Ok(refund_meta_data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,6 +245,7 @@ Never share your secret api keys. Keep them guarded and secure.
|
||||
api_models::payments::RedirectResponse,
|
||||
api_models::refunds::RefundListRequest,
|
||||
api_models::refunds::RefundListResponse,
|
||||
api_models::refunds::TimeRange,
|
||||
api_models::mandates::MandateRevokedResponse,
|
||||
api_models::mandates::MandateResponse,
|
||||
api_models::mandates::MandateCardDetails,
|
||||
|
||||
@ -243,7 +243,9 @@ impl Refunds {
|
||||
|
||||
#[cfg(feature = "olap")]
|
||||
{
|
||||
route = route.service(web::resource("/list").route(web::get().to(refunds_list)));
|
||||
route = route
|
||||
.service(web::resource("/list").route(web::post().to(refunds_list)))
|
||||
.service(web::resource("/filter").route(web::post().to(refunds_filter_list)));
|
||||
}
|
||||
#[cfg(feature = "oltp")]
|
||||
{
|
||||
|
||||
@ -179,17 +179,9 @@ pub async fn refunds_update(
|
||||
///
|
||||
/// To list the refunds associated with a payment_id or with the merchant, if payment_id is not provided
|
||||
#[utoipa::path(
|
||||
get,
|
||||
post,
|
||||
path = "/refunds/list",
|
||||
params(
|
||||
("payment_id" = String, Query, description = "The identifier for the payment"),
|
||||
("limit" = i64, Query, description = "Limit on the number of objects to return"),
|
||||
("created" = PrimitiveDateTime, Query, description = "The time at which refund is created"),
|
||||
("created_lt" = PrimitiveDateTime, Query, description = "Time less than the refund created time"),
|
||||
("created_gt" = PrimitiveDateTime, Query, description = "Time greater than the refund created time"),
|
||||
("created_lte" = PrimitiveDateTime, Query, description = "Time less than or equals to the refund created time"),
|
||||
("created_gte" = PrimitiveDateTime, Query, description = "Time greater than or equals to the refund created time")
|
||||
),
|
||||
request_body=RefundListRequest,
|
||||
responses(
|
||||
(status = 200, description = "List of refunds", body = RefundListResponse),
|
||||
),
|
||||
@ -199,11 +191,10 @@ pub async fn refunds_update(
|
||||
)]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::RefundsList))]
|
||||
#[cfg(feature = "olap")]
|
||||
// #[get("/list")]
|
||||
pub async fn refunds_list(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
payload: web::Query<api_models::refunds::RefundListRequest>,
|
||||
payload: web::Json<api_models::refunds::RefundListRequest>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::RefundsList;
|
||||
api::server_wrap(
|
||||
@ -216,3 +207,36 @@ pub async fn refunds_list(
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Refunds - Filter
|
||||
///
|
||||
/// To list the refunds filters associated with list of connectors, currencies and payment statuses
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/refunds/filter",
|
||||
request_body=TimeRange,
|
||||
responses(
|
||||
(status = 200, description = "List of filters", body = RefundListMetaData),
|
||||
),
|
||||
tag = "Refunds",
|
||||
operation_id = "List all filters for Refunds",
|
||||
security(("api_key" = []))
|
||||
)]
|
||||
#[instrument(skip_all, fields(flow = ?Flow::RefundsList))]
|
||||
#[cfg(feature = "olap")]
|
||||
pub async fn refunds_filter_list(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
payload: web::Json<api_models::refunds::TimeRange>,
|
||||
) -> HttpResponse {
|
||||
let flow = Flow::RefundsList;
|
||||
api::server_wrap(
|
||||
flow,
|
||||
state.get_ref(),
|
||||
&req,
|
||||
payload.into_inner(),
|
||||
|state, auth, req| refund_filter_list(&*state.store, auth.merchant_account, req),
|
||||
&auth::ApiKeyAuth,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -5,9 +5,13 @@ use error_stack::{IntoReport, ResultExt};
|
||||
pub use storage_models::refund::{
|
||||
Refund, RefundCoreWorkflow, RefundNew, RefundUpdate, RefundUpdateInternal,
|
||||
};
|
||||
use storage_models::{errors, schema::refund::dsl};
|
||||
use storage_models::{
|
||||
enums::{Currency, RefundStatus},
|
||||
errors,
|
||||
schema::refund::dsl,
|
||||
};
|
||||
|
||||
use crate::{connection::PgPooledConn, logger};
|
||||
use crate::{connection::PgPooledConn, logger, types::transformers::ForeignInto};
|
||||
|
||||
#[cfg(feature = "kv_store")]
|
||||
impl crate::utils::storage_partitioning::KvStorePartition for Refund {}
|
||||
@ -19,7 +23,14 @@ pub trait RefundDbExt: Sized {
|
||||
merchant_id: &str,
|
||||
refund_list_details: &api_models::refunds::RefundListRequest,
|
||||
limit: i64,
|
||||
offset: i64,
|
||||
) -> CustomResult<Vec<Self>, errors::DatabaseError>;
|
||||
|
||||
async fn filter_by_meta_constraints(
|
||||
conn: &PgPooledConn,
|
||||
merchant_id: &str,
|
||||
refund_list_details: &api_models::refunds::TimeRange,
|
||||
) -> CustomResult<api_models::refunds::RefundListMetaData, errors::DatabaseError>;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@ -29,6 +40,7 @@ impl RefundDbExt for Refund {
|
||||
merchant_id: &str,
|
||||
refund_list_details: &api_models::refunds::RefundListRequest,
|
||||
limit: i64,
|
||||
offset: i64,
|
||||
) -> CustomResult<Vec<Self>, errors::DatabaseError> {
|
||||
let mut filter = <Self as HasTable>::table()
|
||||
.filter(dsl::merchant_id.eq(merchant_id.to_owned()))
|
||||
@ -40,24 +52,36 @@ impl RefundDbExt for Refund {
|
||||
filter = filter.filter(dsl::payment_id.eq(pid.to_owned()));
|
||||
}
|
||||
None => {
|
||||
filter = filter.limit(limit);
|
||||
filter = filter.limit(limit).offset(offset);
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(created) = refund_list_details.created {
|
||||
filter = filter.filter(dsl::created_at.eq(created));
|
||||
if let Some(time_range) = refund_list_details.time_range {
|
||||
filter = filter.filter(dsl::created_at.ge(time_range.start_time));
|
||||
|
||||
if let Some(end_time) = time_range.end_time {
|
||||
filter = filter.filter(dsl::created_at.le(end_time));
|
||||
}
|
||||
}
|
||||
if let Some(created_lt) = refund_list_details.created_lt {
|
||||
filter = filter.filter(dsl::created_at.lt(created_lt));
|
||||
|
||||
if let Some(connector) = refund_list_details.clone().connector {
|
||||
filter = filter.filter(dsl::connector.eq_any(connector));
|
||||
}
|
||||
if let Some(created_gt) = refund_list_details.created_gt {
|
||||
filter = filter.filter(dsl::created_at.gt(created_gt));
|
||||
|
||||
if let Some(filter_currency) = &refund_list_details.currency {
|
||||
let currency: Vec<Currency> = filter_currency
|
||||
.iter()
|
||||
.map(|currency| (*currency).foreign_into())
|
||||
.collect();
|
||||
filter = filter.filter(dsl::currency.eq_any(currency));
|
||||
}
|
||||
if let Some(created_lte) = refund_list_details.created_lte {
|
||||
filter = filter.filter(dsl::created_at.le(created_lte));
|
||||
}
|
||||
if let Some(created_gte) = refund_list_details.created_gte {
|
||||
filter = filter.filter(dsl::created_at.gt(created_gte));
|
||||
|
||||
if let Some(filter_refund_status) = &refund_list_details.refund_status {
|
||||
let refund_status: Vec<RefundStatus> = filter_refund_status
|
||||
.iter()
|
||||
.map(|refund_status| (*refund_status).foreign_into())
|
||||
.collect();
|
||||
filter = filter.filter(dsl::refund_status.eq_any(refund_status));
|
||||
}
|
||||
|
||||
logger::debug!(query = %diesel::debug_query::<diesel::pg::Pg, _>(&filter).to_string());
|
||||
@ -69,4 +93,68 @@ impl RefundDbExt for Refund {
|
||||
.change_context(errors::DatabaseError::NotFound)
|
||||
.attach_printable_lazy(|| "Error filtering records by predicate")
|
||||
}
|
||||
|
||||
async fn filter_by_meta_constraints(
|
||||
conn: &PgPooledConn,
|
||||
merchant_id: &str,
|
||||
refund_list_details: &api_models::refunds::TimeRange,
|
||||
) -> CustomResult<api_models::refunds::RefundListMetaData, errors::DatabaseError> {
|
||||
let start_time = refund_list_details.start_time;
|
||||
|
||||
let end_time = refund_list_details
|
||||
.end_time
|
||||
.unwrap_or_else(common_utils::date_time::now);
|
||||
|
||||
let filter = <Self as HasTable>::table()
|
||||
.filter(dsl::merchant_id.eq(merchant_id.to_owned()))
|
||||
.order(dsl::modified_at.desc())
|
||||
.filter(dsl::created_at.ge(start_time))
|
||||
.filter(dsl::created_at.le(end_time));
|
||||
|
||||
let filter_connector: Vec<String> = filter
|
||||
.clone()
|
||||
.select(dsl::connector)
|
||||
.distinct()
|
||||
.order_by(dsl::connector.asc())
|
||||
.get_results_async(conn)
|
||||
.await
|
||||
.into_report()
|
||||
.change_context(errors::DatabaseError::Others)
|
||||
.attach_printable("Error filtering records by connector")?;
|
||||
|
||||
let filter_currency: Vec<Currency> = filter
|
||||
.clone()
|
||||
.select(dsl::currency)
|
||||
.distinct()
|
||||
.order_by(dsl::currency.asc())
|
||||
.get_results_async(conn)
|
||||
.await
|
||||
.into_report()
|
||||
.change_context(errors::DatabaseError::Others)
|
||||
.attach_printable("Error filtering records by currency")?;
|
||||
|
||||
let filter_status: Vec<RefundStatus> = filter
|
||||
.select(dsl::refund_status)
|
||||
.distinct()
|
||||
.order_by(dsl::refund_status.asc())
|
||||
.get_results_async(conn)
|
||||
.await
|
||||
.into_report()
|
||||
.change_context(errors::DatabaseError::Others)
|
||||
.attach_printable("Error filtering records by refund status")?;
|
||||
|
||||
let meta = api_models::refunds::RefundListMetaData {
|
||||
connector: filter_connector,
|
||||
currency: filter_currency
|
||||
.into_iter()
|
||||
.map(|curr| curr.foreign_into())
|
||||
.collect(),
|
||||
status: filter_status
|
||||
.into_iter()
|
||||
.map(|curr| curr.foreign_into())
|
||||
.collect(),
|
||||
};
|
||||
|
||||
Ok(meta)
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,6 +298,12 @@ impl ForeignFrom<storage_enums::RefundStatus> for api_enums::RefundStatus {
|
||||
}
|
||||
}
|
||||
|
||||
impl ForeignFrom<api_enums::RefundStatus> for storage_enums::RefundStatus {
|
||||
fn foreign_from(status: api_enums::RefundStatus) -> Self {
|
||||
frunk::labelled_convert_from(status)
|
||||
}
|
||||
}
|
||||
|
||||
impl ForeignFrom<api_enums::CaptureMethod> for storage_enums::CaptureMethod {
|
||||
fn foreign_from(capture_method: api_enums::CaptureMethod) -> Self {
|
||||
frunk::labelled_convert_from(capture_method)
|
||||
|
||||
Reference in New Issue
Block a user