diff --git a/crates/analytics/src/auth_events/accumulator.rs b/crates/analytics/src/auth_events/accumulator.rs index 2958030c8d..446ac6ac8c 100644 --- a/crates/analytics/src/auth_events/accumulator.rs +++ b/crates/analytics/src/auth_events/accumulator.rs @@ -4,7 +4,7 @@ use super::metrics::AuthEventMetricRow; #[derive(Debug, Default)] pub struct AuthEventMetricsAccumulator { - pub three_ds_sdk_count: CountAccumulator, + pub authentication_count: CountAccumulator, pub authentication_attempt_count: CountAccumulator, pub authentication_success_count: CountAccumulator, pub challenge_flow_count: CountAccumulator, @@ -47,7 +47,7 @@ impl AuthEventMetricAccumulator for CountAccumulator { impl AuthEventMetricsAccumulator { pub fn collect(self) -> AuthEventMetricsBucketValue { AuthEventMetricsBucketValue { - three_ds_sdk_count: self.three_ds_sdk_count.collect(), + authentication_count: self.authentication_count.collect(), authentication_attempt_count: self.authentication_attempt_count.collect(), authentication_success_count: self.authentication_success_count.collect(), challenge_flow_count: self.challenge_flow_count.collect(), diff --git a/crates/analytics/src/auth_events/core.rs b/crates/analytics/src/auth_events/core.rs index 3fd134bc49..75bdf4de14 100644 --- a/crates/analytics/src/auth_events/core.rs +++ b/crates/analytics/src/auth_events/core.rs @@ -18,7 +18,6 @@ use crate::{ pub async fn get_metrics( pool: &AnalyticsProvider, merchant_id: &common_utils::id_type::MerchantId, - publishable_key: &String, req: GetAuthEventMetricRequest, ) -> AnalyticsResult> { let mut metrics_accumulator: HashMap< @@ -30,14 +29,12 @@ pub async fn get_metrics( for metric_type in req.metrics.iter().cloned() { let req = req.clone(); let merchant_id_scoped = merchant_id.to_owned(); - let publishable_key_scoped = publishable_key.to_owned(); let pool = pool.clone(); set.spawn(async move { let data = pool .get_auth_event_metrics( &metric_type, &merchant_id_scoped, - &publishable_key_scoped, req.time_series.map(|t| t.granularity), &req.time_range, ) @@ -56,8 +53,8 @@ pub async fn get_metrics( for (id, value) in data? { let metrics_builder = metrics_accumulator.entry(id).or_default(); match metric { - AuthEventMetrics::ThreeDsSdkCount => metrics_builder - .three_ds_sdk_count + AuthEventMetrics::AuthenticationCount => metrics_builder + .authentication_count .add_metrics_bucket(&value), AuthEventMetrics::AuthenticationAttemptCount => metrics_builder .authentication_attempt_count diff --git a/crates/analytics/src/auth_events/metrics.rs b/crates/analytics/src/auth_events/metrics.rs index 4a1fbd0e14..f3f0354818 100644 --- a/crates/analytics/src/auth_events/metrics.rs +++ b/crates/analytics/src/auth_events/metrics.rs @@ -12,22 +12,22 @@ use crate::{ }; mod authentication_attempt_count; +mod authentication_count; mod authentication_success_count; mod challenge_attempt_count; mod challenge_flow_count; mod challenge_success_count; mod frictionless_flow_count; mod frictionless_success_count; -mod three_ds_sdk_count; use authentication_attempt_count::AuthenticationAttemptCount; +use authentication_count::AuthenticationCount; use authentication_success_count::AuthenticationSuccessCount; use challenge_attempt_count::ChallengeAttemptCount; use challenge_flow_count::ChallengeFlowCount; use challenge_success_count::ChallengeSuccessCount; use frictionless_flow_count::FrictionlessFlowCount; use frictionless_success_count::FrictionlessSuccessCount; -use three_ds_sdk_count::ThreeDsSdkCount; #[derive(Debug, PartialEq, Eq, serde::Deserialize, Hash)] pub struct AuthEventMetricRow { @@ -45,7 +45,6 @@ where async fn load_metrics( &self, merchant_id: &common_utils::id_type::MerchantId, - publishable_key: &str, granularity: Option, time_range: &TimeRange, pool: &T, @@ -65,50 +64,49 @@ where async fn load_metrics( &self, merchant_id: &common_utils::id_type::MerchantId, - publishable_key: &str, granularity: Option, time_range: &TimeRange, pool: &T, ) -> MetricsResult> { match self { - Self::ThreeDsSdkCount => { - ThreeDsSdkCount - .load_metrics(merchant_id, publishable_key, granularity, time_range, pool) + Self::AuthenticationCount => { + AuthenticationCount + .load_metrics(merchant_id, granularity, time_range, pool) .await } Self::AuthenticationAttemptCount => { AuthenticationAttemptCount - .load_metrics(merchant_id, publishable_key, granularity, time_range, pool) + .load_metrics(merchant_id, granularity, time_range, pool) .await } Self::AuthenticationSuccessCount => { AuthenticationSuccessCount - .load_metrics(merchant_id, publishable_key, granularity, time_range, pool) + .load_metrics(merchant_id, granularity, time_range, pool) .await } Self::ChallengeFlowCount => { ChallengeFlowCount - .load_metrics(merchant_id, publishable_key, granularity, time_range, pool) + .load_metrics(merchant_id, granularity, time_range, pool) .await } Self::ChallengeAttemptCount => { ChallengeAttemptCount - .load_metrics(merchant_id, publishable_key, granularity, time_range, pool) + .load_metrics(merchant_id, granularity, time_range, pool) .await } Self::ChallengeSuccessCount => { ChallengeSuccessCount - .load_metrics(merchant_id, publishable_key, granularity, time_range, pool) + .load_metrics(merchant_id, granularity, time_range, pool) .await } Self::FrictionlessFlowCount => { FrictionlessFlowCount - .load_metrics(merchant_id, publishable_key, granularity, time_range, pool) + .load_metrics(merchant_id, granularity, time_range, pool) .await } Self::FrictionlessSuccessCount => { FrictionlessSuccessCount - .load_metrics(merchant_id, publishable_key, granularity, time_range, pool) + .load_metrics(merchant_id, granularity, time_range, pool) .await } } diff --git a/crates/analytics/src/auth_events/metrics/authentication_attempt_count.rs b/crates/analytics/src/auth_events/metrics/authentication_attempt_count.rs index 5faeefec68..2d34344905 100644 --- a/crates/analytics/src/auth_events/metrics/authentication_attempt_count.rs +++ b/crates/analytics/src/auth_events/metrics/authentication_attempt_count.rs @@ -1,9 +1,9 @@ use std::collections::HashSet; use api_models::analytics::{ - auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity, - TimeRange, + auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange, }; +use common_enums::AuthenticationStatus; use common_utils::errors::ReportSwitchExt; use error_stack::ResultExt; use time::PrimitiveDateTime; @@ -29,14 +29,13 @@ where { async fn load_metrics( &self, - _merchant_id: &common_utils::id_type::MerchantId, - publishable_key: &str, + merchant_id: &common_utils::id_type::MerchantId, granularity: Option, time_range: &TimeRange, pool: &T, ) -> MetricsResult> { let mut query_builder: QueryBuilder = - QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics); + QueryBuilder::new(AnalyticsCollection::Authentications); query_builder .add_select_column(Aggregate::Count { @@ -45,30 +44,26 @@ where }) .switch()?; - if let Some(granularity) = granularity { - query_builder - .add_granularity_in_mins(granularity) - .switch()?; - } - query_builder - .add_filter_clause("merchant_id", publishable_key) + .add_select_column(Aggregate::Min { + field: "created_at", + alias: Some("start_bucket"), + }) .switch()?; query_builder - .add_bool_filter_clause("first_event", 1) + .add_select_column(Aggregate::Max { + field: "created_at", + alias: Some("end_bucket"), + }) .switch()?; query_builder - .add_filter_clause("event_name", SdkEventNames::AuthenticationCallInit) + .add_filter_clause("merchant_id", merchant_id) .switch()?; query_builder - .add_filter_clause("log_type", "INFO") - .switch()?; - - query_builder - .add_filter_clause("category", "API") + .add_negative_filter_clause("authentication_status", AuthenticationStatus::Pending) .switch()?; time_range @@ -76,9 +71,9 @@ where .attach_printable("Error filtering time range") .switch()?; - if let Some(_granularity) = granularity.as_ref() { - query_builder - .add_group_by_clause("time_bucket") + if let Some(granularity) = granularity { + granularity + .set_group_by_clause(&mut query_builder) .attach_printable("Error adding granularity") .switch()?; } diff --git a/crates/analytics/src/auth_events/metrics/three_ds_sdk_count.rs b/crates/analytics/src/auth_events/metrics/authentication_count.rs similarity index 69% rename from crates/analytics/src/auth_events/metrics/three_ds_sdk_count.rs rename to crates/analytics/src/auth_events/metrics/authentication_count.rs index 4ce10c9aad..9f2311f563 100644 --- a/crates/analytics/src/auth_events/metrics/three_ds_sdk_count.rs +++ b/crates/analytics/src/auth_events/metrics/authentication_count.rs @@ -1,8 +1,7 @@ use std::collections::HashSet; use api_models::analytics::{ - auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity, - TimeRange, + auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange, }; use common_utils::errors::ReportSwitchExt; use error_stack::ResultExt; @@ -15,10 +14,10 @@ use crate::{ }; #[derive(Default)] -pub(super) struct ThreeDsSdkCount; +pub(super) struct AuthenticationCount; #[async_trait::async_trait] -impl super::AuthEventMetric for ThreeDsSdkCount +impl super::AuthEventMetric for AuthenticationCount where T: AnalyticsDataSource + super::AuthEventMetricAnalytics, PrimitiveDateTime: ToSql, @@ -29,14 +28,13 @@ where { async fn load_metrics( &self, - _merchant_id: &common_utils::id_type::MerchantId, - publishable_key: &str, + merchant_id: &common_utils::id_type::MerchantId, granularity: Option, time_range: &TimeRange, pool: &T, ) -> MetricsResult> { let mut query_builder: QueryBuilder = - QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics); + QueryBuilder::new(AnalyticsCollection::Authentications); query_builder .add_select_column(Aggregate::Count { @@ -45,30 +43,22 @@ where }) .switch()?; - if let Some(granularity) = granularity { - query_builder - .add_granularity_in_mins(granularity) - .switch()?; - } - query_builder - .add_filter_clause("merchant_id", publishable_key) + .add_select_column(Aggregate::Min { + field: "created_at", + alias: Some("start_bucket"), + }) .switch()?; query_builder - .add_bool_filter_clause("first_event", 1) + .add_select_column(Aggregate::Max { + field: "created_at", + alias: Some("end_bucket"), + }) .switch()?; query_builder - .add_filter_clause("category", "USER_EVENT") - .switch()?; - - query_builder - .add_filter_clause("log_type", "INFO") - .switch()?; - - query_builder - .add_filter_clause("event_name", SdkEventNames::ThreeDsMethod) + .add_filter_clause("merchant_id", merchant_id) .switch()?; time_range @@ -76,9 +66,9 @@ where .attach_printable("Error filtering time range") .switch()?; - if let Some(_granularity) = granularity.as_ref() { - query_builder - .add_group_by_clause("time_bucket") + if let Some(granularity) = granularity { + granularity + .set_group_by_clause(&mut query_builder) .attach_printable("Error adding granularity") .switch()?; } diff --git a/crates/analytics/src/auth_events/metrics/authentication_success_count.rs b/crates/analytics/src/auth_events/metrics/authentication_success_count.rs index 663473c2d8..e887807f41 100644 --- a/crates/analytics/src/auth_events/metrics/authentication_success_count.rs +++ b/crates/analytics/src/auth_events/metrics/authentication_success_count.rs @@ -1,9 +1,9 @@ use std::collections::HashSet; use api_models::analytics::{ - auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity, - TimeRange, + auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange, }; +use common_enums::AuthenticationStatus; use common_utils::errors::ReportSwitchExt; use error_stack::ResultExt; use time::PrimitiveDateTime; @@ -29,14 +29,13 @@ where { async fn load_metrics( &self, - _merchant_id: &common_utils::id_type::MerchantId, - publishable_key: &str, + merchant_id: &common_utils::id_type::MerchantId, granularity: Option, time_range: &TimeRange, pool: &T, ) -> MetricsResult> { let mut query_builder: QueryBuilder = - QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics); + QueryBuilder::new(AnalyticsCollection::Authentications); query_builder .add_select_column(Aggregate::Count { @@ -45,30 +44,26 @@ where }) .switch()?; - if let Some(granularity) = granularity { - query_builder - .add_granularity_in_mins(granularity) - .switch()?; - } - query_builder - .add_filter_clause("merchant_id", publishable_key) + .add_select_column(Aggregate::Min { + field: "created_at", + alias: Some("start_bucket"), + }) .switch()?; query_builder - .add_bool_filter_clause("first_event", 1) + .add_select_column(Aggregate::Max { + field: "created_at", + alias: Some("end_bucket"), + }) .switch()?; query_builder - .add_filter_clause("event_name", SdkEventNames::AuthenticationCall) + .add_filter_clause("merchant_id", merchant_id) .switch()?; query_builder - .add_filter_clause("log_type", "INFO") - .switch()?; - - query_builder - .add_filter_clause("category", "API") + .add_filter_clause("authentication_status", AuthenticationStatus::Success) .switch()?; time_range @@ -76,9 +71,9 @@ where .attach_printable("Error filtering time range") .switch()?; - if let Some(_granularity) = granularity.as_ref() { - query_builder - .add_group_by_clause("time_bucket") + if let Some(granularity) = granularity { + granularity + .set_group_by_clause(&mut query_builder) .attach_printable("Error adding granularity") .switch()?; } diff --git a/crates/analytics/src/auth_events/metrics/challenge_attempt_count.rs b/crates/analytics/src/auth_events/metrics/challenge_attempt_count.rs index 15cd86e5cc..f1f6a39799 100644 --- a/crates/analytics/src/auth_events/metrics/challenge_attempt_count.rs +++ b/crates/analytics/src/auth_events/metrics/challenge_attempt_count.rs @@ -1,8 +1,7 @@ use std::collections::HashSet; use api_models::analytics::{ - auth_events::{AuthEventFlows, AuthEventMetricsBucketIdentifier}, - Granularity, TimeRange, + auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange, }; use common_utils::errors::ReportSwitchExt; use error_stack::ResultExt; @@ -10,7 +9,7 @@ use time::PrimitiveDateTime; use super::AuthEventMetricRow; use crate::{ - query::{Aggregate, FilterTypes, GroupByClause, QueryBuilder, QueryFilter, ToSql, Window}, + query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, ToSql, Window}, types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult}, }; @@ -30,13 +29,12 @@ where async fn load_metrics( &self, merchant_id: &common_utils::id_type::MerchantId, - _publishable_key: &str, granularity: Option, time_range: &TimeRange, pool: &T, ) -> MetricsResult> { let mut query_builder: QueryBuilder = - QueryBuilder::new(AnalyticsCollection::ApiEventsAnalytics); + QueryBuilder::new(AnalyticsCollection::Authentications); query_builder .add_select_column(Aggregate::Count { @@ -45,22 +43,30 @@ where }) .switch()?; - if let Some(granularity) = granularity { - query_builder - .add_granularity_in_mins(granularity) - .switch()?; - } + query_builder + .add_select_column(Aggregate::Min { + field: "created_at", + alias: Some("start_bucket"), + }) + .switch()?; + + query_builder + .add_select_column(Aggregate::Max { + field: "created_at", + alias: Some("end_bucket"), + }) + .switch()?; query_builder .add_filter_clause("merchant_id", merchant_id) .switch()?; query_builder - .add_filter_clause("api_flow", AuthEventFlows::IncomingWebhookReceive) + .add_filter_clause("trans_status", "C".to_string()) .switch()?; query_builder - .add_custom_filter_clause("request", "threeDSServerTransID", FilterTypes::Like) + .add_negative_filter_clause("authentication_status", "pending") .switch()?; time_range @@ -68,9 +74,9 @@ where .attach_printable("Error filtering time range") .switch()?; - if let Some(_granularity) = granularity.as_ref() { - query_builder - .add_group_by_clause("time_bucket") + if let Some(granularity) = granularity { + granularity + .set_group_by_clause(&mut query_builder) .attach_printable("Error adding granularity") .switch()?; } diff --git a/crates/analytics/src/auth_events/metrics/challenge_flow_count.rs b/crates/analytics/src/auth_events/metrics/challenge_flow_count.rs index 61b10e6fb9..c08618cc0d 100644 --- a/crates/analytics/src/auth_events/metrics/challenge_flow_count.rs +++ b/crates/analytics/src/auth_events/metrics/challenge_flow_count.rs @@ -1,8 +1,7 @@ use std::collections::HashSet; use api_models::analytics::{ - auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity, - TimeRange, + auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange, }; use common_utils::errors::ReportSwitchExt; use error_stack::ResultExt; @@ -29,14 +28,13 @@ where { async fn load_metrics( &self, - _merchant_id: &common_utils::id_type::MerchantId, - publishable_key: &str, + merchant_id: &common_utils::id_type::MerchantId, granularity: Option, time_range: &TimeRange, pool: &T, ) -> MetricsResult> { let mut query_builder: QueryBuilder = - QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics); + QueryBuilder::new(AnalyticsCollection::Authentications); query_builder .add_select_column(Aggregate::Count { @@ -45,42 +43,36 @@ where }) .switch()?; - if let Some(granularity) = granularity { - query_builder - .add_granularity_in_mins(granularity) - .switch()?; - } - query_builder - .add_filter_clause("merchant_id", publishable_key) + .add_select_column(Aggregate::Min { + field: "created_at", + alias: Some("start_bucket"), + }) .switch()?; query_builder - .add_bool_filter_clause("first_event", 1) + .add_select_column(Aggregate::Max { + field: "created_at", + alias: Some("end_bucket"), + }) .switch()?; query_builder - .add_filter_clause("category", "USER_EVENT") + .add_filter_clause("merchant_id", merchant_id) .switch()?; query_builder - .add_filter_clause("log_type", "INFO") + .add_filter_clause("trans_status", "C".to_string()) .switch()?; - query_builder - .add_filter_clause("event_name", SdkEventNames::DisplayThreeDsSdk) - .switch()?; - - query_builder.add_filter_clause("value", "C").switch()?; - time_range .set_filter_clause(&mut query_builder) .attach_printable("Error filtering time range") .switch()?; - if let Some(_granularity) = granularity.as_ref() { - query_builder - .add_group_by_clause("time_bucket") + if let Some(granularity) = granularity { + granularity + .set_group_by_clause(&mut query_builder) .attach_printable("Error adding granularity") .switch()?; } diff --git a/crates/analytics/src/auth_events/metrics/challenge_success_count.rs b/crates/analytics/src/auth_events/metrics/challenge_success_count.rs index c5bf7bf81c..3fb75efd56 100644 --- a/crates/analytics/src/auth_events/metrics/challenge_success_count.rs +++ b/crates/analytics/src/auth_events/metrics/challenge_success_count.rs @@ -1,9 +1,9 @@ use std::collections::HashSet; use api_models::analytics::{ - auth_events::{AuthEventFlows, AuthEventMetricsBucketIdentifier}, - Granularity, TimeRange, + auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange, }; +use common_enums::AuthenticationStatus; use common_utils::errors::ReportSwitchExt; use error_stack::ResultExt; use time::PrimitiveDateTime; @@ -30,13 +30,12 @@ where async fn load_metrics( &self, merchant_id: &common_utils::id_type::MerchantId, - _publishable_key: &str, granularity: Option, time_range: &TimeRange, pool: &T, ) -> MetricsResult> { let mut query_builder: QueryBuilder = - QueryBuilder::new(AnalyticsCollection::ApiEventsAnalytics); + QueryBuilder::new(AnalyticsCollection::Authentications); query_builder .add_select_column(Aggregate::Count { @@ -45,22 +44,30 @@ where }) .switch()?; - if let Some(granularity) = granularity { - query_builder - .add_granularity_in_mins(granularity) - .switch()?; - } + query_builder + .add_select_column(Aggregate::Min { + field: "created_at", + alias: Some("start_bucket"), + }) + .switch()?; + + query_builder + .add_select_column(Aggregate::Max { + field: "created_at", + alias: Some("end_bucket"), + }) + .switch()?; query_builder .add_filter_clause("merchant_id", merchant_id) .switch()?; query_builder - .add_filter_clause("api_flow", AuthEventFlows::IncomingWebhookReceive) + .add_filter_clause("authentication_status", AuthenticationStatus::Success) .switch()?; query_builder - .add_filter_clause("visitParamExtractRaw(request, 'transStatus')", "\"Y\"") + .add_filter_clause("trans_status", "C".to_string()) .switch()?; time_range @@ -68,9 +75,9 @@ where .attach_printable("Error filtering time range") .switch()?; - if let Some(_granularity) = granularity.as_ref() { - query_builder - .add_group_by_clause("time_bucket") + if let Some(granularity) = granularity { + granularity + .set_group_by_clause(&mut query_builder) .attach_printable("Error adding granularity") .switch()?; } diff --git a/crates/analytics/src/auth_events/metrics/frictionless_flow_count.rs b/crates/analytics/src/auth_events/metrics/frictionless_flow_count.rs index c08cc511e1..8859c60fc3 100644 --- a/crates/analytics/src/auth_events/metrics/frictionless_flow_count.rs +++ b/crates/analytics/src/auth_events/metrics/frictionless_flow_count.rs @@ -1,8 +1,7 @@ use std::collections::HashSet; use api_models::analytics::{ - auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity, - TimeRange, + auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange, }; use common_utils::errors::ReportSwitchExt; use error_stack::ResultExt; @@ -29,14 +28,13 @@ where { async fn load_metrics( &self, - _merchant_id: &common_utils::id_type::MerchantId, - publishable_key: &str, + merchant_id: &common_utils::id_type::MerchantId, granularity: Option, time_range: &TimeRange, pool: &T, ) -> MetricsResult> { let mut query_builder: QueryBuilder = - QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics); + QueryBuilder::new(AnalyticsCollection::Authentications); query_builder .add_select_column(Aggregate::Count { @@ -45,34 +43,26 @@ where }) .switch()?; - if let Some(granularity) = granularity { - query_builder - .add_granularity_in_mins(granularity) - .switch()?; - } - query_builder - .add_filter_clause("merchant_id", publishable_key) + .add_select_column(Aggregate::Min { + field: "created_at", + alias: Some("start_bucket"), + }) .switch()?; query_builder - .add_bool_filter_clause("first_event", 1) + .add_select_column(Aggregate::Max { + field: "created_at", + alias: Some("end_bucket"), + }) .switch()?; query_builder - .add_filter_clause("category", "USER_EVENT") + .add_filter_clause("merchant_id", merchant_id) .switch()?; query_builder - .add_filter_clause("log_type", "INFO") - .switch()?; - - query_builder - .add_filter_clause("event_name", SdkEventNames::DisplayThreeDsSdk) - .switch()?; - - query_builder - .add_negative_filter_clause("value", "C") + .add_filter_clause("trans_status", "Y".to_string()) .switch()?; time_range @@ -80,9 +70,9 @@ where .attach_printable("Error filtering time range") .switch()?; - if let Some(_granularity) = granularity.as_ref() { - query_builder - .add_group_by_clause("time_bucket") + if let Some(granularity) = granularity { + granularity + .set_group_by_clause(&mut query_builder) .attach_printable("Error adding granularity") .switch()?; } diff --git a/crates/analytics/src/auth_events/metrics/frictionless_success_count.rs b/crates/analytics/src/auth_events/metrics/frictionless_success_count.rs index b310567c9d..3d5d894e7d 100644 --- a/crates/analytics/src/auth_events/metrics/frictionless_success_count.rs +++ b/crates/analytics/src/auth_events/metrics/frictionless_success_count.rs @@ -1,9 +1,9 @@ use std::collections::HashSet; use api_models::analytics::{ - auth_events::{AuthEventFlows, AuthEventMetricsBucketIdentifier}, - Granularity, TimeRange, + auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange, }; +use common_enums::AuthenticationStatus; use common_utils::errors::ReportSwitchExt; use error_stack::ResultExt; use time::PrimitiveDateTime; @@ -30,13 +30,12 @@ where async fn load_metrics( &self, merchant_id: &common_utils::id_type::MerchantId, - _publishable_key: &str, granularity: Option, time_range: &TimeRange, pool: &T, ) -> MetricsResult> { let mut query_builder: QueryBuilder = - QueryBuilder::new(AnalyticsCollection::ApiEventsAnalytics); + QueryBuilder::new(AnalyticsCollection::Authentications); query_builder .add_select_column(Aggregate::Count { @@ -45,22 +44,30 @@ where }) .switch()?; - if let Some(granularity) = granularity { - query_builder - .add_granularity_in_mins(granularity) - .switch()?; - } - query_builder - .add_filter_clause("merchant_id", merchant_id.get_string_repr()) + .add_select_column(Aggregate::Min { + field: "created_at", + alias: Some("start_bucket"), + }) .switch()?; query_builder - .add_filter_clause("api_flow", AuthEventFlows::PaymentsExternalAuthentication) + .add_select_column(Aggregate::Max { + field: "created_at", + alias: Some("end_bucket"), + }) .switch()?; query_builder - .add_filter_clause("visitParamExtractRaw(response, 'transStatus')", "\"Y\"") + .add_filter_clause("merchant_id", merchant_id) + .switch()?; + + query_builder + .add_filter_clause("trans_status", "Y".to_string()) + .switch()?; + + query_builder + .add_filter_clause("authentication_status", AuthenticationStatus::Success) .switch()?; time_range @@ -68,9 +75,9 @@ where .attach_printable("Error filtering time range") .switch()?; - if let Some(_granularity) = granularity.as_ref() { - query_builder - .add_group_by_clause("time_bucket") + if let Some(granularity) = granularity { + granularity + .set_group_by_clause(&mut query_builder) .attach_printable("Error adding granularity") .switch()?; } diff --git a/crates/analytics/src/clickhouse.rs b/crates/analytics/src/clickhouse.rs index cd870c12b2..1c86e7cbcf 100644 --- a/crates/analytics/src/clickhouse.rs +++ b/crates/analytics/src/clickhouse.rs @@ -138,6 +138,7 @@ impl AnalyticsDataSource for ClickhouseClient { | AnalyticsCollection::FraudCheck | AnalyticsCollection::PaymentIntent | AnalyticsCollection::PaymentIntentSessionized + | AnalyticsCollection::Authentications | AnalyticsCollection::Dispute => { TableEngine::CollapsingMergeTree { sign: "sign_flag" } } @@ -457,6 +458,7 @@ impl ToSql for AnalyticsCollection { Self::Dispute => Ok("dispute".to_string()), Self::DisputeSessionized => Ok("sessionizer_dispute".to_string()), Self::ActivePaymentsAnalytics => Ok("active_payments".to_string()), + Self::Authentications => Ok("authentications".to_string()), } } } diff --git a/crates/analytics/src/lib.rs b/crates/analytics/src/lib.rs index 0ad8886b82..ef7108e8ef 100644 --- a/crates/analytics/src/lib.rs +++ b/crates/analytics/src/lib.rs @@ -909,7 +909,6 @@ impl AnalyticsProvider { &self, metric: &AuthEventMetrics, merchant_id: &common_utils::id_type::MerchantId, - publishable_key: &str, granularity: Option, time_range: &TimeRange, ) -> types::MetricsResult> { @@ -917,14 +916,13 @@ impl AnalyticsProvider { Self::Sqlx(_pool) => Err(report!(MetricsError::NotImplemented)), Self::Clickhouse(pool) => { metric - .load_metrics(merchant_id, publishable_key, granularity, time_range, pool) + .load_metrics(merchant_id, granularity, time_range, pool) .await } Self::CombinedCkh(_sqlx_pool, ckh_pool) | Self::CombinedSqlx(_sqlx_pool, ckh_pool) => { metric .load_metrics( merchant_id, - publishable_key, granularity, // Since API events are ckh only use ckh here time_range, diff --git a/crates/analytics/src/query.rs b/crates/analytics/src/query.rs index f449ba2f9b..59cb874344 100644 --- a/crates/analytics/src/query.rs +++ b/crates/analytics/src/query.rs @@ -19,6 +19,7 @@ use api_models::{ }, refunds::RefundStatus, }; +use common_enums::{AuthenticationStatus, TransactionStatus}; use common_utils::{ errors::{CustomResult, ParsingError}, id_type::{MerchantId, OrganizationId, ProfileId}, @@ -502,6 +503,8 @@ impl_to_sql_for_to_string!( Currency, RefundType, FrmTransactionType, + TransactionStatus, + AuthenticationStatus, Flow, &String, &bool, diff --git a/crates/analytics/src/sqlx.rs b/crates/analytics/src/sqlx.rs index 653d019ade..f3143840f3 100644 --- a/crates/analytics/src/sqlx.rs +++ b/crates/analytics/src/sqlx.rs @@ -1034,6 +1034,8 @@ impl ToSql for AnalyticsCollection { Self::Dispute => Ok("dispute".to_string()), Self::DisputeSessionized => Err(error_stack::report!(ParsingError::UnknownError) .attach_printable("DisputeSessionized table is not implemented for Sqlx"))?, + Self::Authentications => Err(error_stack::report!(ParsingError::UnknownError) + .attach_printable("Authentications table is not implemented for Sqlx"))?, } } } diff --git a/crates/analytics/src/types.rs b/crates/analytics/src/types.rs index 8605633810..7bf8fc7d3c 100644 --- a/crates/analytics/src/types.rs +++ b/crates/analytics/src/types.rs @@ -37,6 +37,7 @@ pub enum AnalyticsCollection { PaymentIntentSessionized, ConnectorEvents, OutgoingWebhookEvent, + Authentications, Dispute, DisputeSessionized, ApiEventsAnalytics, diff --git a/crates/api_models/src/analytics/auth_events.rs b/crates/api_models/src/analytics/auth_events.rs index 7791a2f3cd..6f52755134 100644 --- a/crates/api_models/src/analytics/auth_events.rs +++ b/crates/api_models/src/analytics/auth_events.rs @@ -5,6 +5,29 @@ use std::{ use super::NameDescription; +#[derive( + Debug, + serde::Serialize, + serde::Deserialize, + strum::AsRefStr, + PartialEq, + PartialOrd, + Eq, + Ord, + strum::Display, + strum::EnumIter, + Clone, + Copy, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum AuthEventDimensions { + #[serde(rename = "authentication_status")] + AuthenticationStatus, + #[serde(rename = "trans_status")] + TransactionStatus, +} + #[derive( Clone, Debug, @@ -20,7 +43,7 @@ use super::NameDescription; #[strum(serialize_all = "snake_case")] #[serde(rename_all = "snake_case")] pub enum AuthEventMetrics { - ThreeDsSdkCount, + AuthenticationCount, AuthenticationAttemptCount, AuthenticationSuccessCount, ChallengeFlowCount, @@ -48,7 +71,7 @@ pub enum AuthEventFlows { } pub mod metric_behaviour { - pub struct ThreeDsSdkCount; + pub struct AuthenticationCount; pub struct AuthenticationAttemptCount; pub struct AuthenticationSuccessCount; pub struct ChallengeFlowCount; @@ -96,7 +119,7 @@ impl PartialEq for AuthEventMetricsBucketIdentifier { #[derive(Debug, serde::Serialize)] pub struct AuthEventMetricsBucketValue { - pub three_ds_sdk_count: Option, + pub authentication_count: Option, pub authentication_attempt_count: Option, pub authentication_success_count: Option, pub challenge_flow_count: Option, diff --git a/crates/router/src/analytics.rs b/crates/router/src/analytics.rs index 8fb4f2ac2c..deaf84bb00 100644 --- a/crates/router/src/analytics.rs +++ b/crates/router/src/analytics.rs @@ -975,7 +975,6 @@ pub mod routes { analytics::auth_events::get_metrics( &state.pool, auth.merchant_account.get_id(), - &auth.merchant_account.publishable_key, req, ) .await