diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs index e5b0e8b912..62fb06fd52 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -71,6 +71,7 @@ pub trait PaymentIntentInterface { async fn get_intent_status_with_count( &self, merchant_id: &id_type::MerchantId, + profile_id_list: Option>, constraints: &api_models::payments::TimeRange, ) -> error_stack::Result, errors::StorageError>; diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index f94a5a4633..4eedb52c99 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -3234,11 +3234,12 @@ pub async fn get_payment_filters( pub async fn get_aggregates_for_payments( state: SessionState, merchant: domain::MerchantAccount, + profile_id_list: Option>, time_range: api::TimeRange, ) -> RouterResponse { let db = state.store.as_ref(); let intent_status_with_count = db - .get_intent_status_with_count(merchant.get_id(), &time_range) + .get_intent_status_with_count(merchant.get_id(), profile_id_list, &time_range) .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index 2088177754..76111afc6b 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -1640,10 +1640,11 @@ impl PaymentIntentInterface for KafkaStore { async fn get_intent_status_with_count( &self, merchant_id: &id_type::MerchantId, + profile_id_list: Option>, time_range: &api_models::payments::TimeRange, ) -> error_stack::Result, errors::DataStorageError> { self.diesel_store - .get_intent_status_with_count(merchant_id, time_range) + .get_intent_status_with_count(merchant_id, profile_id_list, time_range) .await } diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 4f8e269dff..210ded9c25 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -547,6 +547,10 @@ impl Payments { .service(web::resource("/filter").route(web::post().to(get_filters_for_payments))) .service(web::resource("/v2/filter").route(web::get().to(get_payment_filters))) .service(web::resource("/aggregate").route(web::get().to(get_payments_aggregates))) + .service( + web::resource("/profile/aggregate") + .route(web::get().to(get_payments_aggregates_profile)), + ) .service( web::resource("/v2/profile/filter") .route(web::get().to(get_payment_filters_profile)), diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index 18460d6329..8f3ee3dd4b 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -1341,7 +1341,7 @@ pub async fn get_payments_aggregates( &req, payload, |state, auth: auth::AuthenticationData, req, _| { - payments::get_aggregates_for_payments(state, auth.merchant_account, req) + payments::get_aggregates_for_payments(state, auth.merchant_account, None, req) }, &auth::JWTAuth { permission: Permission::PaymentRead, @@ -2074,3 +2074,34 @@ impl GetLockingInput for payment_types::PaymentsManualUpdateRequest { } } } + +#[instrument(skip_all, fields(flow = ?Flow::PaymentsAggregate))] +#[cfg(feature = "olap")] +pub async fn get_payments_aggregates_profile( + state: web::Data, + req: actix_web::HttpRequest, + payload: web::Query, +) -> impl Responder { + let flow = Flow::PaymentsAggregate; + let payload = payload.into_inner(); + Box::pin(api::server_wrap( + flow, + state, + &req, + payload, + |state, auth: auth::AuthenticationData, req, _| { + payments::get_aggregates_for_payments( + state, + auth.merchant_account, + auth.profile_id.map(|profile_id| vec![profile_id]), + req, + ) + }, + &auth::JWTAuth { + permission: Permission::PaymentRead, + minimum_entity_level: EntityType::Profile, + }, + api_locking::LockAction::NotApplicable, + )) + .await +} diff --git a/crates/storage_impl/src/mock_db/payment_intent.rs b/crates/storage_impl/src/mock_db/payment_intent.rs index f5db60da3f..e296c88b3a 100644 --- a/crates/storage_impl/src/mock_db/payment_intent.rs +++ b/crates/storage_impl/src/mock_db/payment_intent.rs @@ -44,6 +44,7 @@ impl PaymentIntentInterface for MockDb { async fn get_intent_status_with_count( &self, _merchant_id: &common_utils::id_type::MerchantId, + _profile_id_list: Option>, _time_range: &api_models::payments::TimeRange, ) -> CustomResult, StorageError> { // [#172]: Implement function for `MockDb` diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index f69c26e640..90395e15da 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -350,10 +350,11 @@ impl PaymentIntentInterface for KVRouterStore { async fn get_intent_status_with_count( &self, merchant_id: &common_utils::id_type::MerchantId, + profile_id_list: Option>, time_range: &api_models::payments::TimeRange, ) -> error_stack::Result, StorageError> { self.router_store - .get_intent_status_with_count(merchant_id, time_range) + .get_intent_status_with_count(merchant_id, profile_id_list, time_range) .await } @@ -670,6 +671,7 @@ impl PaymentIntentInterface for crate::RouterStore { async fn get_intent_status_with_count( &self, merchant_id: &common_utils::id_type::MerchantId, + profile_id_list: Option>, time_range: &api_models::payments::TimeRange, ) -> error_stack::Result, StorageError> { let conn = connection::pg_connection_read(self).await.switch()?; @@ -681,6 +683,10 @@ impl PaymentIntentInterface for crate::RouterStore { .filter(pi_dsl::merchant_id.eq(merchant_id.to_owned())) .into_boxed(); + if let Some(profile_id) = profile_id_list { + query = query.filter(pi_dsl::profile_id.eq_any(profile_id)); + } + query = query.filter(pi_dsl::created_at.ge(time_range.start_time)); query = match time_range.end_time {