diff --git a/crates/analytics/src/clickhouse.rs b/crates/analytics/src/clickhouse.rs index 27d4235050..ead3b1699e 100644 --- a/crates/analytics/src/clickhouse.rs +++ b/crates/analytics/src/clickhouse.rs @@ -130,7 +130,8 @@ impl AnalyticsDataSource for ClickhouseClient { match table { AnalyticsCollection::Payment | AnalyticsCollection::Refund - | AnalyticsCollection::PaymentIntent => { + | AnalyticsCollection::PaymentIntent + | AnalyticsCollection::Dispute => { TableEngine::CollapsingMergeTree { sign: "sign_flag" } } AnalyticsCollection::SdkEvents => TableEngine::BasicTree, @@ -374,6 +375,7 @@ impl ToSql for AnalyticsCollection { Self::PaymentIntent => Ok("payment_intents".to_string()), Self::ConnectorEvents => Ok("connector_events_audit".to_string()), Self::OutgoingWebhookEvent => Ok("outgoing_webhook_events_audit".to_string()), + Self::Dispute => Ok("dispute".to_string()), } } } diff --git a/crates/analytics/src/core.rs b/crates/analytics/src/core.rs index 354e1e2f17..6ccf2858e2 100644 --- a/crates/analytics/src/core.rs +++ b/crates/analytics/src/core.rs @@ -26,6 +26,11 @@ pub async fn get_domain_info( download_dimensions: None, dimensions: utils::get_api_event_dimensions(), }, + AnalyticsDomain::Dispute => GetInfoResponse { + metrics: utils::get_dispute_metrics_info(), + download_dimensions: None, + dimensions: utils::get_dispute_dimensions(), + }, }; Ok(info) } diff --git a/crates/analytics/src/sqlx.rs b/crates/analytics/src/sqlx.rs index 562a3a1f64..1fb7a9b450 100644 --- a/crates/analytics/src/sqlx.rs +++ b/crates/analytics/src/sqlx.rs @@ -445,6 +445,7 @@ impl ToSql for AnalyticsCollection { .attach_printable("ConnectorEvents table is not implemented for Sqlx"))?, Self::OutgoingWebhookEvent => Err(error_stack::report!(ParsingError::UnknownError) .attach_printable("OutgoingWebhookEvents table is not implemented for Sqlx"))?, + Self::Dispute => Ok("dispute".to_string()), } } } diff --git a/crates/analytics/src/types.rs b/crates/analytics/src/types.rs index 18e9e9f433..356d11bb77 100644 --- a/crates/analytics/src/types.rs +++ b/crates/analytics/src/types.rs @@ -17,6 +17,7 @@ pub enum AnalyticsDomain { Refunds, SdkEvents, ApiEvents, + Dispute, } #[derive(Debug, strum::AsRefStr, strum::Display, Clone, Copy)] @@ -28,6 +29,7 @@ pub enum AnalyticsCollection { PaymentIntent, ConnectorEvents, OutgoingWebhookEvent, + Dispute, } #[allow(dead_code)] diff --git a/crates/analytics/src/utils.rs b/crates/analytics/src/utils.rs index 6a0aa973a1..7bff5c87da 100644 --- a/crates/analytics/src/utils.rs +++ b/crates/analytics/src/utils.rs @@ -1,5 +1,6 @@ use api_models::analytics::{ api_event::{ApiEventDimensions, ApiEventMetrics}, + disputes::{DisputeDimensions, DisputeMetrics}, payments::{PaymentDimensions, PaymentMetrics}, refunds::{RefundDimensions, RefundMetrics}, sdk_events::{SdkEventDimensions, SdkEventMetrics}, @@ -38,3 +39,11 @@ pub fn get_sdk_event_metrics_info() -> Vec { pub fn get_api_event_metrics_info() -> Vec { ApiEventMetrics::iter().map(Into::into).collect() } + +pub fn get_dispute_metrics_info() -> Vec { + DisputeMetrics::iter().map(Into::into).collect() +} + +pub fn get_dispute_dimensions() -> Vec { + DisputeDimensions::iter().map(Into::into).collect() +} diff --git a/crates/api_models/src/analytics.rs b/crates/api_models/src/analytics.rs index c6ca215f9f..1115d40b19 100644 --- a/crates/api_models/src/analytics.rs +++ b/crates/api_models/src/analytics.rs @@ -13,6 +13,7 @@ pub use crate::payments::TimeRange; pub mod api_event; pub mod connector_events; +pub mod disputes; pub mod outgoing_webhook_event; pub mod payments; pub mod refunds; diff --git a/crates/api_models/src/analytics/disputes.rs b/crates/api_models/src/analytics/disputes.rs new file mode 100644 index 0000000000..19d552d45d --- /dev/null +++ b/crates/api_models/src/analytics/disputes.rs @@ -0,0 +1,65 @@ +use super::NameDescription; + +#[derive( + Clone, + Debug, + Hash, + PartialEq, + Eq, + serde::Serialize, + serde::Deserialize, + strum::Display, + strum::EnumIter, + strum::AsRefStr, +)] +#[strum(serialize_all = "snake_case")] +#[serde(rename_all = "snake_case")] +pub enum DisputeMetrics { + DisputesChallenged, + DisputesWon, + DisputesLost, + TotalAmountDisputed, + TotalDisputeLostAmount, +} + +#[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 DisputeDimensions { + // Do not change the order of these enums + // Consult the Dashboard FE folks since these also affects the order of metrics on FE + Connector, + DisputeStatus, + ConnectorStatus, +} + +impl From for NameDescription { + fn from(value: DisputeDimensions) -> Self { + Self { + name: value.to_string(), + desc: String::new(), + } + } +} + +impl From for NameDescription { + fn from(value: DisputeMetrics) -> Self { + Self { + name: value.to_string(), + desc: String::new(), + } + } +}