Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(analytics): add sessionized_metrics and currency_conversion for refunds analytics #6419

Merged
merged 8 commits into from
Nov 14, 2024
14 changes: 12 additions & 2 deletions crates/analytics/src/payment_intents/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,21 @@ pub async fn get_sankey(
i.refunds_status.unwrap_or_default().as_ref(),
i.attempt_count,
) {
(IntentStatus::Succeeded, SessionizerRefundStatus::FullRefunded, 1) => {
sankey_response.refunded += i.count;
sankey_response.normal_success += i.count
}
(IntentStatus::Succeeded, SessionizerRefundStatus::PartialRefunded, 1) => {
sankey_response.partial_refunded += i.count;
sankey_response.normal_success += i.count
}
(IntentStatus::Succeeded, SessionizerRefundStatus::FullRefunded, _) => {
sankey_response.refunded += i.count
sankey_response.refunded += i.count;
sankey_response.smart_retried_success += i.count
}
(IntentStatus::Succeeded, SessionizerRefundStatus::PartialRefunded, _) => {
sankey_response.partial_refunded += i.count
sankey_response.partial_refunded += i.count;
sankey_response.smart_retried_success += i.count
}
(
IntentStatus::Succeeded
Expand Down
4 changes: 2 additions & 2 deletions crates/analytics/src/payments/accumulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ impl PaymentMetricsAccumulator {
payment_processed_count,
payment_processed_amount_without_smart_retries,
payment_processed_count_without_smart_retries,
payment_processed_amount_usd,
payment_processed_amount_in_usd,
payment_processed_amount_without_smart_retries_usd,
) = self.processed_amount.collect();
let (
Expand Down Expand Up @@ -417,7 +417,7 @@ impl PaymentMetricsAccumulator {
payments_failure_rate_distribution_without_smart_retries,
failure_reason_count,
failure_reason_count_without_smart_retries,
payment_processed_amount_usd,
payment_processed_amount_in_usd,
payment_processed_amount_without_smart_retries_usd,
}
}
Expand Down
8 changes: 4 additions & 4 deletions crates/analytics/src/payments/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ pub async fn get_metrics(
let mut total_payment_processed_count_without_smart_retries = 0;
let mut total_failure_reasons_count = 0;
let mut total_failure_reasons_count_without_smart_retries = 0;
let mut total_payment_processed_amount_usd = 0;
let mut total_payment_processed_amount_in_usd = 0;
let mut total_payment_processed_amount_without_smart_retries_usd = 0;
let query_data: Vec<MetricsBucketResponse> = metrics_accumulator
.into_iter()
Expand All @@ -251,9 +251,9 @@ pub async fn get_metrics(
})
.map(|amount| (amount * rust_decimal::Decimal::new(100, 0)).to_u64())
.unwrap_or_default();
collected_values.payment_processed_amount_usd = amount_in_usd;
collected_values.payment_processed_amount_in_usd = amount_in_usd;
total_payment_processed_amount += amount;
total_payment_processed_amount_usd += amount_in_usd.unwrap_or(0);
total_payment_processed_amount_in_usd += amount_in_usd.unwrap_or(0);
}
if let Some(count) = collected_values.payment_processed_count {
total_payment_processed_count += count;
Expand Down Expand Up @@ -299,7 +299,7 @@ pub async fn get_metrics(
query_data,
meta_data: [PaymentsAnalyticsMetadata {
total_payment_processed_amount: Some(total_payment_processed_amount),
total_payment_processed_amount_usd: Some(total_payment_processed_amount_usd),
total_payment_processed_amount_in_usd: Some(total_payment_processed_amount_in_usd),
total_payment_processed_amount_without_smart_retries: Some(
total_payment_processed_amount_without_smart_retries,
),
Expand Down
15 changes: 9 additions & 6 deletions crates/analytics/src/refunds/accumulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub struct RefundMetricsAccumulator {
pub refund_success_rate: SuccessRateAccumulator,
pub refund_count: CountAccumulator,
pub refund_success: CountAccumulator,
pub processed_amount: SumAccumulator,
pub processed_amount: PaymentProcessedAmountAccumulator,
}

#[derive(Debug, Default)]
Expand All @@ -22,7 +22,7 @@ pub struct CountAccumulator {
}
#[derive(Debug, Default)]
#[repr(transparent)]
pub struct SumAccumulator {
pub struct PaymentProcessedAmountAccumulator {
pub total: Option<i64>,
}

Expand Down Expand Up @@ -50,8 +50,8 @@ impl RefundMetricAccumulator for CountAccumulator {
}
}

impl RefundMetricAccumulator for SumAccumulator {
type MetricOutput = Option<u64>;
impl RefundMetricAccumulator for PaymentProcessedAmountAccumulator {
type MetricOutput = (Option<u64>, Option<u64>);
#[inline]
fn add_metrics_bucket(&mut self, metrics: &RefundMetricRow) {
self.total = match (
Expand All @@ -68,7 +68,7 @@ impl RefundMetricAccumulator for SumAccumulator {
}
#[inline]
fn collect(self) -> Self::MetricOutput {
self.total.and_then(|i| u64::try_from(i).ok())
(self.total.and_then(|i| u64::try_from(i).ok()), Some(0))
}
}

Expand Down Expand Up @@ -98,11 +98,14 @@ impl RefundMetricAccumulator for SuccessRateAccumulator {

impl RefundMetricsAccumulator {
pub fn collect(self) -> RefundMetricsBucketValue {
let (refund_processed_amount, refund_processed_amount_in_usd) =
self.processed_amount.collect();
RefundMetricsBucketValue {
refund_success_rate: self.refund_success_rate.collect(),
refund_count: self.refund_count.collect(),
refund_success_count: self.refund_success.collect(),
refund_processed_amount: self.processed_amount.collect(),
refund_processed_amount,
refund_processed_amount_in_usd,
}
}
}
65 changes: 50 additions & 15 deletions crates/analytics/src/refunds/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ use api_models::analytics::{
refunds::{
RefundDimensions, RefundMetrics, RefundMetricsBucketIdentifier, RefundMetricsBucketResponse,
},
AnalyticsMetadata, GetRefundFilterRequest, GetRefundMetricRequest, MetricsResponse,
RefundFilterValue, RefundFiltersResponse,
GetRefundFilterRequest, GetRefundMetricRequest, RefundFilterValue, RefundFiltersResponse,
RefundsAnalyticsMetadata, RefundsMetricsResponse,
};
use bigdecimal::ToPrimitive;
use common_enums::Currency;
use currency_conversion::{conversion::convert, types::ExchangeRates};
use error_stack::ResultExt;
use router_env::{
logger,
Expand All @@ -29,9 +32,10 @@ use crate::{

pub async fn get_metrics(
pool: &AnalyticsProvider,
ex_rates: &ExchangeRates,
auth: &AuthInfo,
req: GetRefundMetricRequest,
) -> AnalyticsResult<MetricsResponse<RefundMetricsBucketResponse>> {
) -> AnalyticsResult<RefundsMetricsResponse<RefundMetricsBucketResponse>> {
let mut metrics_accumulator: HashMap<RefundMetricsBucketIdentifier, RefundMetricsAccumulator> =
HashMap::new();
let mut set = tokio::task::JoinSet::new();
Expand Down Expand Up @@ -86,16 +90,20 @@ pub async fn get_metrics(
logger::debug!(bucket_id=?id, bucket_value=?value, "Bucket row for metric {metric}");
let metrics_builder = metrics_accumulator.entry(id).or_default();
match metric {
RefundMetrics::RefundSuccessRate => metrics_builder
.refund_success_rate
.add_metrics_bucket(&value),
RefundMetrics::RefundCount => {
RefundMetrics::RefundSuccessRate | RefundMetrics::SessionizedRefundSuccessRate => {
metrics_builder
.refund_success_rate
.add_metrics_bucket(&value)
}
RefundMetrics::RefundCount | RefundMetrics::SessionizedRefundCount => {
metrics_builder.refund_count.add_metrics_bucket(&value)
}
RefundMetrics::RefundSuccessCount => {
RefundMetrics::RefundSuccessCount
| RefundMetrics::SessionizedRefundSuccessCount => {
metrics_builder.refund_success.add_metrics_bucket(&value)
}
RefundMetrics::RefundProcessedAmount => {
RefundMetrics::RefundProcessedAmount
| RefundMetrics::SessionizedRefundProcessedAmount => {
metrics_builder.processed_amount.add_metrics_bucket(&value)
}
}
Expand All @@ -107,18 +115,45 @@ pub async fn get_metrics(
metrics_accumulator
);
}
let mut total_refund_processed_amount = 0;
let mut total_refund_processed_amount_in_usd = 0;
let query_data: Vec<RefundMetricsBucketResponse> = metrics_accumulator
.into_iter()
.map(|(id, val)| RefundMetricsBucketResponse {
values: val.collect(),
dimensions: id,
.map(|(id, val)| {
let mut collected_values = val.collect();
if let Some(amount) = collected_values.refund_processed_amount {
let amount_in_usd = id
.currency
.and_then(|currency| {
i64::try_from(amount)
.inspect_err(|e| logger::error!("Amount conversion error: {:?}", e))
.ok()
.and_then(|amount_i64| {
convert(ex_rates, currency, Currency::USD, amount_i64)
.inspect_err(|e| {
logger::error!("Currency conversion error: {:?}", e)
})
.ok()
})
})
.map(|amount| (amount * rust_decimal::Decimal::new(100, 0)).to_u64())
.unwrap_or_default();
collected_values.refund_processed_amount_in_usd = amount_in_usd;
total_refund_processed_amount += amount;
total_refund_processed_amount_in_usd += amount_in_usd.unwrap_or(0);
}
RefundMetricsBucketResponse {
values: collected_values,
dimensions: id,
}
})
.collect();

Ok(MetricsResponse {
Ok(RefundsMetricsResponse {
query_data,
meta_data: [AnalyticsMetadata {
current_time_range: req.time_range,
meta_data: [RefundsAnalyticsMetadata {
total_refund_processed_amount: Some(total_refund_processed_amount),
total_refund_processed_amount_in_usd: Some(total_refund_processed_amount_in_usd),
}],
})
}
Expand Down
21 changes: 21 additions & 0 deletions crates/analytics/src/refunds/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod refund_count;
mod refund_processed_amount;
mod refund_success_count;
mod refund_success_rate;
mod sessionized_metrics;
use std::collections::HashSet;

use refund_count::RefundCount;
Expand Down Expand Up @@ -101,6 +102,26 @@ where
.load_metrics(dimensions, auth, filters, granularity, time_range, pool)
.await
}
Self::SessionizedRefundSuccessRate => {
sessionized_metrics::RefundSuccessRate::default()
.load_metrics(dimensions, auth, filters, granularity, time_range, pool)
.await
}
Self::SessionizedRefundCount => {
sessionized_metrics::RefundCount::default()
.load_metrics(dimensions, auth, filters, granularity, time_range, pool)
.await
}
Self::SessionizedRefundSuccessCount => {
sessionized_metrics::RefundSuccessCount::default()
.load_metrics(dimensions, auth, filters, granularity, time_range, pool)
.await
}
Self::SessionizedRefundProcessedAmount => {
sessionized_metrics::RefundProcessedAmount::default()
.load_metrics(dimensions, auth, filters, granularity, time_range, pool)
.await
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ where
alias: Some("total"),
})
.switch()?;
query_builder.add_select_column("currency").switch()?;
query_builder
.add_select_column(Aggregate::Min {
field: "created_at",
Expand All @@ -78,6 +79,7 @@ where
query_builder.add_group_by_clause(dim).switch()?;
}

query_builder.add_group_by_clause("currency").switch()?;
if let Some(granularity) = granularity.as_ref() {
granularity
.set_group_by_clause(&mut query_builder)
Expand Down
11 changes: 11 additions & 0 deletions crates/analytics/src/refunds/metrics/sessionized_metrics/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
mod refund_count;
mod refund_processed_amount;
mod refund_success_count;
mod refund_success_rate;

pub(super) use refund_count::RefundCount;
pub(super) use refund_processed_amount::RefundProcessedAmount;
pub(super) use refund_success_count::RefundSuccessCount;
pub(super) use refund_success_rate::RefundSuccessRate;

pub use super::{RefundMetric, RefundMetricAnalytics, RefundMetricRow};
Loading
Loading