diff --git a/CHANGELOG.md b/CHANGELOG.md index 79457071a52..993b123b6b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to HyperSwitch will be documented here. - - - +## 2024.09.06.0-hotfix1 + +### Features + +- Enable payment and refund filter at DB query level ([#5839](https://github.com/juspay/hyperswitch/pull/5839)) ([`b75e864`](https://github.com/juspay/hyperswitch/commit/b75e864bdb503d1a86eb729cea7f2b7186de16c3)) + +- - - + ## 2024.09.06.0 ### Features diff --git a/crates/diesel_models/src/query/payment_attempt.rs b/crates/diesel_models/src/query/payment_attempt.rs index d8a9d5f40f4..a9d44bca88f 100644 --- a/crates/diesel_models/src/query/payment_attempt.rs +++ b/crates/diesel_models/src/query/payment_attempt.rs @@ -322,6 +322,7 @@ impl PaymentAttempt { payment_method: Option>, payment_method_type: Option>, authentication_type: Option>, + profile_id_list: Option>, merchant_connector_id: Option>, ) -> StorageResult { let mut filter = ::table() @@ -346,6 +347,9 @@ impl PaymentAttempt { if let Some(merchant_connector_id) = merchant_connector_id { filter = filter.filter(dsl::merchant_connector_id.eq_any(merchant_connector_id)) } + if let Some(profile_id_list) = profile_id_list { + filter = filter.filter(dsl::profile_id.eq_any(profile_id_list)) + } router_env::logger::debug!(query = %debug_query::(&filter).to_string()); db_metrics::track_database_call::<::Table, _, _>( diff --git a/crates/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs index 54920dee6ba..b0a660ad5d3 100644 --- a/crates/hyperswitch_domain_models/src/lib.rs +++ b/crates/hyperswitch_domain_models/src/lib.rs @@ -14,6 +14,7 @@ pub mod payment_methods; pub mod payments; #[cfg(feature = "payouts")] pub mod payouts; +pub mod refunds; pub mod router_data; pub mod router_data_v2; pub mod router_flow_types; diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index 1fc327ef4e4..cd46460e3c9 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -112,6 +112,7 @@ pub trait PaymentAttemptInterface { payment_method_type: Option>, authentication_type: Option>, merchant_connector_id: Option>, + profile_id_list: Option>, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result; } diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs index 6c9ba443de7..bbb561d7007 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -737,6 +737,16 @@ pub enum PaymentIntentFetchConstraints { List(Box), } +impl PaymentIntentFetchConstraints { + pub fn get_profile_id_list(&self) -> Option> { + if let Self::List(pi_list_params) = self { + pi_list_params.profile_id.clone() + } else { + None + } + } +} + pub struct PaymentIntentListParams { pub offset: u32, pub starting_at: Option, @@ -749,7 +759,7 @@ pub struct PaymentIntentListParams { pub payment_method_type: Option>, pub authentication_type: Option>, pub merchant_connector_id: Option>, - pub profile_id: Option, + pub profile_id: Option>, pub customer_id: Option, pub starting_after_id: Option, pub ending_before_id: Option, @@ -759,10 +769,21 @@ pub struct PaymentIntentListParams { impl From for PaymentIntentFetchConstraints { fn from(value: api_models::payments::PaymentListConstraints) -> Self { + let api_models::payments::PaymentListConstraints { + customer_id, + starting_after, + ending_before, + limit, + created, + created_lt, + created_gt, + created_lte, + created_gte, + } = value; Self::List(Box::new(PaymentIntentListParams { offset: 0, - starting_at: value.created_gte.or(value.created_gt).or(value.created), - ending_at: value.created_lte.or(value.created_lt).or(value.created), + starting_at: created_gte.or(created_gt).or(created), + ending_at: created_lte.or(created_lt).or(created), amount_filter: None, connector: None, currency: None, @@ -772,10 +793,10 @@ impl From for PaymentIntentFetchCo authentication_type: None, merchant_connector_id: None, profile_id: None, - customer_id: value.customer_id, - starting_after_id: value.starting_after, - ending_before_id: value.ending_before, - limit: Some(std::cmp::min(value.limit, PAYMENTS_LIST_MAX_LIMIT_V1)), + customer_id, + starting_after_id: starting_after, + ending_before_id: ending_before, + limit: Some(std::cmp::min(limit, PAYMENTS_LIST_MAX_LIMIT_V1)), order: Default::default(), })) } @@ -807,28 +828,96 @@ impl From for PaymentIntentFetchConstraints { impl From for PaymentIntentFetchConstraints { fn from(value: api_models::payments::PaymentListFilterConstraints) -> Self { - if let Some(payment_intent_id) = value.payment_id { + let api_models::payments::PaymentListFilterConstraints { + payment_id, + profile_id, + customer_id, + limit, + offset, + amount_filter, + time_range, + connector, + currency, + status, + payment_method, + payment_method_type, + authentication_type, + merchant_connector_id, + order, + } = value; + if let Some(payment_intent_id) = payment_id { Self::Single { payment_intent_id } } else { Self::List(Box::new(PaymentIntentListParams { - offset: value.offset.unwrap_or_default(), - starting_at: value.time_range.map(|t| t.start_time), - ending_at: value.time_range.and_then(|t| t.end_time), - amount_filter: value.amount_filter, - connector: value.connector, - currency: value.currency, - status: value.status, - payment_method: value.payment_method, - payment_method_type: value.payment_method_type, - authentication_type: value.authentication_type, - merchant_connector_id: value.merchant_connector_id, - profile_id: value.profile_id, - customer_id: value.customer_id, + offset: offset.unwrap_or_default(), + starting_at: time_range.map(|t| t.start_time), + ending_at: time_range.and_then(|t| t.end_time), + amount_filter, + connector, + currency, + status, + payment_method, + payment_method_type, + authentication_type, + merchant_connector_id, + profile_id: profile_id.map(|profile_id| vec![profile_id]), + customer_id, starting_after_id: None, ending_before_id: None, - limit: Some(std::cmp::min(value.limit, PAYMENTS_LIST_MAX_LIMIT_V2)), - order: value.order, + limit: Some(std::cmp::min(limit, PAYMENTS_LIST_MAX_LIMIT_V2)), + order, })) } } } + +impl TryFrom<(T, Option>)> for PaymentIntentFetchConstraints +where + Self: From, +{ + type Error = error_stack::Report; + fn try_from( + (constraints, auth_profile_id_list): (T, Option>), + ) -> Result { + let payment_intent_constraints = Self::from(constraints); + if let Self::List(mut pi_list_params) = payment_intent_constraints { + let profile_id_from_request_body = pi_list_params.profile_id; + match (profile_id_from_request_body, auth_profile_id_list) { + (None, None) => pi_list_params.profile_id = None, + (None, Some(auth_profile_id_list)) => { + pi_list_params.profile_id = Some(auth_profile_id_list) + } + (Some(profile_id_from_request_body), None) => { + pi_list_params.profile_id = Some(profile_id_from_request_body) + } + (Some(profile_id_from_request_body), Some(auth_profile_id_list)) => { + let profile_id_from_request_body_is_available_in_auth_profile_id_list = + profile_id_from_request_body + .iter() + .all(|profile_id| auth_profile_id_list.contains(profile_id)); + + if profile_id_from_request_body_is_available_in_auth_profile_id_list { + pi_list_params.profile_id = Some(profile_id_from_request_body) + } else { + // This scenario is very unlikely to happen + let inaccessible_profile_ids: Vec<_> = profile_id_from_request_body + .iter() + .filter(|profile_id| !auth_profile_id_list.contains(profile_id)) + .collect(); + return Err(error_stack::Report::new( + errors::api_error_response::ApiErrorResponse::PreconditionFailed { + message: format!( + "Access not available for the given profile_id {:?}", + inaccessible_profile_ids + ), + }, + )); + } + } + } + Ok(Self::List(pi_list_params)) + } else { + Ok(payment_intent_constraints) + } + } +} diff --git a/crates/hyperswitch_domain_models/src/refunds.rs b/crates/hyperswitch_domain_models/src/refunds.rs new file mode 100644 index 00000000000..3b3a79407d0 --- /dev/null +++ b/crates/hyperswitch_domain_models/src/refunds.rs @@ -0,0 +1,82 @@ +use crate::errors; + +pub struct RefundListConstraints { + pub payment_id: Option, + pub refund_id: Option, + pub profile_id: Option>, + pub limit: Option, + pub offset: Option, + pub time_range: Option, + pub amount_filter: Option, + pub connector: Option>, + pub merchant_connector_id: Option>, + pub currency: Option>, + pub refund_status: Option>, +} + +impl + TryFrom<( + api_models::refunds::RefundListRequest, + Option>, + )> for RefundListConstraints +{ + type Error = error_stack::Report; + + fn try_from( + (value, auth_profile_id_list): ( + api_models::refunds::RefundListRequest, + Option>, + ), + ) -> Result { + let api_models::refunds::RefundListRequest { + connector, + currency, + refund_status, + payment_id, + refund_id, + profile_id, + limit, + offset, + time_range, + amount_filter, + merchant_connector_id, + } = value; + let profile_id_from_request_body = profile_id; + let profile_id_list = match (profile_id_from_request_body, auth_profile_id_list) { + (None, None) => None, + (None, Some(auth_profile_id_list)) => Some(auth_profile_id_list), + (Some(profile_id_from_request_body), None) => Some(vec![profile_id_from_request_body]), + (Some(profile_id_from_request_body), Some(auth_profile_id_list)) => { + let profile_id_from_request_body_is_available_in_auth_profile_id_list = + auth_profile_id_list.contains(&profile_id_from_request_body); + + if profile_id_from_request_body_is_available_in_auth_profile_id_list { + Some(vec![profile_id_from_request_body]) + } else { + // This scenario is very unlikely to happen + return Err(error_stack::Report::new( + errors::api_error_response::ApiErrorResponse::PreconditionFailed { + message: format!( + "Access not available for the given profile_id {:?}", + profile_id_from_request_body + ), + }, + )); + } + } + }; + Ok(Self { + payment_id, + refund_id, + profile_id: profile_id_list, + limit, + offset, + time_range, + amount_filter, + connector, + merchant_connector_id, + currency, + refund_status, + }) + } +} diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index cee4e9d1dd2..4d4c4f8ccdb 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -3652,23 +3652,29 @@ pub async fn list_payment_methods( api_surcharge_decision_configs::MerchantSurchargeConfigs::default() }; - let collect_shipping_details_from_wallets = business_profile - .as_ref() - .and_then(|business_profile| { - business_profile.always_collect_shipping_details_from_wallet_connector - }) - .or(business_profile.as_ref().and_then(|business_profile| { - business_profile.collect_shipping_details_from_wallet_connector - })); + let collect_shipping_details_from_wallets = + business_profile.as_ref().and_then(|business_profile| { + if business_profile + .always_collect_shipping_details_from_wallet_connector + .unwrap_or(false) + { + business_profile.always_collect_shipping_details_from_wallet_connector + } else { + business_profile.collect_shipping_details_from_wallet_connector + } + }); - let collect_billing_details_from_wallets = business_profile - .as_ref() - .and_then(|business_profile| { - business_profile.always_collect_billing_details_from_wallet_connector - }) - .or(business_profile.as_ref().and_then(|business_profile| { - business_profile.collect_billing_details_from_wallet_connector - })); + let collect_billing_details_from_wallets = + business_profile.as_ref().and_then(|business_profile| { + if business_profile + .always_collect_billing_details_from_wallet_connector + .unwrap_or(false) + { + business_profile.always_collect_billing_details_from_wallet_connector + } else { + business_profile.collect_billing_details_from_wallet_connector + } + }); Ok(services::ApplicationResponse::Json( api::PaymentMethodListResponse { diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 8778079e728..c21d43df9f6 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -2918,15 +2918,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 { @@ -2989,25 +2987,25 @@ pub async fn apply_filters_on_payments( ) -> RouterResponse { 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 = 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 @@ -3022,6 +3020,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 diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 8ce183d3e3d..bbd8545603d 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -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, ) diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index 1761c0bad03..b702b32a733 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -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>, + profile_id_list: Option>, req: api_models::refunds::RefundListRequest, ) -> RouterResponse { 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 diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index 31ed4ad93e2..9c625f1f2b5 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -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>, authentication_type: Option>, merchant_connector_id: Option>, + profile_id_list: Option>, storage_scheme: MerchantStorageScheme, ) -> CustomResult { 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 { self.diesel_store diff --git a/crates/router/src/db/refund.rs b/crates/router/src/db/refund.rs index e6b46c5af5c..6208a06d141 100644 --- a/crates/router/src/db/refund.rs +++ b/crates/router/src/db/refund.rs @@ -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; } @@ -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 { 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 { 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 { 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( diff --git a/crates/router/src/types/storage/refund.rs b/crates/router/src/types/storage/refund.rs index 1860771d026..257982a0fba 100644 --- a/crates/router/src/types/storage/refund.rs +++ b/crates/router/src/types/storage/refund.rs @@ -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, 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; } @@ -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, 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 { let mut filter = ::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 { diff --git a/crates/storage_impl/src/mock_db/payment_attempt.rs b/crates/storage_impl/src/mock_db/payment_attempt.rs index 9cdc1e87ce8..11205b94db5 100644 --- a/crates/storage_impl/src/mock_db/payment_attempt.rs +++ b/crates/storage_impl/src/mock_db/payment_attempt.rs @@ -45,6 +45,7 @@ impl PaymentAttemptInterface for MockDb { _payment_method_type: Option>, _authentication_type: Option>, _merchanat_connector_id: Option>, + _profile_id_list: Option>, _storage_scheme: storage_enums::MerchantStorageScheme, ) -> CustomResult { Err(StorageError::MockDbError)? diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index 7edf5fd5a77..3cc04e8af5d 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -296,6 +296,7 @@ impl PaymentAttemptInterface for RouterStore { payment_method_type: Option>, authentication_type: Option>, merchant_connector_id: Option>, + profile_id_list: Option>, _storage_scheme: MerchantStorageScheme, ) -> CustomResult { let conn = self @@ -318,6 +319,7 @@ impl PaymentAttemptInterface for RouterStore { payment_method, payment_method_type, authentication_type, + profile_id_list, merchant_connector_id, ) .await @@ -1067,6 +1069,7 @@ impl PaymentAttemptInterface for KVRouterStore { payment_method_type: Option>, authentication_type: Option>, merchant_connector_id: Option>, + profile_id_list: Option>, storage_scheme: MerchantStorageScheme, ) -> CustomResult { self.router_store @@ -1078,6 +1081,7 @@ impl PaymentAttemptInterface for KVRouterStore { payment_method_type, authentication_type, merchant_connector_id, + profile_id_list, storage_scheme, ) .await diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index 4624f33eec3..f69c26e6409 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -553,7 +553,7 @@ impl PaymentIntentInterface for crate::RouterStore { query = query.filter(pi_dsl::customer_id.eq(customer_id.clone())); } if let Some(profile_id) = ¶ms.profile_id { - query = query.filter(pi_dsl::profile_id.eq(profile_id.clone())); + query = query.filter(pi_dsl::profile_id.eq_any(profile_id.clone())); } query = match (params.starting_at, ¶ms.starting_after_id) { @@ -758,7 +758,7 @@ impl PaymentIntentInterface for crate::RouterStore { } if let Some(profile_id) = ¶ms.profile_id { - query = query.filter(pi_dsl::profile_id.eq(profile_id.clone())); + query = query.filter(pi_dsl::profile_id.eq_any(profile_id.clone())); } query = match (params.starting_at, ¶ms.starting_after_id) { @@ -922,7 +922,7 @@ impl PaymentIntentInterface for crate::RouterStore { query = query.filter(pi_dsl::customer_id.eq(customer_id.clone())); } if let Some(profile_id) = ¶ms.profile_id { - query = query.filter(pi_dsl::profile_id.eq(profile_id.clone())); + query = query.filter(pi_dsl::profile_id.eq_any(profile_id.clone())); } query = match params.starting_at {