feat(analytics): adding metric api for dispute analytics (#3810)

Co-authored-by: Sampras Lopes <lsampras@pm.me>
This commit is contained in:
harsh-sharma-juspay
2024-02-28 17:39:31 +05:30
committed by GitHub
parent f3931cf484
commit de6b16bed9
20 changed files with 1032 additions and 30 deletions

View File

@ -5,7 +5,7 @@ use masking::Secret;
use self::{
api_event::{ApiEventDimensions, ApiEventMetrics},
disputes::DisputeDimensions,
disputes::{DisputeDimensions, DisputeMetrics},
payments::{PaymentDimensions, PaymentDistributions, PaymentMetrics},
refunds::{RefundDimensions, RefundMetrics},
sdk_events::{SdkEventDimensions, SdkEventMetrics},
@ -271,3 +271,17 @@ pub struct DisputeFilterValue {
pub dimension: DisputeDimensions,
pub values: Vec<String>,
}
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetDisputeMetricRequest {
pub time_series: Option<TimeSeries>,
pub time_range: TimeRange,
#[serde(default)]
pub group_by_names: Vec<DisputeDimensions>,
#[serde(default)]
pub filters: disputes::DisputeFilters,
pub metrics: HashSet<DisputeMetrics>,
#[serde(default)]
pub delta: bool,
}

View File

@ -1,4 +1,10 @@
use super::NameDescription;
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
};
use super::{NameDescription, TimeRange};
use crate::enums::DisputeStage;
#[derive(
Clone,
@ -15,9 +21,7 @@ use super::NameDescription;
#[strum(serialize_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum DisputeMetrics {
DisputesChallenged,
DisputesWon,
DisputesLost,
DisputeStatusMetric,
TotalAmountDisputed,
TotalDisputeLostAmount,
}
@ -42,8 +46,6 @@ 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,
DisputeStage,
}
@ -64,3 +66,70 @@ impl From<DisputeMetrics> for NameDescription {
}
}
}
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
pub struct DisputeFilters {
#[serde(default)]
pub dispute_stage: Vec<DisputeStage>,
pub connector: Vec<String>,
}
#[derive(Debug, serde::Serialize, Eq)]
pub struct DisputeMetricsBucketIdentifier {
pub dispute_stage: Option<DisputeStage>,
pub connector: Option<String>,
#[serde(rename = "time_range")]
pub time_bucket: TimeRange,
#[serde(rename = "time_bucket")]
#[serde(with = "common_utils::custom_serde::iso8601custom")]
pub start_time: time::PrimitiveDateTime,
}
impl Hash for DisputeMetricsBucketIdentifier {
fn hash<H: Hasher>(&self, state: &mut H) {
self.dispute_stage.hash(state);
self.connector.hash(state);
self.time_bucket.hash(state);
}
}
impl PartialEq for DisputeMetricsBucketIdentifier {
fn eq(&self, other: &Self) -> bool {
let mut left = DefaultHasher::new();
self.hash(&mut left);
let mut right = DefaultHasher::new();
other.hash(&mut right);
left.finish() == right.finish()
}
}
impl DisputeMetricsBucketIdentifier {
pub fn new(
dispute_stage: Option<DisputeStage>,
connector: Option<String>,
normalized_time_range: TimeRange,
) -> Self {
Self {
dispute_stage,
connector,
time_bucket: normalized_time_range,
start_time: normalized_time_range.start_time,
}
}
}
#[derive(Debug, serde::Serialize)]
pub struct DisputeMetricsBucketValue {
pub disputes_challenged: Option<u64>,
pub disputes_won: Option<u64>,
pub disputes_lost: Option<u64>,
pub total_amount_disputed: Option<u64>,
pub total_dispute_lost_amount: Option<u64>,
pub total_dispute: Option<u64>,
}
#[derive(Debug, serde::Serialize)]
pub struct DisputeMetricsBucketResponse {
#[serde(flatten)]
pub values: DisputeMetricsBucketValue,
#[serde(flatten)]
pub dimensions: DisputeMetricsBucketIdentifier,
}

View File

@ -97,7 +97,8 @@ impl_misc_api_event_type!(
ConnectorEventsRequest,
OutgoingWebhookLogsRequest,
GetDisputeFilterRequest,
DisputeFiltersResponse
DisputeFiltersResponse,
GetDisputeMetricRequest
);
#[cfg(feature = "stripe")]