Skip to content

Commit 15cb473

Browse files
refactor(router): add support to store signature_network and is_regulated in payment attempts (#8891)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
1 parent 0821d1b commit 15cb473

File tree

16 files changed

+159
-18
lines changed

16 files changed

+159
-18
lines changed

crates/analytics/docs/clickhouse/scripts/payment_attempts.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ CREATE TABLE payment_attempt_queue (
4545
`card_network` Nullable(String),
4646
`routing_approach` LowCardinality(Nullable(String)),
4747
`debit_routing_savings` Nullable(UInt32),
48+
`signature_network` Nullable(String),
49+
`is_issuer_regulated` Nullable(Bool),
4850
`sign_flag` Int8
4951
) ENGINE = Kafka SETTINGS kafka_broker_list = 'kafka0:29092',
5052
kafka_topic_list = 'hyperswitch-payment-attempt-events',
@@ -100,6 +102,8 @@ CREATE TABLE payment_attempts (
100102
`card_network` Nullable(String),
101103
`routing_approach` LowCardinality(Nullable(String)),
102104
`debit_routing_savings` Nullable(UInt32),
105+
`signature_network` Nullable(String),
106+
`is_issuer_regulated` Nullable(Bool),
103107
`sign_flag` Int8,
104108
INDEX connectorIndex connector TYPE bloom_filter GRANULARITY 1,
105109
INDEX paymentMethodIndex payment_method TYPE bloom_filter GRANULARITY 1,
@@ -158,6 +162,8 @@ CREATE MATERIALIZED VIEW payment_attempt_mv TO payment_attempts (
158162
`card_network` Nullable(String),
159163
`routing_approach` LowCardinality(Nullable(String)),
160164
`debit_routing_savings` Nullable(UInt32),
165+
`signature_network` Nullable(String),
166+
`is_issuer_regulated` Nullable(Bool),
161167
`sign_flag` Int8
162168
) AS
163169
SELECT
@@ -208,6 +214,8 @@ SELECT
208214
card_network,
209215
routing_approach,
210216
debit_routing_savings,
217+
signature_network,
218+
is_issuer_regulated,
211219
sign_flag
212220
FROM
213221
payment_attempt_queue

crates/analytics/src/payments/accumulator.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ pub struct ProcessedAmountAccumulator {
6363
pub struct DebitRoutingAccumulator {
6464
pub transaction_count: u64,
6565
pub savings_amount: u64,
66+
pub signature_network: Option<String>,
67+
pub is_issuer_regulated: Option<bool>,
6668
}
6769

6870
#[derive(Debug, Default)]
@@ -191,7 +193,13 @@ impl PaymentMetricAccumulator for SuccessRateAccumulator {
191193
}
192194

193195
impl PaymentMetricAccumulator for DebitRoutingAccumulator {
194-
type MetricOutput = (Option<u64>, Option<u64>, Option<u64>);
196+
type MetricOutput = (
197+
Option<u64>,
198+
Option<u64>,
199+
Option<u64>,
200+
Option<String>,
201+
Option<bool>,
202+
);
195203

196204
fn add_metrics_bucket(&mut self, metrics: &PaymentMetricRow) {
197205
if let Some(count) = metrics.count {
@@ -200,13 +208,21 @@ impl PaymentMetricAccumulator for DebitRoutingAccumulator {
200208
if let Some(total) = metrics.total.as_ref().and_then(ToPrimitive::to_u64) {
201209
self.savings_amount += total;
202210
}
211+
if let Some(signature_network) = &metrics.signature_network {
212+
self.signature_network = Some(signature_network.clone());
213+
}
214+
if let Some(is_issuer_regulated) = metrics.is_issuer_regulated {
215+
self.is_issuer_regulated = Some(is_issuer_regulated);
216+
}
203217
}
204218

205219
fn collect(self) -> Self::MetricOutput {
206220
(
207221
Some(self.transaction_count),
208222
Some(self.savings_amount),
209223
Some(0),
224+
self.signature_network,
225+
self.is_issuer_regulated,
210226
)
211227
}
212228
}
@@ -468,8 +484,13 @@ impl PaymentMetricsAccumulator {
468484
) = self.payments_distribution.collect();
469485
let (failure_reason_count, failure_reason_count_without_smart_retries) =
470486
self.failure_reasons_distribution.collect();
471-
let (debit_routed_transaction_count, debit_routing_savings, debit_routing_savings_in_usd) =
472-
self.debit_routing.collect();
487+
let (
488+
debit_routed_transaction_count,
489+
debit_routing_savings,
490+
debit_routing_savings_in_usd,
491+
signature_network,
492+
is_issuer_regulated,
493+
) = self.debit_routing.collect();
473494

474495
PaymentMetricsBucketValue {
475496
payment_success_rate: self.payment_success_rate.collect(),
@@ -497,6 +518,8 @@ impl PaymentMetricsAccumulator {
497518
debit_routed_transaction_count,
498519
debit_routing_savings,
499520
debit_routing_savings_in_usd,
521+
signature_network,
522+
is_issuer_regulated,
500523
}
501524
}
502525
}

crates/analytics/src/payments/metrics.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ pub struct PaymentMetricRow {
5353
pub total: Option<bigdecimal::BigDecimal>,
5454
pub count: Option<i64>,
5555
pub routing_approach: Option<DBEnumWrapper<storage_enums::RoutingApproach>>,
56+
pub signature_network: Option<String>,
57+
pub is_issuer_regulated: Option<bool>,
5658
#[serde(with = "common_utils::custom_serde::iso8601::option")]
5759
pub start_bucket: Option<PrimitiveDateTime>,
5860
#[serde(with = "common_utils::custom_serde::iso8601::option")]

crates/analytics/src/payments/metrics/debit_routing.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ where
5656
})
5757
.switch()?;
5858
query_builder.add_select_column("currency").switch()?;
59+
60+
query_builder
61+
.add_select_column("signature_network")
62+
.switch()?;
63+
query_builder
64+
.add_select_column("is_issuer_regulated")
65+
.switch()?;
66+
5967
query_builder
6068
.add_select_column(Aggregate::Min {
6169
field: "created_at",
@@ -85,6 +93,16 @@ where
8593
.switch()?;
8694
}
8795

96+
query_builder
97+
.add_group_by_clause("signature_network")
98+
.attach_printable("Error grouping by signature_network")
99+
.switch()?;
100+
101+
query_builder
102+
.add_group_by_clause("is_issuer_regulated")
103+
.attach_printable("Error grouping by is_issuer_regulated")
104+
.switch()?;
105+
88106
query_builder
89107
.add_group_by_clause("currency")
90108
.attach_printable("Error grouping by currency")

crates/analytics/src/sqlx.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,16 @@ impl<'a> FromRow<'a, PgRow> for super::payments::metrics::PaymentMetricRow {
736736
ColumnNotFound(_) => Ok(Default::default()),
737737
e => Err(e),
738738
})?;
739+
let signature_network: Option<String> =
740+
row.try_get("signature_network").or_else(|e| match e {
741+
ColumnNotFound(_) => Ok(Default::default()),
742+
e => Err(e),
743+
})?;
744+
let is_issuer_regulated: Option<bool> =
745+
row.try_get("is_issuer_regulated").or_else(|e| match e {
746+
ColumnNotFound(_) => Ok(Default::default()),
747+
e => Err(e),
748+
})?;
739749
let total: Option<bigdecimal::BigDecimal> = row.try_get("total").or_else(|e| match e {
740750
ColumnNotFound(_) => Ok(Default::default()),
741751
e => Err(e),
@@ -768,6 +778,8 @@ impl<'a> FromRow<'a, PgRow> for super::payments::metrics::PaymentMetricRow {
768778
error_reason,
769779
first_attempt,
770780
routing_approach,
781+
signature_network,
782+
is_issuer_regulated,
771783
total,
772784
count,
773785
start_bucket,

crates/api_models/src/analytics/payments.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,8 @@ pub struct PaymentMetricsBucketValue {
319319
pub debit_routed_transaction_count: Option<u64>,
320320
pub debit_routing_savings: Option<u64>,
321321
pub debit_routing_savings_in_usd: Option<u64>,
322+
pub signature_network: Option<String>,
323+
pub is_issuer_regulated: Option<bool>,
322324
}
323325

324326
#[derive(Debug, serde::Serialize)]

crates/api_models/src/open_router.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,13 @@ impl CoBadgedCardNetworks {
124124
pub fn get_card_networks(&self) -> Vec<common_enums::CardNetwork> {
125125
self.0.iter().map(|info| info.network.clone()).collect()
126126
}
127+
128+
pub fn get_signature_network(&self) -> Option<common_enums::CardNetwork> {
129+
self.0
130+
.iter()
131+
.find(|info| info.network.is_signature_network())
132+
.map(|info| info.network.clone())
133+
}
127134
}
128135

129136
impl From<&DebitRoutingOutput> for payment_methods::CoBadgedCardData {

crates/api_models/src/payment_methods.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,6 +1229,8 @@ impl From<CardDetailFromLocker> for payments::AdditionalCardInfo {
12291229
card_holder_name: item.card_holder_name,
12301230
payment_checks: None,
12311231
authentication_data: None,
1232+
is_regulated: None,
1233+
signature_network: None,
12321234
}
12331235
}
12341236
}
@@ -1252,6 +1254,8 @@ impl From<CardDetailFromLocker> for payments::AdditionalCardInfo {
12521254
card_holder_name: item.card_holder_name,
12531255
payment_checks: None,
12541256
authentication_data: None,
1257+
is_regulated: None,
1258+
signature_network: None,
12551259
}
12561260
}
12571261
}

crates/api_models/src/payments.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2970,6 +2970,15 @@ pub struct AdditionalCardInfo {
29702970
/// Details about the threeds environment.
29712971
/// This is a free form field and the structure varies from processor to processor
29722972
pub authentication_data: Option<serde_json::Value>,
2973+
2974+
/// Indicates if the card issuer is regulated under government-imposed interchange fee caps.
2975+
/// In the United States, this includes debit cards that fall under the Durbin Amendment,
2976+
/// which imposes capped interchange fees.
2977+
pub is_regulated: Option<bool>,
2978+
2979+
/// The global signature network under which the card is issued.
2980+
/// This represents the primary global card brand, even if the transaction uses a local network
2981+
pub signature_network: Option<api_enums::CardNetwork>,
29732982
}
29742983

29752984
#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)]

crates/common_enums/src/enums.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2599,7 +2599,7 @@ pub enum DecisionEngineMerchantCategoryCode {
25992599
}
26002600

26012601
impl CardNetwork {
2602-
pub fn is_global_network(&self) -> bool {
2602+
pub fn is_signature_network(&self) -> bool {
26032603
match self {
26042604
Self::Interac
26052605
| Self::Star

0 commit comments

Comments
 (0)