Skip to content

Commit

Permalink
Merge branch 'main' into feat/profile_specific_fallback_routing
Browse files Browse the repository at this point in the history
  • Loading branch information
prajjwalkumar17 authored Nov 10, 2023
2 parents 45c509e + b3d5062 commit e6542db
Show file tree
Hide file tree
Showing 77 changed files with 6,253 additions and 742 deletions.
281 changes: 270 additions & 11 deletions Cargo.lock

Large diffs are not rendered by default.

14 changes: 13 additions & 1 deletion config/config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -434,10 +434,22 @@ apple_pay_ppc_key = "APPLE_PAY_PAYMENT_PROCESSING_CERTIFICATE_KEY" #Private
apple_pay_merchant_cert = "APPLE_PAY_MERCHNAT_CERTIFICATE" #Merchant Certificate provided by Apple Pay (https://developer.apple.com/) Certificates, Identifiers & Profiles > Apple Pay Merchant Identity Certificate
apple_pay_merchant_cert_key = "APPLE_PAY_MERCHNAT_CERTIFICATE_KEY" #Private key generate by RSA:2048 algorithm


[payment_link]
sdk_url = "http://localhost:9090/dist/HyperLoader.js"

# Analytics configuration.
[analytics]
source = "sqlx" # The Analytics source/strategy to be used

[analytics.sqlx]
username = "db_user" # Analytics DB Username
password = "db_pass" # Analytics DB Password
host = "localhost" # Analytics DB Host
port = 5432 # Analytics DB Port
dbname = "hyperswitch_db" # Name of Database
pool_size = 5 # Number of connections to keep open
connection_timeout = 10 # Timeout for database connection in seconds

# Config for KV setup
[kv_config]
# TTL for KV in seconds
Expand Down
11 changes: 11 additions & 0 deletions config/docker_compose.toml
Original file line number Diff line number Diff line change
Expand Up @@ -319,5 +319,16 @@ supported_connectors = "braintree"
redis_lock_expiry_seconds = 180 # 3 * 60 seconds
delay_between_retries_in_milliseconds = 500

[analytics]
source = "sqlx"

[analytics.sqlx]
username = "db_user"
password = "db_pass"
host = "pg"
port = 5432
dbname = "hyperswitch_db"
pool_size = 5

[kv_config]
ttl = 900 # 15 * 60 seconds
5 changes: 2 additions & 3 deletions crates/api_models/src/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,9 +463,8 @@ pub struct PaymentLinkConfig {
#[serde(deny_unknown_fields)]

pub struct PaymentLinkColorSchema {
pub primary_color: Option<String>,
pub primary_accent_color: Option<String>,
pub secondary_color: Option<String>,
pub background_primary_color: Option<String>,
pub sdk_theme: Option<String>,
}

#[derive(Clone, Debug, Deserialize, ToSchema, Serialize)]
Expand Down
152 changes: 152 additions & 0 deletions crates/api_models/src/analytics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use std::collections::HashSet;

use common_utils::events::ApiEventMetric;
use time::PrimitiveDateTime;

use self::{
payments::{PaymentDimensions, PaymentMetrics},
refunds::{RefundDimensions, RefundMetrics},
};

pub mod payments;
pub mod refunds;

#[derive(Debug, serde::Serialize)]
pub struct NameDescription {
pub name: String,
pub desc: String,
}

#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetInfoResponse {
pub metrics: Vec<NameDescription>,
pub download_dimensions: Option<Vec<NameDescription>>,
pub dimensions: Vec<NameDescription>,
}

impl ApiEventMetric for GetInfoResponse {}

#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "camelCase")]
pub struct TimeRange {
#[serde(with = "common_utils::custom_serde::iso8601")]
pub start_time: PrimitiveDateTime,
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub end_time: Option<PrimitiveDateTime>,
}

#[derive(Clone, Copy, Debug, serde::Deserialize, masking::Serialize)]
pub struct TimeSeries {
pub granularity: Granularity,
}

#[derive(Clone, Copy, Debug, serde::Deserialize, masking::Serialize)]
pub enum Granularity {
#[serde(rename = "G_ONEMIN")]
OneMin,
#[serde(rename = "G_FIVEMIN")]
FiveMin,
#[serde(rename = "G_FIFTEENMIN")]
FifteenMin,
#[serde(rename = "G_THIRTYMIN")]
ThirtyMin,
#[serde(rename = "G_ONEHOUR")]
OneHour,
#[serde(rename = "G_ONEDAY")]
OneDay,
}

#[derive(Clone, Debug, serde::Deserialize, masking::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetPaymentMetricRequest {
pub time_series: Option<TimeSeries>,
pub time_range: TimeRange,
#[serde(default)]
pub group_by_names: Vec<PaymentDimensions>,
#[serde(default)]
pub filters: payments::PaymentFilters,
pub metrics: HashSet<PaymentMetrics>,
#[serde(default)]
pub delta: bool,
}

impl ApiEventMetric for GetPaymentMetricRequest {}

#[derive(Clone, Debug, serde::Deserialize, masking::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetRefundMetricRequest {
pub time_series: Option<TimeSeries>,
pub time_range: TimeRange,
#[serde(default)]
pub group_by_names: Vec<RefundDimensions>,
#[serde(default)]
pub filters: refunds::RefundFilters,
pub metrics: HashSet<RefundMetrics>,
#[serde(default)]
pub delta: bool,
}

impl ApiEventMetric for GetRefundMetricRequest {}

#[derive(Debug, serde::Serialize)]
pub struct AnalyticsMetadata {
pub current_time_range: TimeRange,
}

