From 6fb2d70d7773a14be2b0df97748c52e0a93a6885 Mon Sep 17 00:00:00 2001 From: Jeeva Ramachandran Date: Fri, 3 May 2024 12:44:42 +0530 Subject: [PATCH 1/7] organazation analytics --- crates/analytics/src/lib.rs | 7 ++ crates/analytics/src/payments/core.rs | 41 +++++++++- crates/analytics/src/payments/filters.rs | 6 +- crates/analytics/src/payments/metrics.rs | 9 +++ .../src/payments/metrics/avg_ticket_size.rs | 7 +- .../metrics/connector_success_rate.rs | 6 +- .../src/payments/metrics/payment_count.rs | 7 +- .../metrics/payment_processed_amount.rs | 7 +- .../payments/metrics/payment_success_count.rs | 7 +- .../src/payments/metrics/retries_count.rs | 6 +- .../src/payments/metrics/success_rate.rs | 6 +- crates/analytics/src/refunds/core.rs | 1 + crates/analytics/src/sqlx.rs | 5 ++ crates/api_models/src/analytics/payments.rs | 5 ++ crates/api_models/src/user_role.rs | 1 + crates/router/src/analytics.rs | 12 ++- crates/router/src/services/api.rs | 1 + crates/router/src/services/authentication.rs | 79 +++++++++++++++++++ .../authorization/permission_groups.rs | 3 +- .../src/services/authorization/permissions.rs | 2 + crates/router/src/utils/user_role.rs | 1 + 21 files changed, 197 insertions(+), 22 deletions(-) diff --git a/crates/analytics/src/lib.rs b/crates/analytics/src/lib.rs index eb08d8549d1..2d886a21fc2 100644 --- a/crates/analytics/src/lib.rs +++ b/crates/analytics/src/lib.rs @@ -98,6 +98,7 @@ impl AnalyticsProvider { filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, + merchant_ids: &Vec, ) -> types::MetricsResult> { // Metrics to get the fetch time for each payment metric metrics::request::record_operation_time( @@ -112,6 +113,7 @@ impl AnalyticsProvider { granularity, time_range, pool, + merchant_ids ) .await } @@ -124,6 +126,7 @@ impl AnalyticsProvider { granularity, time_range, pool, + merchant_ids ) .await } @@ -136,6 +139,7 @@ impl AnalyticsProvider { granularity, time_range, ckh_pool, + merchant_ids ), metric .load_metrics( @@ -145,6 +149,7 @@ impl AnalyticsProvider { granularity, time_range, sqlx_pool, + merchant_ids )); match (&sqlx_result, &ckh_result) { (Ok(ref sqlx_res), Ok(ref ckh_res)) if sqlx_res != ckh_res => { @@ -165,6 +170,7 @@ impl AnalyticsProvider { granularity, time_range, ckh_pool, + merchant_ids ), metric .load_metrics( @@ -174,6 +180,7 @@ impl AnalyticsProvider { granularity, time_range, sqlx_pool, + merchant_ids )); match (&sqlx_result, &ckh_result) { (Ok(ref sqlx_res), Ok(ref ckh_res)) if sqlx_res != ckh_res => { diff --git a/crates/analytics/src/payments/core.rs b/crates/analytics/src/payments/core.rs index debc03fc9d5..e4aa7a730a4 100644 --- a/crates/analytics/src/payments/core.rs +++ b/crates/analytics/src/payments/core.rs @@ -41,17 +41,41 @@ pub enum TaskType { ), } +fn compare_and_return_matching( + org_merchant_ids: &Vec, + payload: &Vec, +) -> Vec { + let mut matching_values = vec![]; + + for m in org_merchant_ids { + let t = m.clone(); + if payload.contains(&t) { + matching_values.push(t); + } + } + + if matching_values.is_empty() { + org_merchant_ids.to_vec() + } else { + matching_values + } +} + #[instrument(skip_all)] pub async fn get_metrics( pool: &AnalyticsProvider, merchant_id: &str, req: GetPaymentMetricRequest, + merchant_ids: &Vec, ) -> AnalyticsResult> { + println!("{:?}ORG MERCHANT_IDSSS", merchant_ids); + let org_merchant_ids = compare_and_return_matching(merchant_ids, &req.filters.merchant_id); + println!("{:?}MERCHANT_IDSSS", org_merchant_ids); let mut metrics_accumulator: HashMap< PaymentMetricsBucketIdentifier, PaymentMetricsAccumulator, > = HashMap::new(); - + // println!("{:?} List of Merchant ID", merchant_ids); let mut set = tokio::task::JoinSet::new(); for metric_type in req.metrics.iter().cloned() { let req = req.clone(); @@ -64,6 +88,7 @@ pub async fn get_metrics( // TODO: lifetime issues with joinset, // can be optimized away if joinset lifetime requirements are relaxed let merchant_id_scoped = merchant_id.to_owned(); + let merchant_ids = org_merchant_ids.to_owned(); set.spawn( async move { let data = pool @@ -74,6 +99,7 @@ pub async fn get_metrics( &req.filters, &req.time_series.map(|t| t.granularity), &req.time_range, + &merchant_ids.clone(), ) .await .change_context(AnalyticsError::UnknownError); @@ -222,17 +248,21 @@ pub async fn get_filters( pool: &AnalyticsProvider, req: GetPaymentFiltersRequest, merchant_id: &String, + merchant_ids: &Vec, ) -> AnalyticsResult { + println!("{:?} merchant_id merchant_id FG LOF", merchant_id); + // println!("{:?} merchant_id list", list_merchant_id); + let mut res = PaymentFiltersResponse::default(); for dim in req.group_by_names { let values = match pool { AnalyticsProvider::Sqlx(pool) => { - get_payment_filter_for_dimension(dim, merchant_id, &req.time_range, pool) + get_payment_filter_for_dimension(dim, merchant_id, &req.time_range, pool,merchant_ids) .await } AnalyticsProvider::Clickhouse(pool) => { - get_payment_filter_for_dimension(dim, merchant_id, &req.time_range, pool) + get_payment_filter_for_dimension(dim, merchant_id, &req.time_range, pool,merchant_ids) .await } AnalyticsProvider::CombinedCkh(sqlx_poll, ckh_pool) => { @@ -241,6 +271,7 @@ pub async fn get_filters( merchant_id, &req.time_range, ckh_pool, + merchant_ids ) .await; let sqlx_result = get_payment_filter_for_dimension( @@ -248,6 +279,7 @@ pub async fn get_filters( merchant_id, &req.time_range, sqlx_poll, + merchant_ids ) .await; match (&sqlx_result, &ckh_result) { @@ -264,6 +296,7 @@ pub async fn get_filters( merchant_id, &req.time_range, ckh_pool, + merchant_ids ) .await; let sqlx_result = get_payment_filter_for_dimension( @@ -271,6 +304,7 @@ pub async fn get_filters( merchant_id, &req.time_range, sqlx_poll, + merchant_ids ) .await; match (&sqlx_result, &ckh_result) { @@ -291,6 +325,7 @@ pub async fn get_filters( PaymentDimensions::AuthType => fil.authentication_type.map(|i| i.as_ref().to_string()), PaymentDimensions::PaymentMethod => fil.payment_method, PaymentDimensions::PaymentMethodType => fil.payment_method_type, + PaymentDimensions::MerchantId=>fil.merchant_id }) .collect::>(); res.query_data.push(FilterValue { diff --git a/crates/analytics/src/payments/filters.rs b/crates/analytics/src/payments/filters.rs index 6c165f78a8e..6c9eb94d708 100644 --- a/crates/analytics/src/payments/filters.rs +++ b/crates/analytics/src/payments/filters.rs @@ -19,6 +19,7 @@ pub async fn get_payment_filter_for_dimension( merchant: &String, time_range: &TimeRange, pool: &T, + merchant_ids: &Vec, ) -> FiltersResult> where T: AnalyticsDataSource + PaymentFilterAnalytics, @@ -37,11 +38,9 @@ where .switch()?; query_builder - .add_filter_clause("merchant_id", merchant) + .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; - query_builder.set_distinct(); - query_builder .execute_query::(pool) .await @@ -57,4 +56,5 @@ pub struct FilterRow { pub authentication_type: Option>, pub payment_method: Option, pub payment_method_type: Option, + pub merchant_id: Option, } diff --git a/crates/analytics/src/payments/metrics.rs b/crates/analytics/src/payments/metrics.rs index 6fe6b6260d4..0c498202c77 100644 --- a/crates/analytics/src/payments/metrics.rs +++ b/crates/analytics/src/payments/metrics.rs @@ -58,6 +58,7 @@ where granularity: &Option, time_range: &TimeRange, pool: &T, + merchant_ids: &Vec, ) -> MetricsResult>; } @@ -79,6 +80,7 @@ where granularity: &Option, time_range: &TimeRange, pool: &T, + merchant_ids: &Vec, ) -> MetricsResult> { match self { Self::PaymentSuccessRate => { @@ -90,6 +92,7 @@ where granularity, time_range, pool, + merchant_ids, ) .await } @@ -102,6 +105,7 @@ where granularity, time_range, pool, + merchant_ids, ) .await } @@ -114,6 +118,7 @@ where granularity, time_range, pool, + merchant_ids, ) .await } @@ -126,6 +131,7 @@ where granularity, time_range, pool, + merchant_ids, ) .await } @@ -138,6 +144,7 @@ where granularity, time_range, pool, + merchant_ids, ) .await } @@ -150,6 +157,7 @@ where granularity, time_range, pool, + merchant_ids, ) .await } @@ -162,6 +170,7 @@ where granularity, time_range, pool, + merchant_ids, ) .await } diff --git a/crates/analytics/src/payments/metrics/avg_ticket_size.rs b/crates/analytics/src/payments/metrics/avg_ticket_size.rs index 9475d5288a6..75ccac2ee07 100644 --- a/crates/analytics/src/payments/metrics/avg_ticket_size.rs +++ b/crates/analytics/src/payments/metrics/avg_ticket_size.rs @@ -34,6 +34,7 @@ where granularity: &Option, time_range: &TimeRange, pool: &T, + merchant_ids: &Vec, ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::Payment); @@ -68,10 +69,12 @@ where filters.set_filter_clause(&mut query_builder).switch()?; + // query_builder + // .add_filter_clause("merchant_id", merchant_id) + // .switch()?; query_builder - .add_filter_clause("merchant_id", merchant_id) + .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; - time_range .set_filter_clause(&mut query_builder) .attach_printable("Error filtering time range") diff --git a/crates/analytics/src/payments/metrics/connector_success_rate.rs b/crates/analytics/src/payments/metrics/connector_success_rate.rs index 0c4d19b2e0b..18bf6961c79 100644 --- a/crates/analytics/src/payments/metrics/connector_success_rate.rs +++ b/crates/analytics/src/payments/metrics/connector_success_rate.rs @@ -36,6 +36,7 @@ where granularity: &Option, time_range: &TimeRange, pool: &T, + merchant_ids: &Vec, ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::Payment); let mut dimensions = dimensions.to_vec(); @@ -67,8 +68,11 @@ where filters.set_filter_clause(&mut query_builder).switch()?; + // query_builder + // .add_filter_clause("merchant_id", merchant_id) + // .switch()?; query_builder - .add_filter_clause("merchant_id", merchant_id) + .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; query_builder .add_custom_filter_clause(PaymentDimensions::Connector, "NULL", FilterTypes::IsNotNull) diff --git a/crates/analytics/src/payments/metrics/payment_count.rs b/crates/analytics/src/payments/metrics/payment_count.rs index 34e71f3da6f..4f57d1bea9b 100644 --- a/crates/analytics/src/payments/metrics/payment_count.rs +++ b/crates/analytics/src/payments/metrics/payment_count.rs @@ -33,6 +33,7 @@ where granularity: &Option, time_range: &TimeRange, pool: &T, + merchant_ids: &Vec, ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::Payment); @@ -61,10 +62,12 @@ where filters.set_filter_clause(&mut query_builder).switch()?; + // query_builder + // .add_filter_clause("merchant_id", merchant_id) + // .switch()?; query_builder - .add_filter_clause("merchant_id", merchant_id) + .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; - time_range .set_filter_clause(&mut query_builder) .attach_printable("Error filtering time range") diff --git a/crates/analytics/src/payments/metrics/payment_processed_amount.rs b/crates/analytics/src/payments/metrics/payment_processed_amount.rs index f2dbf97e0db..55438403bce 100644 --- a/crates/analytics/src/payments/metrics/payment_processed_amount.rs +++ b/crates/analytics/src/payments/metrics/payment_processed_amount.rs @@ -34,6 +34,7 @@ where granularity: &Option, time_range: &TimeRange, pool: &T, + merchant_ids: &Vec, ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::Payment); @@ -62,10 +63,12 @@ where filters.set_filter_clause(&mut query_builder).switch()?; + // query_builder + // .add_filter_clause("merchant_id", merchant_id) + // .switch()?; query_builder - .add_filter_clause("merchant_id", merchant_id) + .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; - time_range .set_filter_clause(&mut query_builder) .attach_printable("Error filtering time range") diff --git a/crates/analytics/src/payments/metrics/payment_success_count.rs b/crates/analytics/src/payments/metrics/payment_success_count.rs index a6fb8ed2239..1aaba5c2f32 100644 --- a/crates/analytics/src/payments/metrics/payment_success_count.rs +++ b/crates/analytics/src/payments/metrics/payment_success_count.rs @@ -34,6 +34,7 @@ where granularity: &Option, time_range: &TimeRange, pool: &T, + merchant_ids: &Vec, ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::Payment); @@ -62,10 +63,12 @@ where filters.set_filter_clause(&mut query_builder).switch()?; + // query_builder + // .add_filter_clause("merchant_id", merchant_id) + // .switch()?; query_builder - .add_filter_clause("merchant_id", merchant_id) + .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; - time_range .set_filter_clause(&mut query_builder) .attach_printable("Error filtering time range") diff --git a/crates/analytics/src/payments/metrics/retries_count.rs b/crates/analytics/src/payments/metrics/retries_count.rs index 91952adb569..fc89f848848 100644 --- a/crates/analytics/src/payments/metrics/retries_count.rs +++ b/crates/analytics/src/payments/metrics/retries_count.rs @@ -36,6 +36,7 @@ where granularity: &Option, time_range: &TimeRange, pool: &T, + merchant_ids: &Vec, ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::PaymentIntent); @@ -63,8 +64,11 @@ where alias: Some("end_bucket"), }) .switch()?; + // query_builder + // .add_filter_clause("merchant_id", merchant_id) + // .switch()?; query_builder - .add_filter_clause("merchant_id", merchant_id) + .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; query_builder .add_custom_filter_clause("attempt_count", "1", FilterTypes::Gt) diff --git a/crates/analytics/src/payments/metrics/success_rate.rs b/crates/analytics/src/payments/metrics/success_rate.rs index 9e688240ddb..c1be7ad3549 100644 --- a/crates/analytics/src/payments/metrics/success_rate.rs +++ b/crates/analytics/src/payments/metrics/success_rate.rs @@ -33,6 +33,7 @@ where granularity: &Option, time_range: &TimeRange, pool: &T, + merchant_ids: &Vec, ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::Payment); let mut dimensions = dimensions.to_vec(); @@ -64,8 +65,11 @@ where filters.set_filter_clause(&mut query_builder).switch()?; + // query_builder + // .add_filter_clause("merchant_id", merchant_id) + // .switch()?; query_builder - .add_filter_clause("merchant_id", merchant_id) + .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; time_range diff --git a/crates/analytics/src/refunds/core.rs b/crates/analytics/src/refunds/core.rs index b53d482e620..eeb23aae1eb 100644 --- a/crates/analytics/src/refunds/core.rs +++ b/crates/analytics/src/refunds/core.rs @@ -29,6 +29,7 @@ pub async fn get_metrics( pool: &AnalyticsProvider, merchant_id: &String, req: GetRefundMetricRequest, + list_merchant_id: &Vec, ) -> AnalyticsResult> { let mut metrics_accumulator: HashMap = HashMap::new(); diff --git a/crates/analytics/src/sqlx.rs b/crates/analytics/src/sqlx.rs index 86782c5f750..756a3ca0f15 100644 --- a/crates/analytics/src/sqlx.rs +++ b/crates/analytics/src/sqlx.rs @@ -387,6 +387,10 @@ impl<'a> FromRow<'a, PgRow> for super::payments::filters::FilterRow { ColumnNotFound(_) => Ok(Default::default()), e => Err(e), })?; + let merchant_id: Option = row.try_get("merchant_id").or_else(|e| match e { + ColumnNotFound(_) => Ok(Default::default()), + e => Err(e), + })?; Ok(Self { currency, status, @@ -394,6 +398,7 @@ impl<'a> FromRow<'a, PgRow> for super::payments::filters::FilterRow { authentication_type, payment_method, payment_method_type, + merchant_id, }) } } diff --git a/crates/api_models/src/analytics/payments.rs b/crates/api_models/src/analytics/payments.rs index 2d7ae262f48..db4fb7bb2f3 100644 --- a/crates/api_models/src/analytics/payments.rs +++ b/crates/api_models/src/analytics/payments.rs @@ -22,6 +22,8 @@ pub struct PaymentFilters { pub payment_method: Vec, #[serde(default)] pub payment_method_type: Vec, + #[serde(default)] + pub merchant_id: Vec, } #[derive( @@ -53,6 +55,9 @@ pub enum PaymentDimensions { #[strum(serialize = "status")] #[serde(rename = "status")] PaymentStatus, + #[strum(serialize = "merchant_id")] + #[serde(rename = "merchant_id")] + MerchantId, } #[derive( diff --git a/crates/api_models/src/user_role.rs b/crates/api_models/src/user_role.rs index 25c1c5ecd40..81e5f8907d9 100644 --- a/crates/api_models/src/user_role.rs +++ b/crates/api_models/src/user_role.rs @@ -35,6 +35,7 @@ pub enum Permission { PayoutWrite, PayoutRead, WebhookEventWrite, + OrgAnalytics, } #[derive(Debug, serde::Serialize)] diff --git a/crates/router/src/analytics.rs b/crates/router/src/analytics.rs index 0aec94c205c..f22c2c6b963 100644 --- a/crates/router/src/analytics.rs +++ b/crates/router/src/analytics.rs @@ -25,7 +25,7 @@ pub mod routes { routes::AppState, services::{ api, - authentication::{self as auth, AuthenticationData}, + authentication::{self as auth, AuthenticationData, AuthenticationDataOrg}, authorization::permissions::Permission, ApplicationResponse, }, @@ -154,11 +154,12 @@ pub mod routes { state, &req, payload, - |state, auth: AuthenticationData, req, _| async move { + |state, auth: AuthenticationDataOrg, req, _| async move { analytics::payments::get_metrics( &state.pool, &auth.merchant_account.merchant_id, req, + &auth.org_merchant_ids, ) .await .map(ApplicationResponse::Json) @@ -190,11 +191,12 @@ pub mod routes { state, &req, payload, - |state, auth: AuthenticationData, req, _| async move { + |state, auth: AuthenticationDataOrg, req, _| async move { analytics::refunds::get_metrics( &state.pool, &auth.merchant_account.merchant_id, req, + &auth.org_merchant_ids, ) .await .map(ApplicationResponse::Json) @@ -247,16 +249,18 @@ pub mod routes { json_payload: web::Json, ) -> impl Responder { let flow = AnalyticsFlow::GetPaymentFilters; + Box::pin(api::server_wrap( flow, state, &req, json_payload.into_inner(), - |state, auth: AuthenticationData, req, _| async move { + |state, auth: AuthenticationDataOrg, req, _| async move { analytics::payments::get_filters( &state.pool, req, &auth.merchant_account.merchant_id, + &auth.org_merchant_ids, ) .await .map(ApplicationResponse::Json) diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 30c3ce164e2..259b8fad5e4 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -948,6 +948,7 @@ pub enum AuthFlow { skip(request, payload, state, func, api_auth, request_state), fields(merchant_id) )] + pub async fn server_wrap_util<'a, 'b, U, T, Q, F, Fut, E, OErr>( flow: &'a impl router_env::types::FlowMetric, state: web::Data, diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index 8652f51451a..42e02c67e74 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -45,6 +45,13 @@ pub struct AuthenticationData { pub key_store: domain::MerchantKeyStore, } +#[derive(Clone, Debug)] +pub struct AuthenticationDataOrg { + pub merchant_account: domain::MerchantAccount, + pub key_store: domain::MerchantKeyStore, + pub org_merchant_ids: Vec, +} + #[derive(Clone, Debug, Eq, PartialEq, Serialize)] #[serde( tag = "api_auth_type", @@ -704,6 +711,77 @@ where decode_jwt(&token, state).await } +#[async_trait] +impl AuthenticateAndFetch for JWTAuth +where + A: AppStateInfo + Sync, +{ + async fn authenticate_and_fetch( + &self, + request_headers: &HeaderMap, + state: &A, + ) -> RouterResult<(AuthenticationDataOrg, AuthenticationType)> { + let payload = parse_jwt_payload::(request_headers, state).await?; + if payload.check_in_blacklist(state).await? { + return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); + } + + let permissions = authorization::get_permissions(state, &payload).await?; + authorization::check_authorization(&self.0, &permissions)?; + logger::debug!("{:?} PERMISSIONS PERMISSIONS", permissions); + let org_id = payload.org_id; + + let key_store = state + .store() + .get_merchant_key_store_by_merchant_id( + &payload.merchant_id, + &state.store().get_master_key().to_vec().into(), + ) + .await + .change_context(errors::ApiErrorResponse::InvalidJwtToken) + .attach_printable("Failed to fetch merchant key store for the merchant id")?; + //get merchant ids for above org_id + let merchant = state + .store() + .find_merchant_account_by_merchant_id(&payload.merchant_id, &key_store) + .await + .change_context(errors::ApiErrorResponse::InvalidJwtToken)?; + let organization = state + .store() + .list_merchant_accounts_by_organization_id(&org_id) + .await + .change_context(errors::ApiErrorResponse::InvalidJwtToken)?; + let org_merchant_ids: Vec = permissions + .iter() + .filter_map(|permission| match permission { + Permission::OrgAnalytics => Some( + organization + .iter() + .map(|org| org.merchant_id.clone()) + .collect(), + ), + _ => None, + }) + .next() + .unwrap_or_else(|| vec![merchant.merchant_id.clone()]); + println!("{:?} AUTH ORG MECHANT IDS", org_merchant_ids); + + let auth = AuthenticationDataOrg { + merchant_account: merchant, + key_store, + org_merchant_ids, + }; + + Ok(( + auth.clone(), + AuthenticationType::MerchantJwt { + merchant_id: auth.merchant_account.merchant_id.clone(), + user_id: None, + }, + )) + } +} + #[async_trait] impl AuthenticateAndFetch for JWTAuth where @@ -714,6 +792,7 @@ where request_headers: &HeaderMap, state: &A, ) -> RouterResult<(AuthenticationData, AuthenticationType)> { + let a = self.0; let payload = parse_jwt_payload::(request_headers, state).await?; if payload.check_in_blacklist(state).await? { return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); diff --git a/crates/router/src/services/authorization/permission_groups.rs b/crates/router/src/services/authorization/permission_groups.rs index f3275a78fd0..b9a2cb2b4ef 100644 --- a/crates/router/src/services/authorization/permission_groups.rs +++ b/crates/router/src/services/authorization/permission_groups.rs @@ -84,7 +84,8 @@ pub static MERCHANT_DETAILS_MANAGE: [Permission; 6] = [ Permission::WebhookEventWrite, ]; -pub static ORGANIZATION_MANAGE: [Permission; 2] = [ +pub static ORGANIZATION_MANAGE: [Permission; 3] = [ Permission::MerchantAccountCreate, Permission::MerchantAccountRead, + Permission::OrgAnalytics, ]; diff --git a/crates/router/src/services/authorization/permissions.rs b/crates/router/src/services/authorization/permissions.rs index 583b22fe86c..de83b18fa14 100644 --- a/crates/router/src/services/authorization/permissions.rs +++ b/crates/router/src/services/authorization/permissions.rs @@ -34,6 +34,7 @@ pub enum Permission { WebhookEventWrite, PayoutRead, PayoutWrite, + OrgAnalytics, } impl Permission { @@ -75,6 +76,7 @@ impl Permission { Self::WebhookEventWrite => "Trigger retries for webhook events", Self::PayoutRead => "View all payouts", Self::PayoutWrite => "Create payout, download payout data", + Self::OrgAnalytics => "View Organization level analytics", } } } diff --git a/crates/router/src/utils/user_role.rs b/crates/router/src/utils/user_role.rs index ba4c2878667..f81a103c53d 100644 --- a/crates/router/src/utils/user_role.rs +++ b/crates/router/src/utils/user_role.rs @@ -47,6 +47,7 @@ impl From for user_role_api::Permission { Permission::WebhookEventWrite => Self::WebhookEventWrite, Permission::PayoutRead => Self::PayoutRead, Permission::PayoutWrite => Self::PayoutWrite, + Permission::OrgAnalytics => Self::OrgAnalytics, } } } From 095ef33685d5860e62e82c404c7c0f63fa8057d8 Mon Sep 17 00:00:00 2001 From: Jeeva Ramachandran Date: Fri, 3 May 2024 13:21:35 +0530 Subject: [PATCH 2/7] organazation analytics --- crates/analytics/src/lib.rs | 23 +++++--------- crates/analytics/src/payments/core.rs | 31 +++++-------------- crates/analytics/src/payments/distribution.rs | 6 ++-- .../distribution/payment_error_message.rs | 4 +-- crates/analytics/src/payments/filters.rs | 3 +- crates/analytics/src/payments/metrics.rs | 15 +++------ .../src/payments/metrics/avg_ticket_size.rs | 7 ++--- .../metrics/connector_success_rate.rs | 6 +--- .../src/payments/metrics/payment_count.rs | 6 +--- .../metrics/payment_processed_amount.rs | 6 +--- .../payments/metrics/payment_success_count.rs | 6 +--- .../src/payments/metrics/retries_count.rs | 6 +--- .../src/payments/metrics/success_rate.rs | 6 +--- crates/analytics/src/refunds/core.rs | 1 - crates/router/src/analytics.rs | 23 ++++---------- crates/router/src/services/authentication.rs | 2 -- 16 files changed, 40 insertions(+), 111 deletions(-) diff --git a/crates/analytics/src/lib.rs b/crates/analytics/src/lib.rs index 2d886a21fc2..8d4a944a87e 100644 --- a/crates/analytics/src/lib.rs +++ b/crates/analytics/src/lib.rs @@ -94,11 +94,10 @@ impl AnalyticsProvider { &self, metric: &PaymentMetrics, dimensions: &[PaymentDimensions], - merchant_id: &str, filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, - merchant_ids: &Vec, + merchant_ids: &[String], ) -> types::MetricsResult> { // Metrics to get the fetch time for each payment metric metrics::request::record_operation_time( @@ -108,7 +107,6 @@ impl AnalyticsProvider { metric .load_metrics( dimensions, - merchant_id, filters, granularity, time_range, @@ -121,7 +119,6 @@ impl AnalyticsProvider { metric .load_metrics( dimensions, - merchant_id, filters, granularity, time_range, @@ -134,7 +131,6 @@ impl AnalyticsProvider { let (ckh_result, sqlx_result) = tokio::join!(metric .load_metrics( dimensions, - merchant_id, filters, granularity, time_range, @@ -144,7 +140,6 @@ impl AnalyticsProvider { metric .load_metrics( dimensions, - merchant_id, filters, granularity, time_range, @@ -165,7 +160,6 @@ impl AnalyticsProvider { let (ckh_result, sqlx_result) = tokio::join!(metric .load_metrics( dimensions, - merchant_id, filters, granularity, time_range, @@ -175,7 +169,6 @@ impl AnalyticsProvider { metric .load_metrics( dimensions, - merchant_id, filters, granularity, time_range, @@ -205,7 +198,7 @@ impl AnalyticsProvider { &self, distribution: &Distribution, dimensions: &[PaymentDimensions], - merchant_id: &str, + merchant_ids: &[String], filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, @@ -219,7 +212,7 @@ impl AnalyticsProvider { .load_distribution( distribution, dimensions, - merchant_id, + merchant_ids, filters, granularity, time_range, @@ -232,7 +225,7 @@ impl AnalyticsProvider { .load_distribution( distribution, dimensions, - merchant_id, + merchant_ids, filters, granularity, time_range, @@ -245,7 +238,7 @@ impl AnalyticsProvider { .load_distribution( distribution, dimensions, - merchant_id, + merchant_ids, filters, granularity, time_range, @@ -255,7 +248,7 @@ impl AnalyticsProvider { .load_distribution( distribution, dimensions, - merchant_id, + merchant_ids, filters, granularity, time_range, @@ -276,7 +269,7 @@ impl AnalyticsProvider { .load_distribution( distribution, dimensions, - merchant_id, + merchant_ids, filters, granularity, time_range, @@ -286,7 +279,7 @@ impl AnalyticsProvider { .load_distribution( distribution, dimensions, - merchant_id, + merchant_ids, filters, granularity, time_range, diff --git a/crates/analytics/src/payments/core.rs b/crates/analytics/src/payments/core.rs index e4aa7a730a4..28d135994ab 100644 --- a/crates/analytics/src/payments/core.rs +++ b/crates/analytics/src/payments/core.rs @@ -41,10 +41,7 @@ pub enum TaskType { ), } -fn compare_and_return_matching( - org_merchant_ids: &Vec, - payload: &Vec, -) -> Vec { +fn compare_and_return_matching(org_merchant_ids: &Vec, payload: &[String]) -> Vec { let mut matching_values = vec![]; for m in org_merchant_ids { @@ -64,18 +61,15 @@ fn compare_and_return_matching( #[instrument(skip_all)] pub async fn get_metrics( pool: &AnalyticsProvider, - merchant_id: &str, + req: GetPaymentMetricRequest, merchant_ids: &Vec, ) -> AnalyticsResult> { - println!("{:?}ORG MERCHANT_IDSSS", merchant_ids); let org_merchant_ids = compare_and_return_matching(merchant_ids, &req.filters.merchant_id); - println!("{:?}MERCHANT_IDSSS", org_merchant_ids); let mut metrics_accumulator: HashMap< PaymentMetricsBucketIdentifier, PaymentMetricsAccumulator, > = HashMap::new(); - // println!("{:?} List of Merchant ID", merchant_ids); let mut set = tokio::task::JoinSet::new(); for metric_type in req.metrics.iter().cloned() { let req = req.clone(); @@ -87,7 +81,7 @@ pub async fn get_metrics( // TODO: lifetime issues with joinset, // can be optimized away if joinset lifetime requirements are relaxed - let merchant_id_scoped = merchant_id.to_owned(); + let merchant_ids = org_merchant_ids.to_owned(); set.spawn( async move { @@ -95,7 +89,6 @@ pub async fn get_metrics( .get_payment_metrics( &metric_type, &req.group_by_names.clone(), - &merchant_id_scoped, &req.filters, &req.time_series.map(|t| t.granularity), &req.time_range, @@ -117,14 +110,14 @@ pub async fn get_metrics( payment_distribution = distribution.distribution_for.as_ref() ); - let merchant_id_scoped = merchant_id.to_owned(); + let merchant_ids = org_merchant_ids.to_owned(); set.spawn( async move { let data = pool .get_payment_distribution( &distribution, &req.group_by_names.clone(), - &merchant_id_scoped, + &merchant_ids, &req.filters, &req.time_series.map(|t| t.granularity), &req.time_range, @@ -247,28 +240,23 @@ pub async fn get_metrics( pub async fn get_filters( pool: &AnalyticsProvider, req: GetPaymentFiltersRequest, - merchant_id: &String, - merchant_ids: &Vec, + merchant_ids: &[String], ) -> AnalyticsResult { - println!("{:?} merchant_id merchant_id FG LOF", merchant_id); - // println!("{:?} merchant_id list", list_merchant_id); - let mut res = PaymentFiltersResponse::default(); for dim in req.group_by_names { let values = match pool { AnalyticsProvider::Sqlx(pool) => { - get_payment_filter_for_dimension(dim, merchant_id, &req.time_range, pool,merchant_ids) + get_payment_filter_for_dimension(dim, &req.time_range, pool,merchant_ids) .await } AnalyticsProvider::Clickhouse(pool) => { - get_payment_filter_for_dimension(dim, merchant_id, &req.time_range, pool,merchant_ids) + get_payment_filter_for_dimension(dim, &req.time_range, pool,merchant_ids) .await } AnalyticsProvider::CombinedCkh(sqlx_poll, ckh_pool) => { let ckh_result = get_payment_filter_for_dimension( dim, - merchant_id, &req.time_range, ckh_pool, merchant_ids @@ -276,7 +264,6 @@ pub async fn get_filters( .await; let sqlx_result = get_payment_filter_for_dimension( dim, - merchant_id, &req.time_range, sqlx_poll, merchant_ids @@ -293,7 +280,6 @@ pub async fn get_filters( AnalyticsProvider::CombinedSqlx(sqlx_poll, ckh_pool) => { let ckh_result = get_payment_filter_for_dimension( dim, - merchant_id, &req.time_range, ckh_pool, merchant_ids @@ -301,7 +287,6 @@ pub async fn get_filters( .await; let sqlx_result = get_payment_filter_for_dimension( dim, - merchant_id, &req.time_range, sqlx_poll, merchant_ids diff --git a/crates/analytics/src/payments/distribution.rs b/crates/analytics/src/payments/distribution.rs index cf18c26310a..91cea8d4a15 100644 --- a/crates/analytics/src/payments/distribution.rs +++ b/crates/analytics/src/payments/distribution.rs @@ -45,7 +45,7 @@ where &self, distribution: &Distribution, dimensions: &[PaymentDimensions], - merchant_id: &str, + merchant_ids: &[String], filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, @@ -67,7 +67,7 @@ where &self, distribution: &Distribution, dimensions: &[PaymentDimensions], - merchant_id: &str, + merchant_ids: &[String], filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, @@ -79,7 +79,7 @@ where .load_distribution( distribution, dimensions, - merchant_id, + merchant_ids, filters, granularity, time_range, diff --git a/crates/analytics/src/payments/distribution/payment_error_message.rs b/crates/analytics/src/payments/distribution/payment_error_message.rs index c70fc09aeac..2df7b737493 100644 --- a/crates/analytics/src/payments/distribution/payment_error_message.rs +++ b/crates/analytics/src/payments/distribution/payment_error_message.rs @@ -32,7 +32,7 @@ where &self, distribution: &Distribution, dimensions: &[PaymentDimensions], - merchant_id: &str, + merchant_ids: &[String], filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, @@ -70,7 +70,7 @@ where filters.set_filter_clause(&mut query_builder).switch()?; query_builder - .add_filter_clause("merchant_id", merchant_id) + .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; time_range diff --git a/crates/analytics/src/payments/filters.rs b/crates/analytics/src/payments/filters.rs index 6c9eb94d708..e9b6361411a 100644 --- a/crates/analytics/src/payments/filters.rs +++ b/crates/analytics/src/payments/filters.rs @@ -16,10 +16,9 @@ pub trait PaymentFilterAnalytics: LoadRow {} pub async fn get_payment_filter_for_dimension( dimension: PaymentDimensions, - merchant: &String, time_range: &TimeRange, pool: &T, - merchant_ids: &Vec, + merchant_ids: &[String], ) -> FiltersResult> where T: AnalyticsDataSource + PaymentFilterAnalytics, diff --git a/crates/analytics/src/payments/metrics.rs b/crates/analytics/src/payments/metrics.rs index 0c498202c77..b1ec03f54a3 100644 --- a/crates/analytics/src/payments/metrics.rs +++ b/crates/analytics/src/payments/metrics.rs @@ -53,12 +53,12 @@ where async fn load_metrics( &self, dimensions: &[PaymentDimensions], - merchant_id: &str, + filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, pool: &T, - merchant_ids: &Vec, + merchant_ids: &[String], ) -> MetricsResult>; } @@ -75,19 +75,18 @@ where async fn load_metrics( &self, dimensions: &[PaymentDimensions], - merchant_id: &str, + filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, pool: &T, - merchant_ids: &Vec, + merchant_ids: &[String], ) -> MetricsResult> { match self { Self::PaymentSuccessRate => { PaymentSuccessRate .load_metrics( dimensions, - merchant_id, filters, granularity, time_range, @@ -100,7 +99,6 @@ where PaymentCount .load_metrics( dimensions, - merchant_id, filters, granularity, time_range, @@ -113,7 +111,6 @@ where PaymentSuccessCount .load_metrics( dimensions, - merchant_id, filters, granularity, time_range, @@ -126,7 +123,6 @@ where PaymentProcessedAmount .load_metrics( dimensions, - merchant_id, filters, granularity, time_range, @@ -139,7 +135,6 @@ where AvgTicketSize .load_metrics( dimensions, - merchant_id, filters, granularity, time_range, @@ -152,7 +147,6 @@ where RetriesCount .load_metrics( dimensions, - merchant_id, filters, granularity, time_range, @@ -165,7 +159,6 @@ where ConnectorSuccessRate .load_metrics( dimensions, - merchant_id, filters, granularity, time_range, diff --git a/crates/analytics/src/payments/metrics/avg_ticket_size.rs b/crates/analytics/src/payments/metrics/avg_ticket_size.rs index 75ccac2ee07..1f0ecb40c45 100644 --- a/crates/analytics/src/payments/metrics/avg_ticket_size.rs +++ b/crates/analytics/src/payments/metrics/avg_ticket_size.rs @@ -29,12 +29,12 @@ where async fn load_metrics( &self, dimensions: &[PaymentDimensions], - merchant_id: &str, + filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, pool: &T, - merchant_ids: &Vec, + merchant_ids: &[String], ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::Payment); @@ -69,9 +69,6 @@ where filters.set_filter_clause(&mut query_builder).switch()?; - // query_builder - // .add_filter_clause("merchant_id", merchant_id) - // .switch()?; query_builder .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; diff --git a/crates/analytics/src/payments/metrics/connector_success_rate.rs b/crates/analytics/src/payments/metrics/connector_success_rate.rs index 18bf6961c79..2871fa8ea79 100644 --- a/crates/analytics/src/payments/metrics/connector_success_rate.rs +++ b/crates/analytics/src/payments/metrics/connector_success_rate.rs @@ -31,12 +31,11 @@ where async fn load_metrics( &self, dimensions: &[PaymentDimensions], - merchant_id: &str, filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, pool: &T, - merchant_ids: &Vec, + merchant_ids: &[String], ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::Payment); let mut dimensions = dimensions.to_vec(); @@ -68,9 +67,6 @@ where filters.set_filter_clause(&mut query_builder).switch()?; - // query_builder - // .add_filter_clause("merchant_id", merchant_id) - // .switch()?; query_builder .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; diff --git a/crates/analytics/src/payments/metrics/payment_count.rs b/crates/analytics/src/payments/metrics/payment_count.rs index 4f57d1bea9b..ae39fb2e939 100644 --- a/crates/analytics/src/payments/metrics/payment_count.rs +++ b/crates/analytics/src/payments/metrics/payment_count.rs @@ -28,12 +28,11 @@ where async fn load_metrics( &self, dimensions: &[PaymentDimensions], - merchant_id: &str, filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, pool: &T, - merchant_ids: &Vec, + merchant_ids: &[String], ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::Payment); @@ -62,9 +61,6 @@ where filters.set_filter_clause(&mut query_builder).switch()?; - // query_builder - // .add_filter_clause("merchant_id", merchant_id) - // .switch()?; query_builder .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; diff --git a/crates/analytics/src/payments/metrics/payment_processed_amount.rs b/crates/analytics/src/payments/metrics/payment_processed_amount.rs index 55438403bce..5c0df9b03e2 100644 --- a/crates/analytics/src/payments/metrics/payment_processed_amount.rs +++ b/crates/analytics/src/payments/metrics/payment_processed_amount.rs @@ -29,12 +29,11 @@ where async fn load_metrics( &self, dimensions: &[PaymentDimensions], - merchant_id: &str, filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, pool: &T, - merchant_ids: &Vec, + merchant_ids: &[String], ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::Payment); @@ -63,9 +62,6 @@ where filters.set_filter_clause(&mut query_builder).switch()?; - // query_builder - // .add_filter_clause("merchant_id", merchant_id) - // .switch()?; query_builder .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; diff --git a/crates/analytics/src/payments/metrics/payment_success_count.rs b/crates/analytics/src/payments/metrics/payment_success_count.rs index 1aaba5c2f32..64d8f947fab 100644 --- a/crates/analytics/src/payments/metrics/payment_success_count.rs +++ b/crates/analytics/src/payments/metrics/payment_success_count.rs @@ -29,12 +29,11 @@ where async fn load_metrics( &self, dimensions: &[PaymentDimensions], - merchant_id: &str, filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, pool: &T, - merchant_ids: &Vec, + merchant_ids: &[String], ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::Payment); @@ -63,9 +62,6 @@ where filters.set_filter_clause(&mut query_builder).switch()?; - // query_builder - // .add_filter_clause("merchant_id", merchant_id) - // .switch()?; query_builder .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; diff --git a/crates/analytics/src/payments/metrics/retries_count.rs b/crates/analytics/src/payments/metrics/retries_count.rs index fc89f848848..96388c82c09 100644 --- a/crates/analytics/src/payments/metrics/retries_count.rs +++ b/crates/analytics/src/payments/metrics/retries_count.rs @@ -31,12 +31,11 @@ where async fn load_metrics( &self, _dimensions: &[PaymentDimensions], - merchant_id: &str, _filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, pool: &T, - merchant_ids: &Vec, + merchant_ids: &[String], ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::PaymentIntent); @@ -64,9 +63,6 @@ where alias: Some("end_bucket"), }) .switch()?; - // query_builder - // .add_filter_clause("merchant_id", merchant_id) - // .switch()?; query_builder .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; diff --git a/crates/analytics/src/payments/metrics/success_rate.rs b/crates/analytics/src/payments/metrics/success_rate.rs index c1be7ad3549..f0c3d11597d 100644 --- a/crates/analytics/src/payments/metrics/success_rate.rs +++ b/crates/analytics/src/payments/metrics/success_rate.rs @@ -28,12 +28,11 @@ where async fn load_metrics( &self, dimensions: &[PaymentDimensions], - merchant_id: &str, filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, pool: &T, - merchant_ids: &Vec, + merchant_ids: &[String], ) -> MetricsResult> { let mut query_builder: QueryBuilder = QueryBuilder::new(AnalyticsCollection::Payment); let mut dimensions = dimensions.to_vec(); @@ -65,9 +64,6 @@ where filters.set_filter_clause(&mut query_builder).switch()?; - // query_builder - // .add_filter_clause("merchant_id", merchant_id) - // .switch()?; query_builder .add_filter_in_range_clause("merchant_id", merchant_ids) .switch()?; diff --git a/crates/analytics/src/refunds/core.rs b/crates/analytics/src/refunds/core.rs index eeb23aae1eb..b53d482e620 100644 --- a/crates/analytics/src/refunds/core.rs +++ b/crates/analytics/src/refunds/core.rs @@ -29,7 +29,6 @@ pub async fn get_metrics( pool: &AnalyticsProvider, merchant_id: &String, req: GetRefundMetricRequest, - list_merchant_id: &Vec, ) -> AnalyticsResult> { let mut metrics_accumulator: HashMap = HashMap::new(); diff --git a/crates/router/src/analytics.rs b/crates/router/src/analytics.rs index f22c2c6b963..fa353ba37f9 100644 --- a/crates/router/src/analytics.rs +++ b/crates/router/src/analytics.rs @@ -155,14 +155,9 @@ pub mod routes { &req, payload, |state, auth: AuthenticationDataOrg, req, _| async move { - analytics::payments::get_metrics( - &state.pool, - &auth.merchant_account.merchant_id, - req, - &auth.org_merchant_ids, - ) - .await - .map(ApplicationResponse::Json) + analytics::payments::get_metrics(&state.pool, req, &auth.org_merchant_ids) + .await + .map(ApplicationResponse::Json) }, &auth::JWTAuth(Permission::Analytics), api_locking::LockAction::NotApplicable, @@ -196,7 +191,6 @@ pub mod routes { &state.pool, &auth.merchant_account.merchant_id, req, - &auth.org_merchant_ids, ) .await .map(ApplicationResponse::Json) @@ -256,14 +250,9 @@ pub mod routes { &req, json_payload.into_inner(), |state, auth: AuthenticationDataOrg, req, _| async move { - analytics::payments::get_filters( - &state.pool, - req, - &auth.merchant_account.merchant_id, - &auth.org_merchant_ids, - ) - .await - .map(ApplicationResponse::Json) + analytics::payments::get_filters(&state.pool, req, &auth.org_merchant_ids) + .await + .map(ApplicationResponse::Json) }, &auth::JWTAuth(Permission::Analytics), api_locking::LockAction::NotApplicable, diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index 42e02c67e74..a2a46cee78b 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -728,7 +728,6 @@ where let permissions = authorization::get_permissions(state, &payload).await?; authorization::check_authorization(&self.0, &permissions)?; - logger::debug!("{:?} PERMISSIONS PERMISSIONS", permissions); let org_id = payload.org_id; let key_store = state @@ -792,7 +791,6 @@ where request_headers: &HeaderMap, state: &A, ) -> RouterResult<(AuthenticationData, AuthenticationType)> { - let a = self.0; let payload = parse_jwt_payload::(request_headers, state).await?; if payload.check_in_blacklist(state).await? { return Err(errors::ApiErrorResponse::InvalidJwtToken.into()); From 5dbe5937075692c2d797198e85ba49c5a09144e2 Mon Sep 17 00:00:00 2001 From: Jeeva Ramachandran Date: Fri, 3 May 2024 13:23:21 +0530 Subject: [PATCH 3/7] organazation analytics --- crates/analytics/src/payments/metrics.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/analytics/src/payments/metrics.rs b/crates/analytics/src/payments/metrics.rs index b1ec03f54a3..98c16d03e89 100644 --- a/crates/analytics/src/payments/metrics.rs +++ b/crates/analytics/src/payments/metrics.rs @@ -53,7 +53,6 @@ where async fn load_metrics( &self, dimensions: &[PaymentDimensions], - filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, @@ -75,7 +74,6 @@ where async fn load_metrics( &self, dimensions: &[PaymentDimensions], - filters: &PaymentFilters, granularity: &Option, time_range: &TimeRange, From f492ef1eaa2e6bed97d292aa0637d49a51b6339d Mon Sep 17 00:00:00 2001 From: Jeeva Ramachandran Date: Fri, 3 May 2024 13:26:04 +0530 Subject: [PATCH 4/7] organazation analytics --- crates/router/src/analytics.rs | 1 - crates/router/src/services/api.rs | 1 - crates/router/src/services/authentication.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/crates/router/src/analytics.rs b/crates/router/src/analytics.rs index fa353ba37f9..1a14b50ab66 100644 --- a/crates/router/src/analytics.rs +++ b/crates/router/src/analytics.rs @@ -243,7 +243,6 @@ pub mod routes { json_payload: web::Json, ) -> impl Responder { let flow = AnalyticsFlow::GetPaymentFilters; - Box::pin(api::server_wrap( flow, state, diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 259b8fad5e4..30c3ce164e2 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -948,7 +948,6 @@ pub enum AuthFlow { skip(request, payload, state, func, api_auth, request_state), fields(merchant_id) )] - pub async fn server_wrap_util<'a, 'b, U, T, Q, F, Fut, E, OErr>( flow: &'a impl router_env::types::FlowMetric, state: web::Data, diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index a2a46cee78b..27dbe920172 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -763,7 +763,6 @@ where }) .next() .unwrap_or_else(|| vec![merchant.merchant_id.clone()]); - println!("{:?} AUTH ORG MECHANT IDS", org_merchant_ids); let auth = AuthenticationDataOrg { merchant_account: merchant, From c198235f96737f51b57539ffeec2967d91c8d1ca Mon Sep 17 00:00:00 2001 From: Jeeva Ramachandran Date: Fri, 3 May 2024 18:20:50 +0530 Subject: [PATCH 5/7] chore: analytics table url fix --- crates/analytics/src/payments/core.rs | 17 +++++++---------- crates/analytics/src/payments/distribution.rs | 1 + crates/analytics/src/payments/metrics.rs | 1 + crates/analytics/src/sqlx.rs | 10 ++++++++++ 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/crates/analytics/src/payments/core.rs b/crates/analytics/src/payments/core.rs index 28d135994ab..013141bd272 100644 --- a/crates/analytics/src/payments/core.rs +++ b/crates/analytics/src/payments/core.rs @@ -41,15 +41,12 @@ pub enum TaskType { ), } -fn compare_and_return_matching(org_merchant_ids: &Vec, payload: &[String]) -> Vec { - let mut matching_values = vec![]; - - for m in org_merchant_ids { - let t = m.clone(); - if payload.contains(&t) { - matching_values.push(t); - } - } +fn compare_and_return_matching(org_merchant_ids: &[String], payload: &[String]) -> Vec { + let matching_values: Vec = payload + .iter() + .filter(|i| org_merchant_ids.contains(i)) + .cloned() + .collect(); if matching_values.is_empty() { org_merchant_ids.to_vec() @@ -63,7 +60,7 @@ pub async fn get_metrics( pool: &AnalyticsProvider, req: GetPaymentMetricRequest, - merchant_ids: &Vec, + merchant_ids: &[String], ) -> AnalyticsResult> { let org_merchant_ids = compare_and_return_matching(merchant_ids, &req.filters.merchant_id); let mut metrics_accumulator: HashMap< diff --git a/crates/analytics/src/payments/distribution.rs b/crates/analytics/src/payments/distribution.rs index 91cea8d4a15..a0a0fd318d2 100644 --- a/crates/analytics/src/payments/distribution.rs +++ b/crates/analytics/src/payments/distribution.rs @@ -31,6 +31,7 @@ pub struct PaymentDistributionRow { pub start_bucket: Option, #[serde(with = "common_utils::custom_serde::iso8601::option")] pub end_bucket: Option, + pub merchant_id: Option, } pub trait PaymentDistributionAnalytics: LoadRow {} diff --git a/crates/analytics/src/payments/metrics.rs b/crates/analytics/src/payments/metrics.rs index 98c16d03e89..2b431931a04 100644 --- a/crates/analytics/src/payments/metrics.rs +++ b/crates/analytics/src/payments/metrics.rs @@ -41,6 +41,7 @@ pub struct PaymentMetricRow { pub start_bucket: Option, #[serde(with = "common_utils::custom_serde::iso8601::option")] pub end_bucket: Option, + pub merchant_id: Option, } pub trait PaymentMetricAnalytics: LoadRow {} diff --git a/crates/analytics/src/sqlx.rs b/crates/analytics/src/sqlx.rs index 756a3ca0f15..ea9e95cb821 100644 --- a/crates/analytics/src/sqlx.rs +++ b/crates/analytics/src/sqlx.rs @@ -268,6 +268,10 @@ impl<'a> FromRow<'a, PgRow> for super::payments::metrics::PaymentMetricRow { ColumnNotFound(_) => Ok(Default::default()), e => Err(e), })?; + let merchant_id: Option = row.try_get("merchant_id").or_else(|e| match e { + ColumnNotFound(_) => Ok(Default::default()), + e => Err(e), + })?; // Removing millisecond precision to get accurate diffs against clickhouse let start_bucket: Option = row .try_get::, _>("start_bucket")? @@ -286,6 +290,7 @@ impl<'a> FromRow<'a, PgRow> for super::payments::metrics::PaymentMetricRow { count, start_bucket, end_bucket, + merchant_id, }) } } @@ -340,6 +345,10 @@ impl<'a> FromRow<'a, PgRow> for super::payments::distribution::PaymentDistributi let end_bucket: Option = row .try_get::, _>("end_bucket")? .and_then(|dt| dt.replace_millisecond(0).ok()); + let merchant_id: Option = row.try_get("merchant_id").or_else(|e| match e { + ColumnNotFound(_) => Ok(Default::default()), + e => Err(e), + })?; Ok(Self { currency, status, @@ -352,6 +361,7 @@ impl<'a> FromRow<'a, PgRow> for super::payments::distribution::PaymentDistributi error_message, start_bucket, end_bucket, + merchant_id, }) } } From fba566bf874c0d4fc115a34f77507ef1882f017f Mon Sep 17 00:00:00 2001 From: Jeeva Ramachandran Date: Mon, 6 May 2024 12:17:34 +0530 Subject: [PATCH 6/7] address comments --- crates/router/src/services/authentication.rs | 35 ++++++++++---------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index 258c64be6de..26a14ad905d 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -696,24 +696,25 @@ where .find_merchant_account_by_merchant_id(&payload.merchant_id, &key_store) .await .change_context(errors::ApiErrorResponse::InvalidJwtToken)?; - let organization = state - .store() - .list_merchant_accounts_by_organization_id(&org_id) - .await - .change_context(errors::ApiErrorResponse::InvalidJwtToken)?; - let org_merchant_ids: Vec = permissions + + let org_merchant_ids: Vec = match permissions .iter() - .filter_map(|permission| match permission { - Permission::OrgAnalytics => Some( - organization - .iter() - .map(|org| org.merchant_id.clone()) - .collect(), - ), - _ => None, - }) - .next() - .unwrap_or_else(|| vec![merchant.merchant_id.clone()]); + .find(|&permission| *permission == Permission::OrgAnalytics) + { + Some(_) => { + let organization = state + .store() + .list_merchant_accounts_by_organization_id(&org_id) + .await + .change_context(errors::ApiErrorResponse::InvalidJwtToken)?; + + organization + .iter() + .map(|org| org.merchant_id.clone()) + .collect() + } + None => vec![merchant.merchant_id.clone()], + }; let auth = AuthenticationDataOrg { merchant_account: merchant, From 7105be41dbca055aa9f79d56b833fd5ba0fca3e4 Mon Sep 17 00:00:00 2001 From: Jeeva Ramachandran Date: Mon, 6 May 2024 12:20:37 +0530 Subject: [PATCH 7/7] add comments --- crates/router/src/services/authentication.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index 26a14ad905d..6c67a7ff6b7 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -690,13 +690,13 @@ where .await .change_context(errors::ApiErrorResponse::InvalidJwtToken) .attach_printable("Failed to fetch merchant key store for the merchant id")?; - //get merchant ids for above org_id + let merchant = state .store() .find_merchant_account_by_merchant_id(&payload.merchant_id, &key_store) .await .change_context(errors::ApiErrorResponse::InvalidJwtToken)?; - + //get merchant ids if the user is org admin or return with default merchant id let org_merchant_ids: Vec = match permissions .iter() .find(|&permission| *permission == Permission::OrgAnalytics)