diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 919f057d55..b85734af8b 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -3394,6 +3394,8 @@ pub struct PaymentListFilterConstraints { pub limit: u32, /// The starting point within a list of objects pub offset: Option, + /// The amount to filter payments list + pub amount_filter: Option, /// 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). #[serde(flatten)] pub time_range: Option, @@ -3409,6 +3411,8 @@ pub struct PaymentListFilterConstraints { pub payment_method_type: Option>, /// The list of authentication types to filter payments list pub authentication_type: Option>, + /// The list of merchant connector ids to filter payments list for selected label + pub merchant_connector_id: Option>, } #[derive(Clone, Debug, serde::Serialize)] pub struct PaymentListFilters { @@ -3440,6 +3444,12 @@ pub struct PaymentListFiltersV2 { pub authentication_type: Vec, } +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +pub struct AmountFilter { + pub start_amount: Option, + pub end_amount: Option, +} + #[derive( Debug, Clone, Copy, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash, ToSchema, )] diff --git a/crates/common_utils/src/consts.rs b/crates/common_utils/src/consts.rs index 74fdabecf1..0b988a195f 100644 --- a/crates/common_utils/src/consts.rs +++ b/crates/common_utils/src/consts.rs @@ -22,7 +22,7 @@ pub static FRM_CONFIGS_EG: &str = r#" /// Maximum limit for payments list get api pub const PAYMENTS_LIST_MAX_LIMIT_V1: u32 = 100; /// Maximum limit for payments list post api with filters -pub const PAYMENTS_LIST_MAX_LIMIT_V2: u32 = 20; +pub const PAYMENTS_LIST_MAX_LIMIT_V2: u32 = 50; /// Default limit for payments list API pub fn default_payments_list_limit() -> u32 { 10 diff --git a/crates/data_models/src/payments/payment_attempt.rs b/crates/data_models/src/payments/payment_attempt.rs index 6c236729de..ec0e087316 100644 --- a/crates/data_models/src/payments/payment_attempt.rs +++ b/crates/data_models/src/payments/payment_attempt.rs @@ -99,6 +99,7 @@ pub trait PaymentAttemptInterface { payment_method: Option>, payment_method_type: Option>, authentication_type: Option>, + merchant_connector_id: Option>, storage_scheme: storage_enums::MerchantStorageScheme, ) -> error_stack::Result; } diff --git a/crates/data_models/src/payments/payment_intent.rs b/crates/data_models/src/payments/payment_intent.rs index 83b266c347..0ab39bcbad 100644 --- a/crates/data_models/src/payments/payment_intent.rs +++ b/crates/data_models/src/payments/payment_intent.rs @@ -430,12 +430,14 @@ pub struct PaymentIntentListParams { pub offset: u32, pub starting_at: Option, pub ending_at: Option, + pub amount_filter: Option, pub connector: Option>, pub currency: Option>, pub status: Option>, pub payment_method: Option>, pub payment_method_type: Option>, pub authentication_type: Option>, + pub merchant_connector_id: Option>, pub profile_id: Option, pub customer_id: Option, pub starting_after_id: Option, @@ -449,12 +451,14 @@ impl From for PaymentIntentFetchCo 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), + amount_filter: None, connector: None, currency: None, status: None, payment_method: None, payment_method_type: None, authentication_type: None, + merchant_connector_id: None, profile_id: None, customer_id: value.customer_id, starting_after_id: value.starting_after, @@ -470,12 +474,14 @@ impl From for PaymentIntentFetchConstraints { offset: 0, starting_at: Some(value.start_time), ending_at: value.end_time, + amount_filter: None, connector: None, currency: None, status: None, payment_method: None, payment_method_type: None, authentication_type: None, + merchant_connector_id: None, profile_id: None, customer_id: None, starting_after_id: None, @@ -494,12 +500,14 @@ impl From for PaymentIntentF 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, starting_after_id: None, diff --git a/crates/diesel_models/src/query/payment_attempt.rs b/crates/diesel_models/src/query/payment_attempt.rs index 0133c52c5d..f23c231889 100644 --- a/crates/diesel_models/src/query/payment_attempt.rs +++ b/crates/diesel_models/src/query/payment_attempt.rs @@ -309,6 +309,8 @@ impl PaymentAttempt { filter_authentication_type, )) } + + #[allow(clippy::too_many_arguments)] pub async fn get_total_count_of_attempts( conn: &PgPooledConn, merchant_id: &str, @@ -317,6 +319,7 @@ impl PaymentAttempt { payment_method: Option>, payment_method_type: Option>, authentication_type: Option>, + merchant_connector_id: Option>, ) -> StorageResult { let mut filter = ::table() .count() @@ -324,19 +327,22 @@ impl PaymentAttempt { .filter(dsl::attempt_id.eq_any(active_attempt_ids.to_owned())) .into_boxed(); - if let Some(connector) = connector.clone() { + if let Some(connector) = connector { filter = filter.filter(dsl::connector.eq_any(connector)); } - if let Some(payment_method) = payment_method.clone() { + if let Some(payment_method) = payment_method { filter = filter.filter(dsl::payment_method.eq_any(payment_method)); } - if let Some(payment_method_type) = payment_method_type.clone() { + if let Some(payment_method_type) = payment_method_type { filter = filter.filter(dsl::payment_method_type.eq_any(payment_method_type)); } - if let Some(authentication_type) = authentication_type.clone() { + if let Some(authentication_type) = authentication_type { filter = filter.filter(dsl::authentication_type.eq_any(authentication_type)); } + if let Some(merchant_connector_id) = merchant_connector_id { + filter = filter.filter(dsl::merchant_connector_id.eq_any(merchant_connector_id)) + } router_env::logger::debug!(query = %debug_query::(&filter).to_string()); db_metrics::track_database_call::<::Table, _, _>( diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index d9e22d4026..a3292e3cd6 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -2579,6 +2579,7 @@ pub async fn apply_filters_on_payments( constraints.payment_method, constraints.payment_method_type, constraints.authentication_type, + constraints.merchant_connector_id, merchant.storage_scheme, ) .await diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index 7da40e505e..73b519e544 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -1258,6 +1258,7 @@ impl PaymentAttemptInterface for KafkaStore { payment_method: Option>, payment_method_type: Option>, authentication_type: Option>, + merchant_connector_id: Option>, storage_scheme: MerchantStorageScheme, ) -> CustomResult { self.diesel_store @@ -1268,6 +1269,7 @@ impl PaymentAttemptInterface for KafkaStore { payment_method, payment_method_type, authentication_type, + merchant_connector_id, storage_scheme, ) .await diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index c333181778..c1d67c4ce0 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -922,14 +922,10 @@ pub async fn payments_list_by_filter( state, &req, payload, - |state, auth, req, _| { + |state, auth: auth::AuthenticationData, req, _| { payments::apply_filters_on_payments(state, auth.merchant_account, req) }, - auth::auth_type( - &auth::ApiKeyAuth, - &auth::JWTAuth(Permission::PaymentRead), - req.headers(), - ), + &auth::JWTAuth(Permission::PaymentRead), api_locking::LockAction::NotApplicable, ) .await @@ -948,12 +944,10 @@ pub async fn get_filters_for_payments( state, &req, payload, - |state, auth, req, _| payments::get_filters_for_payments(state, auth.merchant_account, req), - auth::auth_type( - &auth::ApiKeyAuth, - &auth::JWTAuth(Permission::PaymentRead), - req.headers(), - ), + |state, auth: auth::AuthenticationData, req, _| { + payments::get_filters_for_payments(state, auth.merchant_account, req) + }, + &auth::JWTAuth(Permission::PaymentRead), api_locking::LockAction::NotApplicable, ) .await @@ -971,12 +965,10 @@ pub async fn get_payment_filters( state, &req, (), - |state, auth, _, _| payments::get_payment_filters(state, auth.merchant_account), - auth::auth_type( - &auth::ApiKeyAuth, - &auth::JWTAuth(Permission::PaymentRead), - req.headers(), - ), + |state, auth: auth::AuthenticationData, _, _| { + payments::get_payment_filters(state, auth.merchant_account) + }, + &auth::JWTAuth(Permission::PaymentRead), api_locking::LockAction::NotApplicable, ) .await diff --git a/crates/storage_impl/src/mock_db/payment_attempt.rs b/crates/storage_impl/src/mock_db/payment_attempt.rs index acec82e172..996c8e102b 100644 --- a/crates/storage_impl/src/mock_db/payment_attempt.rs +++ b/crates/storage_impl/src/mock_db/payment_attempt.rs @@ -42,6 +42,7 @@ impl PaymentAttemptInterface for MockDb { _payment_method: Option>, _payment_method_type: Option>, _authentication_type: Option>, + _merchanat_connector_id: 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 138f3658aa..6eda689c8d 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -292,6 +292,7 @@ impl PaymentAttemptInterface for RouterStore { payment_method: Option>, payment_method_type: Option>, authentication_type: Option>, + merchant_connector_id: Option>, _storage_scheme: MerchantStorageScheme, ) -> CustomResult { let conn = self @@ -314,6 +315,7 @@ impl PaymentAttemptInterface for RouterStore { payment_method, payment_method_type, authentication_type, + merchant_connector_id, ) .await .map_err(|er| { @@ -1021,6 +1023,7 @@ impl PaymentAttemptInterface for KVRouterStore { payment_method: Option>, payment_method_type: Option>, authentication_type: Option>, + merchant_connector_id: Option>, storage_scheme: MerchantStorageScheme, ) -> CustomResult { self.router_store @@ -1031,6 +1034,7 @@ impl PaymentAttemptInterface for KVRouterStore { payment_method, payment_method_type, authentication_type, + merchant_connector_id, storage_scheme, ) .await diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index 8934b3ba2c..6b4cf8b82e 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -1,5 +1,9 @@ #[cfg(feature = "olap")] +use api_models::payments::AmountFilter; +#[cfg(feature = "olap")] use async_bb8_diesel::{AsyncConnection, AsyncRunQueryDsl}; +#[cfg(feature = "olap")] +use common_utils::errors::ReportSwitchExt; use common_utils::{date_time, ext_traits::Encode}; #[cfg(feature = "olap")] use data_models::payments::payment_intent::PaymentIntentFetchConstraints; @@ -549,8 +553,6 @@ impl PaymentIntentInterface for crate::RouterStore { constraints: &PaymentIntentFetchConstraints, storage_scheme: MerchantStorageScheme, ) -> error_stack::Result, StorageError> { - use common_utils::errors::ReportSwitchExt; - let conn = connection::pg_connection_read(self).await.switch()?; let conn = async_bb8_diesel::Connection::as_async_conn(&conn); let mut query = DieselPaymentIntent::table() @@ -615,9 +617,26 @@ impl PaymentIntentInterface for crate::RouterStore { query = query.offset(params.offset.into()); - if let Some(currency) = ¶ms.currency { - query = query.filter(pi_dsl::currency.eq_any(currency.clone())); - } + query = match params.amount_filter { + Some(AmountFilter { + start_amount: Some(start), + end_amount: Some(end), + }) => query.filter(pi_dsl::amount.between(start, end)), + Some(AmountFilter { + start_amount: Some(start), + end_amount: None, + }) => query.filter(pi_dsl::amount.ge(start)), + Some(AmountFilter { + start_amount: None, + end_amount: Some(end), + }) => query.filter(pi_dsl::amount.le(end)), + _ => query, + }; + + query = match ¶ms.currency { + Some(currency) => query.filter(pi_dsl::currency.eq_any(currency.clone())), + None => query, + }; let connectors = params .connector @@ -653,6 +672,13 @@ impl PaymentIntentInterface for crate::RouterStore { None => query, }; + query = match ¶ms.merchant_connector_id { + Some(merchant_connector_id) => query.filter( + pa_dsl::merchant_connector_id.eq_any(merchant_connector_id.clone()), + ), + None => query, + }; + query } }; @@ -690,8 +716,6 @@ impl PaymentIntentInterface for crate::RouterStore { constraints: &PaymentIntentFetchConstraints, _storage_scheme: MerchantStorageScheme, ) -> error_stack::Result, StorageError> { - use common_utils::errors::ReportSwitchExt; - let conn = connection::pg_connection_read(self).await.switch()?; let conn = async_bb8_diesel::Connection::as_async_conn(&conn); let mut query = DieselPaymentIntent::table() @@ -722,6 +746,22 @@ impl PaymentIntentInterface for crate::RouterStore { None => query, }; + query = match params.amount_filter { + Some(AmountFilter { + start_amount: Some(start), + end_amount: Some(end), + }) => query.filter(pi_dsl::amount.between(start, end)), + Some(AmountFilter { + start_amount: Some(start), + end_amount: None, + }) => query.filter(pi_dsl::amount.ge(start)), + Some(AmountFilter { + start_amount: None, + end_amount: Some(end), + }) => query.filter(pi_dsl::amount.le(end)), + _ => query, + }; + query = match ¶ms.currency { Some(currency) => query.filter(pi_dsl::currency.eq_any(currency.clone())), None => query,