mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 11:24:45 +08:00
feat: list of refunds (#284)
This commit is contained in:
committed by
GitHub
parent
38649130bb
commit
e5330528fa
@ -455,6 +455,40 @@ pub async fn validate_and_create_refund(
|
||||
Ok(refund.foreign_into())
|
||||
}
|
||||
|
||||
// ********************************************** Refund list **********************************************
|
||||
|
||||
/// If payment-id is provided, lists all the refunds associated with that particular payment-id
|
||||
/// If payment-id is not provided, lists the refunds associated with that particular merchant - to the limit specified,if no limits given, it is 10 by default
|
||||
|
||||
#[instrument(skip_all)]
|
||||
pub async fn refund_list(
|
||||
db: &dyn db::StorageInterface,
|
||||
merchant_account: storage::merchant_account::MerchantAccount,
|
||||
req: api_models::refunds::RefundListRequest,
|
||||
) -> RouterResponse<api_models::refunds::RefundListResponse> {
|
||||
let limit = validator::validate_refund_list(req.limit)?;
|
||||
let refund_list = db
|
||||
.filter_refund_by_constraints(
|
||||
&merchant_account.merchant_id,
|
||||
&req,
|
||||
merchant_account.storage_scheme,
|
||||
limit,
|
||||
)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::RefundNotFound)?;
|
||||
|
||||
let data: Vec<refunds::RefundResponse> = refund_list
|
||||
.into_iter()
|
||||
.map(ForeignInto::foreign_into)
|
||||
.collect();
|
||||
utils::when(data.is_empty(), || {
|
||||
Err(errors::ApiErrorResponse::RefundNotFound)
|
||||
})?;
|
||||
Ok(services::BachResponse::Json(
|
||||
api_models::refunds::RefundListResponse { data },
|
||||
))
|
||||
}
|
||||
|
||||
// ********************************************** UTILS **********************************************
|
||||
|
||||
// FIXME: function should not have more than 3 arguments.
|
||||
|
||||
@ -122,3 +122,19 @@ 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) {
|
||||
Err(errors::ApiErrorResponse::InvalidRequestData {
|
||||
message: "limit should be in between 1 and 100".to_string(),
|
||||
}
|
||||
.into())
|
||||
} else {
|
||||
Ok(limit_val)
|
||||
}
|
||||
}
|
||||
None => Ok(10),
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,6 +55,14 @@ pub trait RefundInterface {
|
||||
new: storage_types::RefundNew,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
) -> CustomResult<storage_types::Refund, errors::StorageError>;
|
||||
|
||||
async fn filter_refund_by_constraints(
|
||||
&self,
|
||||
merchant_id: &str,
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
limit: i64,
|
||||
) -> CustomResult<Vec<storage_models::refund::Refund>, errors::StorageError>;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "kv_store"))]
|
||||
@ -163,6 +171,25 @@ mod storage {
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
}
|
||||
|
||||
async fn filter_refund_by_constraints(
|
||||
&self,
|
||||
merchant_id: &str,
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
_storage_scheme: enums::MerchantStorageScheme,
|
||||
limit: i64,
|
||||
) -> CustomResult<Vec<storage_models::refund::Refund>, errors::StorageError> {
|
||||
let conn = pg_connection(&self.master_pool).await;
|
||||
<storage_models::refund::Refund as storage_types::RefundDbExt>::filter_by_constraints(
|
||||
&conn,
|
||||
merchant_id,
|
||||
refund_details,
|
||||
limit,
|
||||
)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -546,6 +573,26 @@ mod storage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn filter_refund_by_constraints(
|
||||
&self,
|
||||
merchant_id: &str,
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
limit: i64,
|
||||
) -> CustomResult<Vec<storage_models::refund::Refund>, errors::StorageError> {
|
||||
match storage_scheme {
|
||||
enums::MerchantStorageScheme::PostgresOnly => {
|
||||
let conn = pg_connection(&self.master_pool).await;
|
||||
<storage_models::refund::Refund as storage_types::RefundDbExt>::filter_by_constraints(&conn, merchant_id, refund_details, limit)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.into_report()
|
||||
}
|
||||
|
||||
enums::MerchantStorageScheme::RedisKv => Err(errors::StorageError::KVError.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -651,4 +698,15 @@ impl RefundInterface for MockDb {
|
||||
// [#172]: Implement function for `MockDb`
|
||||
Err(errors::StorageError::MockDbError)?
|
||||
}
|
||||
|
||||
async fn filter_refund_by_constraints(
|
||||
&self,
|
||||
_merchant_id: &str,
|
||||
_refund_details: &api_models::refunds::RefundListRequest,
|
||||
_storage_scheme: enums::MerchantStorageScheme,
|
||||
_limit: i64,
|
||||
) -> CustomResult<Vec<storage_models::refund::Refund>, errors::StorageError> {
|
||||
// [#172]: Implement function for `MockDb`
|
||||
Err(errors::StorageError::MockDbError)?
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,12 +113,12 @@ impl Refunds {
|
||||
web::scope("/refunds")
|
||||
.app_data(web::Data::new(state))
|
||||
.service(web::resource("").route(web::post().to(refunds_create)))
|
||||
.service(web::resource("/list").route(web::get().to(refunds_list)))
|
||||
.service(
|
||||
web::resource("/{id}")
|
||||
.route(web::get().to(refunds_retrieve))
|
||||
.route(web::post().to(refunds_update)),
|
||||
)
|
||||
.service(web::resource("/list").route(web::get().to(refunds_list)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -68,6 +68,17 @@ pub async fn refunds_update(
|
||||
|
||||
#[instrument(skip_all, fields(flow = ?Flow::RefundsList))]
|
||||
// #[get("/list")]
|
||||
pub async fn refunds_list() -> HttpResponse {
|
||||
api::http_response_json("list")
|
||||
pub async fn refunds_list(
|
||||
state: web::Data<AppState>,
|
||||
req: HttpRequest,
|
||||
payload: web::Query<api_models::refunds::RefundListRequest>,
|
||||
) -> HttpResponse {
|
||||
api::server_wrap(
|
||||
&state,
|
||||
&req,
|
||||
payload.into_inner(),
|
||||
|state, merchant_account, req| refund_list(&*state.store, merchant_account, req),
|
||||
api::MerchantAuthentication::ApiKey,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@ -1,6 +1,72 @@
|
||||
use async_bb8_diesel::AsyncRunQueryDsl;
|
||||
use common_utils::errors::CustomResult;
|
||||
use diesel::{associations::HasTable, ExpressionMethods, QueryDsl};
|
||||
use error_stack::{IntoReport, ResultExt};
|
||||
pub use storage_models::refund::{
|
||||
Refund, RefundCoreWorkflow, RefundNew, RefundUpdate, RefundUpdateInternal,
|
||||
};
|
||||
use storage_models::{errors, schema::refund::dsl};
|
||||
|
||||
use crate::{connection::PgPooledConn, logger};
|
||||
|
||||
#[cfg(feature = "kv_store")]
|
||||
impl crate::utils::storage_partitioning::KvStorePartition for Refund {}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait RefundDbExt: Sized {
|
||||
async fn filter_by_constraints(
|
||||
conn: &PgPooledConn,
|
||||
merchant_id: &str,
|
||||
refund_list_details: &api_models::refunds::RefundListRequest,
|
||||
limit: i64,
|
||||
) -> CustomResult<Vec<Self>, errors::DatabaseError>;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl RefundDbExt for Refund {
|
||||
async fn filter_by_constraints(
|
||||
conn: &PgPooledConn,
|
||||
merchant_id: &str,
|
||||
refund_list_details: &api_models::refunds::RefundListRequest,
|
||||
limit: i64,
|
||||
) -> CustomResult<Vec<Self>, errors::DatabaseError> {
|
||||
let mut filter = <Self as HasTable>::table()
|
||||
.filter(dsl::merchant_id.eq(merchant_id.to_owned()))
|
||||
.order_by(dsl::id)
|
||||
.into_boxed();
|
||||
|
||||
match &refund_list_details.payment_id {
|
||||
Some(pid) => {
|
||||
filter = filter.filter(dsl::payment_id.eq(pid.to_owned()));
|
||||
}
|
||||
None => {
|
||||
filter = filter.limit(limit);
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(created) = refund_list_details.created {
|
||||
filter = filter.filter(dsl::created_at.eq(created));
|
||||
}
|
||||
if let Some(created_lt) = refund_list_details.created_lt {
|
||||
filter = filter.filter(dsl::created_at.lt(created_lt));
|
||||
}
|
||||
if let Some(created_gt) = refund_list_details.created_gt {
|
||||
filter = filter.filter(dsl::created_at.gt(created_gt));
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
logger::debug!(query = %diesel::debug_query::<diesel::pg::Pg, _>(&filter).to_string());
|
||||
|
||||
filter
|
||||
.get_results_async(conn)
|
||||
.await
|
||||
.into_report()
|
||||
.change_context(errors::DatabaseError::NotFound)
|
||||
.attach_printable_lazy(|| "Error filtering records by predicate")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user