From 7682cd445eccdc8c213e0013a1fd025b21a4414d Mon Sep 17 00:00:00 2001 From: Sarthak Soni <76486416+Sarthak1799@users.noreply.github.com> Date: Mon, 28 Jul 2025 12:59:13 +0530 Subject: [PATCH] refactor: Add routing_approach other variant to handle unknown data (#8754) --- .../distribution/payment_error_message.rs | 2 +- .../src/payments/metrics/avg_ticket_size.rs | 2 +- .../payments/metrics/connector_success_rate.rs | 2 +- .../src/payments/metrics/debit_routing.rs | 2 +- .../src/payments/metrics/payment_count.rs | 2 +- .../metrics/payment_processed_amount.rs | 2 +- .../payments/metrics/payment_success_count.rs | 2 +- .../src/payments/metrics/retries_count.rs | 2 +- .../sessionized_metrics/avg_ticket_size.rs | 2 +- .../connector_success_rate.rs | 2 +- .../sessionized_metrics/debit_routing.rs | 2 +- .../sessionized_metrics/failure_reasons.rs | 2 +- .../sessionized_metrics/payment_count.rs | 2 +- .../payment_processed_amount.rs | 2 +- .../payment_success_count.rs | 2 +- .../payments_distribution.rs | 2 +- .../sessionized_metrics/retries_count.rs | 2 +- .../sessionized_metrics/success_rate.rs | 2 +- .../src/payments/metrics/success_rate.rs | 2 +- crates/api_models/src/analytics/payments.rs | 5 ++++- crates/common_enums/src/enums.rs | 5 ++++- .../src/payments/payment_attempt.rs | 18 ++++++++++++++++-- crates/router/src/core/payments.rs | 4 ++++ .../core/payments/operations/payment_create.rs | 2 +- crates/router/src/core/payments/routing.rs | 10 ++++++++-- .../src/services/kafka/payment_attempt.rs | 2 +- .../services/kafka/payment_attempt_event.rs | 2 +- .../src/payments/payment_attempt.rs | 2 +- 28 files changed, 59 insertions(+), 29 deletions(-) diff --git a/crates/analytics/src/payments/distribution/payment_error_message.rs b/crates/analytics/src/payments/distribution/payment_error_message.rs index d5fa056945..2022aad32d 100644 --- a/crates/analytics/src/payments/distribution/payment_error_message.rs +++ b/crates/analytics/src/payments/distribution/payment_error_message.rs @@ -160,7 +160,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/avg_ticket_size.rs b/crates/analytics/src/payments/metrics/avg_ticket_size.rs index 8ec175cf8d..0dff94cec7 100644 --- a/crates/analytics/src/payments/metrics/avg_ticket_size.rs +++ b/crates/analytics/src/payments/metrics/avg_ticket_size.rs @@ -122,7 +122,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/connector_success_rate.rs b/crates/analytics/src/payments/metrics/connector_success_rate.rs index eb4518f6d2..ac1c4efdfb 100644 --- a/crates/analytics/src/payments/metrics/connector_success_rate.rs +++ b/crates/analytics/src/payments/metrics/connector_success_rate.rs @@ -117,7 +117,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/debit_routing.rs b/crates/analytics/src/payments/metrics/debit_routing.rs index 584221205c..2caec813ec 100644 --- a/crates/analytics/src/payments/metrics/debit_routing.rs +++ b/crates/analytics/src/payments/metrics/debit_routing.rs @@ -127,7 +127,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/payment_count.rs b/crates/analytics/src/payments/metrics/payment_count.rs index ed23a400fb..6f9e999143 100644 --- a/crates/analytics/src/payments/metrics/payment_count.rs +++ b/crates/analytics/src/payments/metrics/payment_count.rs @@ -108,7 +108,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/payment_processed_amount.rs b/crates/analytics/src/payments/metrics/payment_processed_amount.rs index 302acf097e..1b6355622e 100644 --- a/crates/analytics/src/payments/metrics/payment_processed_amount.rs +++ b/crates/analytics/src/payments/metrics/payment_processed_amount.rs @@ -122,7 +122,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/payment_success_count.rs b/crates/analytics/src/payments/metrics/payment_success_count.rs index d1f437d812..fa1daad137 100644 --- a/crates/analytics/src/payments/metrics/payment_success_count.rs +++ b/crates/analytics/src/payments/metrics/payment_success_count.rs @@ -115,7 +115,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/retries_count.rs b/crates/analytics/src/payments/metrics/retries_count.rs index 63ebfaefca..bf4546bf53 100644 --- a/crates/analytics/src/payments/metrics/retries_count.rs +++ b/crates/analytics/src/payments/metrics/retries_count.rs @@ -112,7 +112,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics/avg_ticket_size.rs b/crates/analytics/src/payments/metrics/sessionized_metrics/avg_ticket_size.rs index a513877736..4c129e43db 100644 --- a/crates/analytics/src/payments/metrics/sessionized_metrics/avg_ticket_size.rs +++ b/crates/analytics/src/payments/metrics/sessionized_metrics/avg_ticket_size.rs @@ -123,7 +123,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics/connector_success_rate.rs b/crates/analytics/src/payments/metrics/sessionized_metrics/connector_success_rate.rs index 626f11aa22..c00b28e61a 100644 --- a/crates/analytics/src/payments/metrics/sessionized_metrics/connector_success_rate.rs +++ b/crates/analytics/src/payments/metrics/sessionized_metrics/connector_success_rate.rs @@ -118,7 +118,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics/debit_routing.rs b/crates/analytics/src/payments/metrics/sessionized_metrics/debit_routing.rs index f7c84e1b65..6df1d265f1 100644 --- a/crates/analytics/src/payments/metrics/sessionized_metrics/debit_routing.rs +++ b/crates/analytics/src/payments/metrics/sessionized_metrics/debit_routing.rs @@ -128,7 +128,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics/failure_reasons.rs b/crates/analytics/src/payments/metrics/sessionized_metrics/failure_reasons.rs index 5ed76cc493..a9cab381ac 100644 --- a/crates/analytics/src/payments/metrics/sessionized_metrics/failure_reasons.rs +++ b/crates/analytics/src/payments/metrics/sessionized_metrics/failure_reasons.rs @@ -183,7 +183,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics/payment_count.rs b/crates/analytics/src/payments/metrics/sessionized_metrics/payment_count.rs index 79d57477e1..a713b5fd1b 100644 --- a/crates/analytics/src/payments/metrics/sessionized_metrics/payment_count.rs +++ b/crates/analytics/src/payments/metrics/sessionized_metrics/payment_count.rs @@ -109,7 +109,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics/payment_processed_amount.rs b/crates/analytics/src/payments/metrics/sessionized_metrics/payment_processed_amount.rs index 0a2ab1f8a2..d96a023cb1 100644 --- a/crates/analytics/src/payments/metrics/sessionized_metrics/payment_processed_amount.rs +++ b/crates/analytics/src/payments/metrics/sessionized_metrics/payment_processed_amount.rs @@ -140,7 +140,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics/payment_success_count.rs b/crates/analytics/src/payments/metrics/sessionized_metrics/payment_success_count.rs index e59402933a..54833d3575 100644 --- a/crates/analytics/src/payments/metrics/sessionized_metrics/payment_success_count.rs +++ b/crates/analytics/src/payments/metrics/sessionized_metrics/payment_success_count.rs @@ -116,7 +116,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics/payments_distribution.rs b/crates/analytics/src/payments/metrics/sessionized_metrics/payments_distribution.rs index d7305cd079..e774d9816a 100644 --- a/crates/analytics/src/payments/metrics/sessionized_metrics/payments_distribution.rs +++ b/crates/analytics/src/payments/metrics/sessionized_metrics/payments_distribution.rs @@ -119,7 +119,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics/retries_count.rs b/crates/analytics/src/payments/metrics/sessionized_metrics/retries_count.rs index 83307d75f7..b8920614ce 100644 --- a/crates/analytics/src/payments/metrics/sessionized_metrics/retries_count.rs +++ b/crates/analytics/src/payments/metrics/sessionized_metrics/retries_count.rs @@ -112,7 +112,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics/success_rate.rs b/crates/analytics/src/payments/metrics/sessionized_metrics/success_rate.rs index 8159a615ba..1a6e48d646 100644 --- a/crates/analytics/src/payments/metrics/sessionized_metrics/success_rate.rs +++ b/crates/analytics/src/payments/metrics/sessionized_metrics/success_rate.rs @@ -112,7 +112,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payments/metrics/success_rate.rs b/crates/analytics/src/payments/metrics/success_rate.rs index 032f3219a6..f6acb968b9 100644 --- a/crates/analytics/src/payments/metrics/success_rate.rs +++ b/crates/analytics/src/payments/metrics/success_rate.rs @@ -111,7 +111,7 @@ where i.card_last_4.clone(), i.card_issuer.clone(), i.error_reason.clone(), - i.routing_approach.as_ref().map(|i| i.0), + i.routing_approach.as_ref().map(|i| i.0.clone()), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/api_models/src/analytics/payments.rs b/crates/api_models/src/analytics/payments.rs index ec5719f1ad..193fdf26cc 100644 --- a/crates/api_models/src/analytics/payments.rs +++ b/crates/api_models/src/analytics/payments.rs @@ -274,7 +274,10 @@ impl Hash for PaymentMetricsBucketIdentifier { self.card_last_4.hash(state); self.card_issuer.hash(state); self.error_reason.hash(state); - self.routing_approach.map(|i| i.to_string()).hash(state); + self.routing_approach + .clone() + .map(|i| i.to_string()) + .hash(state); self.time_bucket.hash(state); } } diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index c589d4aee0..39bdc74c99 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -8535,7 +8535,6 @@ pub enum TokenDataType { #[derive( Clone, - Copy, Debug, Default, Eq, @@ -8562,6 +8561,9 @@ pub enum RoutingApproach { StraightThroughRouting, #[default] DefaultFallback, + #[serde(untagged)] + #[strum(default)] + Other(String), } impl RoutingApproach { @@ -8570,6 +8572,7 @@ impl RoutingApproach { "SR_SELECTION_V3_ROUTING" => Self::SuccessRateExploitation, "SR_V3_HEDGING" => Self::SuccessRateExploration, "NTW_BASED_ROUTING" => Self::DebitRouting, + "DEFAULT" => Self::StraightThroughRouting, _ => Self::DefaultFallback, } } diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index e16285e3df..d9a7063054 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -1463,7 +1463,14 @@ impl PaymentAttemptUpdate { tax_amount, updated_by, merchant_connector_id, - routing_approach, + routing_approach: routing_approach.map(|approach| match approach { + storage_enums::RoutingApproach::Other(_) => { + // we need to make sure Other variant is not stored in DB, in the rare case + // where we attempt to store an unknown value, we default to the default value + storage_enums::RoutingApproach::default() + } + _ => approach, + }), }, Self::AuthenticationTypeUpdate { authentication_type, @@ -1565,7 +1572,14 @@ impl PaymentAttemptUpdate { order_tax_amount: net_amount.get_order_tax_amount(), connector_mandate_detail, card_discovery, - routing_approach, + routing_approach: routing_approach.map(|approach| match approach { + // we need to make sure Other variant is not stored in DB, in the rare case + // where we attempt to store an unknown value, we default to the default value + storage_enums::RoutingApproach::Other(_) => { + storage_enums::RoutingApproach::default() + } + _ => approach, + }), connector_request_reference_id, }, Self::VoidUpdate { diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index d2248a2fca..fd8615ff8a 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -8020,6 +8020,10 @@ where .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Failed execution of straight through routing")?; + payment_data.set_routing_approach_in_attempt(Some( + common_enums::RoutingApproach::StraightThroughRouting, + )); + if check_eligibility { let transaction_data = core_routing::PaymentsDslInput::new( payment_data.get_setup_mandate(), diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 1c3a8a0be9..5dfdb5427e 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -882,7 +882,7 @@ impl UpdateTracker, api::PaymentsRequest> for .as_ref() .map(|surcharge_details| surcharge_details.tax_on_surcharge_amount); - let routing_approach = payment_data.payment_attempt.routing_approach; + let routing_approach = payment_data.payment_attempt.routing_approach.clone(); payment_data.payment_attempt = state .store diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 8207f71c1a..547f49ce55 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -522,7 +522,10 @@ pub async fn perform_static_routing_v1( }; let (routable_connectors, routing_approach) = match cached_algorithm.as_ref() { - CachedAlgorithm::Single(conn) => (vec![(**conn).clone()], None), + CachedAlgorithm::Single(conn) => ( + vec![(**conn).clone()], + Some(common_enums::RoutingApproach::StraightThroughRouting), + ), CachedAlgorithm::Priority(plist) => (plist.clone(), None), CachedAlgorithm::VolumeSplit(splits) => ( perform_volume_split(splits.to_vec()) @@ -1390,7 +1393,10 @@ async fn perform_session_routing_for_pm_type( .await?; match cached_algorithm.as_ref() { - CachedAlgorithm::Single(conn) => (vec![(**conn).clone()], None), + CachedAlgorithm::Single(conn) => ( + vec![(**conn).clone()], + Some(common_enums::RoutingApproach::StraightThroughRouting), + ), CachedAlgorithm::Priority(plist) => (plist.clone(), None), CachedAlgorithm::VolumeSplit(splits) => ( perform_volume_split(splits.to_vec()) diff --git a/crates/router/src/services/kafka/payment_attempt.rs b/crates/router/src/services/kafka/payment_attempt.rs index e0dbc6ad21..8a900019b7 100644 --- a/crates/router/src/services/kafka/payment_attempt.rs +++ b/crates/router/src/services/kafka/payment_attempt.rs @@ -132,7 +132,7 @@ impl<'a> KafkaPaymentAttempt<'a> { card_discovery: attempt .card_discovery .map(|discovery| discovery.to_string()), - routing_approach: attempt.routing_approach, + routing_approach: attempt.routing_approach.clone(), debit_routing_savings: attempt.debit_routing_savings, } } diff --git a/crates/router/src/services/kafka/payment_attempt_event.rs b/crates/router/src/services/kafka/payment_attempt_event.rs index a54ff3cc28..4bff1b7646 100644 --- a/crates/router/src/services/kafka/payment_attempt_event.rs +++ b/crates/router/src/services/kafka/payment_attempt_event.rs @@ -133,7 +133,7 @@ impl<'a> KafkaPaymentAttemptEvent<'a> { card_discovery: attempt .card_discovery .map(|discovery| discovery.to_string()), - routing_approach: attempt.routing_approach, + routing_approach: attempt.routing_approach.clone(), debit_routing_savings: attempt.debit_routing_savings, } } diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index b3fccea353..5ddf5d5018 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -685,7 +685,7 @@ impl PaymentAttemptInterface for KVRouterStore { processor_merchant_id: payment_attempt.processor_merchant_id.clone(), created_by: payment_attempt.created_by.clone(), setup_future_usage_applied: payment_attempt.setup_future_usage_applied, - routing_approach: payment_attempt.routing_approach, + routing_approach: payment_attempt.routing_approach.clone(), connector_request_reference_id: payment_attempt .connector_request_reference_id .clone(),