#[derive(Debug, serde::Deserialize, masking::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetPaymentFiltersRequest {
pub time_range: TimeRange,
#[serde(default)]
pub group_by_names: Vec<PaymentDimensions>,
}

impl ApiEventMetric for GetPaymentFiltersRequest {}

#[derive(Debug, Default, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PaymentFiltersResponse {
pub query_data: Vec<FilterValue>,
}

impl ApiEventMetric for PaymentFiltersResponse {}

#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FilterValue {
pub dimension: PaymentDimensions,
pub values: Vec<String>,
}

#[derive(Debug, serde::Deserialize, masking::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetRefundFilterRequest {
pub time_range: TimeRange,
#[serde(default)]
pub group_by_names: Vec<RefundDimensions>,
}

impl ApiEventMetric for GetRefundFilterRequest {}

#[derive(Debug, Default, serde::Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct RefundFiltersResponse {
pub query_data: Vec<RefundFilterValue>,
}

impl ApiEventMetric for RefundFiltersResponse {}

#[derive(Debug, serde::Serialize, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct RefundFilterValue {
pub dimension: RefundDimensions,
pub values: Vec<String>,
}

#[derive(Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct MetricsResponse<T> {
pub query_data: Vec<T>,
pub meta_data: [AnalyticsMetadata; 1],
}
180 changes: 180 additions & 0 deletions crates/api_models/src/analytics/payments.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
};

use common_enums::enums::{AttemptStatus, AuthenticationType, Currency, PaymentMethod};
use common_utils::events::ApiEventMetric;

use super::{NameDescription, TimeRange};
use crate::{analytics::MetricsResponse, enums::Connector};

#[derive(Clone, Debug, Default, serde::Deserialize, masking::Serialize)]
pub struct PaymentFilters {
#[serde(default)]
pub currency: Vec<Currency>,
#[serde(default)]
pub status: Vec<AttemptStatus>,
#[serde(default)]
pub connector: Vec<Connector>,
#[serde(default)]
pub auth_type: Vec<AuthenticationType>,
#[serde(default)]
pub payment_method: Vec<PaymentMethod>,
}

#[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 PaymentDimensions {
// Do not change the order of these enums
// Consult the Dashboard FE folks since these also affects the order of metrics on FE
Connector,
PaymentMethod,
Currency,
#[strum(serialize = "authentication_type")]
#[serde(rename = "authentication_type")]
AuthType,
#[strum(serialize = "status")]
#[serde(rename = "status")]
PaymentStatus,
}

#[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 PaymentMetrics {
PaymentSuccessRate,
PaymentCount,
PaymentSuccessCount,
PaymentProcessedAmount,
AvgTicketSize,
}

pub mod metric_behaviour {
pub struct PaymentSuccessRate;
pub struct PaymentCount;
pub struct PaymentSuccessCount;
pub struct PaymentProcessedAmount;
pub struct AvgTicketSize;
}

impl From<PaymentMetrics> for NameDescription {
fn from(value: PaymentMetrics) -> Self {
Self {
name: value.to_string(),
desc: String::new(),
}
}
}

impl From<PaymentDimensions> for NameDescription {
fn from(value: PaymentDimensions) -> Self {
Self {
name: value.to_string(),
desc: String::new(),
}
}
}

#[derive(Debug, serde::Serialize, Eq)]
pub struct PaymentMetricsBucketIdentifier {
pub currency: Option<Currency>,
pub status: Option<AttemptStatus>,
pub connector: Option<String>,
#[serde(rename = "authentication_type")]
pub auth_type: Option<AuthenticationType>,
pub payment_method: Option<String>,
#[serde(rename = "time_range")]
pub time_bucket: TimeRange,
// Coz FE sucks
#[serde(rename = "time_bucket")]
#[serde(with = "common_utils::custom_serde::iso8601custom")]
pub start_time: time::PrimitiveDateTime,
}

impl PaymentMetricsBucketIdentifier {
pub fn new(
currency: Option<Currency>,
status: Option<AttemptStatus>,
connector: Option<String>,
auth_type: Option<AuthenticationType>,
payment_method: Option<String>,
normalized_time_range: TimeRange,
) -> Self {
Self {
currency,
status,
connector,
auth_type,
payment_method,
time_bucket: normalized_time_range,
start_time: normalized_time_range.start_time,
}
}
}

impl Hash for PaymentMetricsBucketIdentifier {
fn hash<H: Hasher>(&self, state: &mut H) {
self.currency.hash(state);
self.status.map(|i| i.to_string()).hash(state);
self.connector.hash(state);
self.auth_type.map(|i| i.to_string()).hash(state);
self.payment_method.hash(state);
self.time_bucket.hash(state);
}
}

impl PartialEq for PaymentMetricsBucketIdentifier {
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()
}
}

#[derive(Debug, serde::Serialize)]
pub struct PaymentMetricsBucketValue {
pub payment_success_rate: Option<f64>,
pub payment_count: Option<u64>,
pub payment_success_count: Option<u64>,
pub payment_processed_amount: Option<u64>,
pub avg_ticket_size: Option<f64>,
}

#[derive(Debug, serde::Serialize)]
pub struct MetricsBucketResponse {
#[serde(flatten)]
pub values: PaymentMetricsBucketValue,
#[serde(flatten)]
pub dimensions: PaymentMetricsBucketIdentifier,
}

impl ApiEventMetric for MetricsBucketResponse {}
impl ApiEventMetric for MetricsResponse<MetricsBucketResponse> {}
Loading

0 comments on commit e6542db

Please sign in to comment.