mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 12:06:56 +08:00
feat: enable payment and refund filter at DB query level (#5827)
This commit is contained in:
@ -2940,15 +2940,13 @@ pub async fn list_payments(
|
||||
let db = state.store.as_ref();
|
||||
let payment_intents = helpers::filter_by_constraints(
|
||||
&state,
|
||||
&constraints,
|
||||
&(constraints, profile_id_list).try_into()?,
|
||||
merchant_id,
|
||||
&key_store,
|
||||
merchant.storage_scheme,
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
|
||||
let payment_intents =
|
||||
utils::filter_objects_based_on_profile_id_list(profile_id_list, payment_intents);
|
||||
|
||||
let collected_futures = payment_intents.into_iter().map(|pi| {
|
||||
async {
|
||||
@ -3011,25 +3009,25 @@ pub async fn apply_filters_on_payments(
|
||||
) -> RouterResponse<api::PaymentListResponseV2> {
|
||||
let limit = &constraints.limit;
|
||||
helpers::validate_payment_list_request_for_joins(*limit)?;
|
||||
let db = state.store.as_ref();
|
||||
let db: &dyn StorageInterface = state.store.as_ref();
|
||||
let pi_fetch_constraints = (constraints.clone(), profile_id_list.clone()).try_into()?;
|
||||
let list: Vec<(storage::PaymentIntent, storage::PaymentAttempt)> = db
|
||||
.get_filtered_payment_intents_attempt(
|
||||
&(&state).into(),
|
||||
merchant.get_id(),
|
||||
&constraints.clone().into(),
|
||||
&pi_fetch_constraints,
|
||||
&merchant_key_store,
|
||||
merchant.storage_scheme,
|
||||
)
|
||||
.await
|
||||
.to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
|
||||
let list = utils::filter_objects_based_on_profile_id_list(profile_id_list, list);
|
||||
let data: Vec<api::PaymentsResponse> =
|
||||
list.into_iter().map(ForeignFrom::foreign_from).collect();
|
||||
|
||||
let active_attempt_ids = db
|
||||
.get_filtered_active_attempt_ids_for_total_count(
|
||||
merchant.get_id(),
|
||||
&constraints.clone().into(),
|
||||
&pi_fetch_constraints,
|
||||
merchant.storage_scheme,
|
||||
)
|
||||
.await
|
||||
@ -3044,6 +3042,7 @@ pub async fn apply_filters_on_payments(
|
||||
constraints.payment_method_type,
|
||||
constraints.authentication_type,
|
||||
constraints.merchant_connector_id,
|
||||
pi_fetch_constraints.get_profile_id_list(),
|
||||
merchant.storage_scheme,
|
||||
)
|
||||
.await
|
||||
|
||||
@ -26,7 +26,10 @@ use hyperswitch_domain_models::payments::payment_intent::CustomerData;
|
||||
use hyperswitch_domain_models::{
|
||||
mandates::MandateData,
|
||||
payment_method_data::GetPaymentMethodType,
|
||||
payments::{payment_attempt::PaymentAttempt, PaymentIntent},
|
||||
payments::{
|
||||
payment_attempt::PaymentAttempt, payment_intent::PaymentIntentFetchConstraints,
|
||||
PaymentIntent,
|
||||
},
|
||||
router_data::KlarnaSdkResponse,
|
||||
};
|
||||
use hyperswitch_interfaces::integrity::{CheckIntegrity, FlowIntegrity, GetIntegrityObject};
|
||||
@ -2538,7 +2541,7 @@ where
|
||||
#[cfg(feature = "olap")]
|
||||
pub(super) async fn filter_by_constraints(
|
||||
state: &SessionState,
|
||||
constraints: &api::PaymentListConstraints,
|
||||
constraints: &PaymentIntentFetchConstraints,
|
||||
merchant_id: &id_type::MerchantId,
|
||||
key_store: &domain::MerchantKeyStore,
|
||||
storage_scheme: storage_enums::MerchantStorageScheme,
|
||||
@ -2548,7 +2551,7 @@ pub(super) async fn filter_by_constraints(
|
||||
.filter_payment_intent_by_constraints(
|
||||
&(state).into(),
|
||||
merchant_id,
|
||||
&constraints.clone().into(),
|
||||
constraints,
|
||||
key_store,
|
||||
storage_scheme,
|
||||
)
|
||||
|
||||
@ -869,7 +869,7 @@ pub async fn validate_and_create_refund(
|
||||
pub async fn refund_list(
|
||||
state: SessionState,
|
||||
merchant_account: domain::MerchantAccount,
|
||||
_profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
|
||||
profile_id_list: Option<Vec<common_utils::id_type::ProfileId>>,
|
||||
req: api_models::refunds::RefundListRequest,
|
||||
) -> RouterResponse<api_models::refunds::RefundListResponse> {
|
||||
let db = state.store;
|
||||
@ -879,7 +879,7 @@ pub async fn refund_list(
|
||||
let refund_list = db
|
||||
.filter_refund_by_constraints(
|
||||
merchant_account.get_id(),
|
||||
&req,
|
||||
&(req.clone(), profile_id_list.clone()).try_into()?,
|
||||
merchant_account.storage_scheme,
|
||||
limit,
|
||||
offset,
|
||||
@ -895,7 +895,7 @@ pub async fn refund_list(
|
||||
let total_count = db
|
||||
.get_total_count_of_refunds(
|
||||
merchant_account.get_id(),
|
||||
&req,
|
||||
&(req, profile_id_list).try_into()?,
|
||||
merchant_account.storage_scheme,
|
||||
)
|
||||
.await
|
||||
|
||||
@ -9,13 +9,14 @@ use diesel_models::{
|
||||
reverse_lookup::{ReverseLookup, ReverseLookupNew},
|
||||
user_role as user_storage,
|
||||
};
|
||||
use hyperswitch_domain_models::payments::{
|
||||
payment_attempt::PaymentAttemptInterface, payment_intent::PaymentIntentInterface,
|
||||
};
|
||||
#[cfg(feature = "payouts")]
|
||||
use hyperswitch_domain_models::payouts::{
|
||||
payout_attempt::PayoutAttemptInterface, payouts::PayoutsInterface,
|
||||
};
|
||||
use hyperswitch_domain_models::{
|
||||
payments::{payment_attempt::PaymentAttemptInterface, payment_intent::PaymentIntentInterface},
|
||||
refunds,
|
||||
};
|
||||
#[cfg(not(feature = "payouts"))]
|
||||
use hyperswitch_domain_models::{PayoutAttemptInterface, PayoutsInterface};
|
||||
use masking::Secret;
|
||||
@ -1490,6 +1491,7 @@ impl PaymentAttemptInterface for KafkaStore {
|
||||
payment_method_type: Option<Vec<common_enums::PaymentMethodType>>,
|
||||
authentication_type: Option<Vec<common_enums::AuthenticationType>>,
|
||||
merchant_connector_id: Option<Vec<id_type::MerchantConnectorAccountId>>,
|
||||
profile_id_list: Option<Vec<id_type::ProfileId>>,
|
||||
storage_scheme: MerchantStorageScheme,
|
||||
) -> CustomResult<i64, errors::DataStorageError> {
|
||||
self.diesel_store
|
||||
@ -1501,6 +1503,7 @@ impl PaymentAttemptInterface for KafkaStore {
|
||||
payment_method_type,
|
||||
authentication_type,
|
||||
merchant_connector_id,
|
||||
profile_id_list,
|
||||
storage_scheme,
|
||||
)
|
||||
.await
|
||||
@ -2361,7 +2364,7 @@ impl RefundInterface for KafkaStore {
|
||||
async fn filter_refund_by_constraints(
|
||||
&self,
|
||||
merchant_id: &id_type::MerchantId,
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
refund_details: &refunds::RefundListConstraints,
|
||||
storage_scheme: MerchantStorageScheme,
|
||||
limit: i64,
|
||||
offset: i64,
|
||||
@ -2393,7 +2396,7 @@ impl RefundInterface for KafkaStore {
|
||||
async fn get_total_count_of_refunds(
|
||||
&self,
|
||||
merchant_id: &id_type::MerchantId,
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
refund_details: &refunds::RefundListConstraints,
|
||||
storage_scheme: MerchantStorageScheme,
|
||||
) -> CustomResult<i64, errors::StorageError> {
|
||||
self.diesel_store
|
||||
|
||||
@ -4,6 +4,7 @@ use std::collections::HashSet;
|
||||
#[cfg(feature = "olap")]
|
||||
use common_utils::types::MinorUnit;
|
||||
use diesel_models::{errors::DatabaseError, refund::RefundUpdateInternal};
|
||||
use hyperswitch_domain_models::refunds;
|
||||
|
||||
use super::MockDb;
|
||||
use crate::{
|
||||
@ -69,7 +70,7 @@ pub trait RefundInterface {
|
||||
async fn filter_refund_by_constraints(
|
||||
&self,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
refund_details: &refunds::RefundListConstraints,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
limit: i64,
|
||||
offset: i64,
|
||||
@ -87,7 +88,7 @@ pub trait RefundInterface {
|
||||
async fn get_total_count_of_refunds(
|
||||
&self,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
refund_details: &refunds::RefundListConstraints,
|
||||
storage_scheme: enums::MerchantStorageScheme,
|
||||
) -> CustomResult<i64, errors::StorageError>;
|
||||
}
|
||||
@ -216,7 +217,7 @@ mod storage {
|
||||
async fn filter_refund_by_constraints(
|
||||
&self,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
refund_details: &refunds::RefundListConstraints,
|
||||
_storage_scheme: enums::MerchantStorageScheme,
|
||||
limit: i64,
|
||||
offset: i64,
|
||||
@ -255,7 +256,7 @@ mod storage {
|
||||
async fn get_total_count_of_refunds(
|
||||
&self,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
refund_details: &refunds::RefundListConstraints,
|
||||
_storage_scheme: enums::MerchantStorageScheme,
|
||||
) -> CustomResult<i64, errors::StorageError> {
|
||||
let conn = connection::pg_connection_read(self).await?;
|
||||
@ -274,6 +275,7 @@ mod storage {
|
||||
mod storage {
|
||||
use common_utils::{ext_traits::Encode, fallback_reverse_lookup_not_found};
|
||||
use error_stack::{report, ResultExt};
|
||||
use hyperswitch_domain_models::refunds;
|
||||
use redis_interface::HsetnxReply;
|
||||
use router_env::{instrument, tracing};
|
||||
use storage_impl::redis::kv_store::{
|
||||
@ -752,7 +754,7 @@ mod storage {
|
||||
async fn filter_refund_by_constraints(
|
||||
&self,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
refund_details: &refunds::RefundListConstraints,
|
||||
_storage_scheme: enums::MerchantStorageScheme,
|
||||
limit: i64,
|
||||
offset: i64,
|
||||
@ -788,7 +790,7 @@ mod storage {
|
||||
async fn get_total_count_of_refunds(
|
||||
&self,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
refund_details: &refunds::RefundListConstraints,
|
||||
_storage_scheme: enums::MerchantStorageScheme,
|
||||
) -> CustomResult<i64, errors::StorageError> {
|
||||
let conn = connection::pg_connection_read(self).await?;
|
||||
@ -963,7 +965,7 @@ impl RefundInterface for MockDb {
|
||||
async fn filter_refund_by_constraints(
|
||||
&self,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
refund_details: &refunds::RefundListConstraints,
|
||||
_storage_scheme: enums::MerchantStorageScheme,
|
||||
limit: i64,
|
||||
offset: i64,
|
||||
@ -972,6 +974,7 @@ impl RefundInterface for MockDb {
|
||||
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 {
|
||||
@ -1000,6 +1003,10 @@ impl RefundInterface for MockDb {
|
||||
});
|
||||
}
|
||||
|
||||
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()
|
||||
@ -1016,7 +1023,11 @@ impl RefundInterface for MockDb {
|
||||
.clone()
|
||||
.map_or(true, |id| id == refund.refund_id)
|
||||
})
|
||||
.filter(|refund| refund_details.profile_id == refund.profile_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(
|
||||
@ -1116,13 +1127,14 @@ impl RefundInterface for MockDb {
|
||||
async fn get_total_count_of_refunds(
|
||||
&self,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
refund_details: &api_models::refunds::RefundListRequest,
|
||||
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 {
|
||||
@ -1151,6 +1163,10 @@ impl RefundInterface for MockDb {
|
||||
});
|
||||
}
|
||||
|
||||
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()
|
||||
@ -1167,7 +1183,11 @@ impl RefundInterface for MockDb {
|
||||
.clone()
|
||||
.map_or(true, |id| id == refund.refund_id)
|
||||
})
|
||||
.filter(|refund| refund_details.profile_id == refund.profile_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(
|
||||
|
||||
@ -12,6 +12,7 @@ use diesel_models::{
|
||||
schema::refund::dsl,
|
||||
};
|
||||
use error_stack::ResultExt;
|
||||
use hyperswitch_domain_models::refunds;
|
||||
|
||||
use crate::{connection::PgPooledConn, logger};
|
||||
|
||||
@ -20,7 +21,7 @@ pub trait RefundDbExt: Sized {
|
||||
async fn filter_by_constraints(
|
||||
conn: &PgPooledConn,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
refund_list_details: &api_models::refunds::RefundListRequest,
|
||||
refund_list_details: &refunds::RefundListConstraints,
|
||||
limit: i64,
|
||||
offset: i64,
|
||||
) -> CustomResult<Vec<Self>, errors::DatabaseError>;
|
||||
@ -34,7 +35,7 @@ pub trait RefundDbExt: Sized {
|
||||
async fn get_refunds_count(
|
||||
conn: &PgPooledConn,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
refund_list_details: &api_models::refunds::RefundListRequest,
|
||||
refund_list_details: &refunds::RefundListConstraints,
|
||||
) -> CustomResult<i64, errors::DatabaseError>;
|
||||
}
|
||||
|
||||
@ -43,7 +44,7 @@ impl RefundDbExt for Refund {
|
||||
async fn filter_by_constraints(
|
||||
conn: &PgPooledConn,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
refund_list_details: &api_models::refunds::RefundListRequest,
|
||||
refund_list_details: &refunds::RefundListConstraints,
|
||||
limit: i64,
|
||||
offset: i64,
|
||||
) -> CustomResult<Vec<Self>, errors::DatabaseError> {
|
||||
@ -88,7 +89,7 @@ impl RefundDbExt for Refund {
|
||||
match &refund_list_details.profile_id {
|
||||
Some(profile_id) => {
|
||||
filter = filter
|
||||
.filter(dsl::profile_id.eq(profile_id.to_owned()))
|
||||
.filter(dsl::profile_id.eq_any(profile_id.to_owned()))
|
||||
.limit(limit)
|
||||
.offset(offset);
|
||||
}
|
||||
@ -206,7 +207,7 @@ impl RefundDbExt for Refund {
|
||||
async fn get_refunds_count(
|
||||
conn: &PgPooledConn,
|
||||
merchant_id: &common_utils::id_type::MerchantId,
|
||||
refund_list_details: &api_models::refunds::RefundListRequest,
|
||||
refund_list_details: &refunds::RefundListConstraints,
|
||||
) -> CustomResult<i64, errors::DatabaseError> {
|
||||
let mut filter = <Self as HasTable>::table()
|
||||
.count()
|
||||
@ -237,7 +238,7 @@ impl RefundDbExt for Refund {
|
||||
}
|
||||
}
|
||||
if let Some(profile_id) = &refund_list_details.profile_id {
|
||||
filter = filter.filter(dsl::profile_id.eq(profile_id.to_owned()));
|
||||
filter = filter.filter(dsl::profile_id.eq_any(profile_id.to_owned()));
|
||||
}
|
||||
|
||||
if let Some(time_range) = refund_list_details.time_range {
|
||||
|
||||
Reference in New Issue
Block a user