From 9d03bd1ea61c6ce296b089522a8b9331773a278f Mon Sep 17 00:00:00 2001 From: T Sandeep Kumar Date: Wed, 8 Jan 2025 11:20:33 +0530 Subject: [PATCH] feat(analytics): Add currency as dimension and filter for disputes --- crates/analytics/src/disputes/core.rs | 1 + crates/analytics/src/disputes/filters.rs | 7 ++++++- crates/analytics/src/disputes/metrics.rs | 1 + .../src/disputes/metrics/dispute_status_metric.rs | 1 + .../sessionized_metrics/dispute_status_metric.rs | 1 + .../sessionized_metrics/total_amount_disputed.rs | 1 + .../sessionized_metrics/total_dispute_lost_amount.rs | 1 + .../src/disputes/metrics/total_amount_disputed.rs | 1 + .../disputes/metrics/total_dispute_lost_amount.rs | 1 + crates/analytics/src/disputes/types.rs | 6 ++++++ crates/analytics/src/sqlx.rs | 12 ++++++++++++ crates/api_models/src/analytics/disputes.rs | 10 +++++++++- 12 files changed, 41 insertions(+), 2 deletions(-) diff --git a/crates/analytics/src/disputes/core.rs b/crates/analytics/src/disputes/core.rs index 540a14104c1f..c1dcbaf2b2fb 100644 --- a/crates/analytics/src/disputes/core.rs +++ b/crates/analytics/src/disputes/core.rs @@ -204,6 +204,7 @@ pub async fn get_filters( .filter_map(|fil: DisputeFilterRow| match dim { DisputeDimensions::DisputeStage => fil.dispute_stage, DisputeDimensions::Connector => fil.connector, + DisputeDimensions::Currency => fil.currency.map(|i| i.as_ref().to_string()), }) .collect::>(); res.query_data.push(DisputeFilterValue { diff --git a/crates/analytics/src/disputes/filters.rs b/crates/analytics/src/disputes/filters.rs index cd60b5022577..9e4aa3026447 100644 --- a/crates/analytics/src/disputes/filters.rs +++ b/crates/analytics/src/disputes/filters.rs @@ -1,12 +1,16 @@ use api_models::analytics::{disputes::DisputeDimensions, Granularity, TimeRange}; use common_utils::errors::ReportSwitchExt; +use diesel_models::enums::Currency; use error_stack::ResultExt; use time::PrimitiveDateTime; use crate::{ enums::AuthInfo, query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, ToSql, Window}, - types::{AnalyticsCollection, AnalyticsDataSource, FiltersError, FiltersResult, LoadRow}, + types::{ + AnalyticsCollection, AnalyticsDataSource, DBEnumWrapper, FiltersError, FiltersResult, + LoadRow, + }, }; pub trait DisputeFilterAnalytics: LoadRow {} @@ -48,4 +52,5 @@ pub struct DisputeFilterRow { pub dispute_status: Option, pub connector_status: Option, pub dispute_stage: Option, + pub currency: Option>, } diff --git a/crates/analytics/src/disputes/metrics.rs b/crates/analytics/src/disputes/metrics.rs index 6514e5fcbe0c..72bb09003d33 100644 --- a/crates/analytics/src/disputes/metrics.rs +++ b/crates/analytics/src/disputes/metrics.rs @@ -27,6 +27,7 @@ pub struct DisputeMetricRow { pub dispute_stage: Option>, pub dispute_status: Option>, pub connector: Option, + pub currency: Option>, pub total: Option, pub count: Option, #[serde(with = "common_utils::custom_serde::iso8601::option")] diff --git a/crates/analytics/src/disputes/metrics/dispute_status_metric.rs b/crates/analytics/src/disputes/metrics/dispute_status_metric.rs index ce962e284f6f..b23dba4af38c 100644 --- a/crates/analytics/src/disputes/metrics/dispute_status_metric.rs +++ b/crates/analytics/src/disputes/metrics/dispute_status_metric.rs @@ -97,6 +97,7 @@ where DisputeMetricsBucketIdentifier::new( i.dispute_stage.as_ref().map(|i| i.0), i.connector.clone(), + i.currency.as_ref().map(|i| i.0), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/disputes/metrics/sessionized_metrics/dispute_status_metric.rs b/crates/analytics/src/disputes/metrics/sessionized_metrics/dispute_status_metric.rs index 9a7b05358192..0d54d75aee56 100644 --- a/crates/analytics/src/disputes/metrics/sessionized_metrics/dispute_status_metric.rs +++ b/crates/analytics/src/disputes/metrics/sessionized_metrics/dispute_status_metric.rs @@ -97,6 +97,7 @@ where DisputeMetricsBucketIdentifier::new( i.dispute_stage.as_ref().map(|i| i.0), i.connector.clone(), + i.currency.as_ref().map(|i| i.0), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/disputes/metrics/sessionized_metrics/total_amount_disputed.rs b/crates/analytics/src/disputes/metrics/sessionized_metrics/total_amount_disputed.rs index 5c5eceb06196..bf2332ab12f2 100644 --- a/crates/analytics/src/disputes/metrics/sessionized_metrics/total_amount_disputed.rs +++ b/crates/analytics/src/disputes/metrics/sessionized_metrics/total_amount_disputed.rs @@ -98,6 +98,7 @@ where DisputeMetricsBucketIdentifier::new( i.dispute_stage.as_ref().map(|i| i.0), i.connector.clone(), + i.currency.as_ref().map(|i| i.0), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/disputes/metrics/sessionized_metrics/total_dispute_lost_amount.rs b/crates/analytics/src/disputes/metrics/sessionized_metrics/total_dispute_lost_amount.rs index d6308b09f33b..5d10becbbe29 100644 --- a/crates/analytics/src/disputes/metrics/sessionized_metrics/total_dispute_lost_amount.rs +++ b/crates/analytics/src/disputes/metrics/sessionized_metrics/total_dispute_lost_amount.rs @@ -99,6 +99,7 @@ where DisputeMetricsBucketIdentifier::new( i.dispute_stage.as_ref().map(|i| i.0), i.connector.clone(), + i.currency.as_ref().map(|i| i.0), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/disputes/metrics/total_amount_disputed.rs b/crates/analytics/src/disputes/metrics/total_amount_disputed.rs index 68c7fa6d166c..fc85ee39b261 100644 --- a/crates/analytics/src/disputes/metrics/total_amount_disputed.rs +++ b/crates/analytics/src/disputes/metrics/total_amount_disputed.rs @@ -97,6 +97,7 @@ where DisputeMetricsBucketIdentifier::new( i.dispute_stage.as_ref().map(|i| i.0), i.connector.clone(), + i.currency.as_ref().map(|i| i.0), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/disputes/metrics/total_dispute_lost_amount.rs b/crates/analytics/src/disputes/metrics/total_dispute_lost_amount.rs index d14d49827010..33228cbb58b3 100644 --- a/crates/analytics/src/disputes/metrics/total_dispute_lost_amount.rs +++ b/crates/analytics/src/disputes/metrics/total_dispute_lost_amount.rs @@ -98,6 +98,7 @@ where DisputeMetricsBucketIdentifier::new( i.dispute_stage.as_ref().map(|i| i.0), i.connector.clone(), + i.currency.as_ref().map(|i| i.0), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/disputes/types.rs b/crates/analytics/src/disputes/types.rs index 762e8d27554f..da66744aede6 100644 --- a/crates/analytics/src/disputes/types.rs +++ b/crates/analytics/src/disputes/types.rs @@ -24,6 +24,12 @@ where .attach_printable("Error adding dispute stage filter")?; } + if !self.currency.is_empty() { + builder + .add_filter_in_range_clause(DisputeDimensions::Currency, &self.currency) + .attach_printable("Error adding currency filter")?; + } + Ok(()) } } diff --git a/crates/analytics/src/sqlx.rs b/crates/analytics/src/sqlx.rs index 2a94d528768d..653d019adeb8 100644 --- a/crates/analytics/src/sqlx.rs +++ b/crates/analytics/src/sqlx.rs @@ -933,11 +933,17 @@ impl<'a> FromRow<'a, PgRow> for super::disputes::filters::DisputeFilterRow { ColumnNotFound(_) => Ok(Default::default()), e => Err(e), })?; + let currency: Option> = + row.try_get("currency").or_else(|e| match e { + ColumnNotFound(_) => Ok(Default::default()), + e => Err(e), + })?; Ok(Self { dispute_stage, dispute_status, connector, connector_status, + currency, }) } } @@ -957,6 +963,11 @@ impl<'a> FromRow<'a, PgRow> for super::disputes::metrics::DisputeMetricRow { ColumnNotFound(_) => Ok(Default::default()), e => Err(e), })?; + let currency: Option> = + row.try_get("currency").or_else(|e| match e { + ColumnNotFound(_) => Ok(Default::default()), + e => Err(e), + })?; let total: Option = row.try_get("total").or_else(|e| match e { ColumnNotFound(_) => Ok(Default::default()), e => Err(e), @@ -976,6 +987,7 @@ impl<'a> FromRow<'a, PgRow> for super::disputes::metrics::DisputeMetricRow { dispute_stage, dispute_status, connector, + currency, total, count, start_bucket, diff --git a/crates/api_models/src/analytics/disputes.rs b/crates/api_models/src/analytics/disputes.rs index e373704b87c5..179edee04133 100644 --- a/crates/api_models/src/analytics/disputes.rs +++ b/crates/api_models/src/analytics/disputes.rs @@ -4,7 +4,7 @@ use std::{ }; use super::{ForexMetric, NameDescription, TimeRange}; -use crate::enums::DisputeStage; +use crate::enums::{Currency, DisputeStage}; #[derive( Clone, @@ -58,6 +58,7 @@ pub enum DisputeDimensions { // Consult the Dashboard FE folks since these also affects the order of metrics on FE Connector, DisputeStage, + Currency, } impl From for NameDescription { @@ -82,13 +83,17 @@ impl From for NameDescription { pub struct DisputeFilters { #[serde(default)] pub dispute_stage: Vec, + #[serde(default)] pub connector: Vec, + #[serde(default)] + pub currency: Vec, } #[derive(Debug, serde::Serialize, Eq)] pub struct DisputeMetricsBucketIdentifier { pub dispute_stage: Option, pub connector: Option, + pub currency: Option, #[serde(rename = "time_range")] pub time_bucket: TimeRange, #[serde(rename = "time_bucket")] @@ -100,6 +105,7 @@ impl Hash for DisputeMetricsBucketIdentifier { fn hash(&self, state: &mut H) { self.dispute_stage.hash(state); self.connector.hash(state); + self.currency.hash(state); self.time_bucket.hash(state); } } @@ -117,11 +123,13 @@ impl DisputeMetricsBucketIdentifier { pub fn new( dispute_stage: Option, connector: Option, + currency: Option, normalized_time_range: TimeRange, ) -> Self { Self { dispute_stage, connector, + currency, time_bucket: normalized_time_range, start_time: normalized_time_range.start_time, }