feat(router): add open router integration for debit routing (#7907)

Co-authored-by: Sayak Bhattacharya <sayak.b@Sayak-Bhattacharya-G092THXJ34.local>
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Shankar Singh C
2025-05-19 15:34:29 +05:30
committed by GitHub
parent 868ff50d14
commit 140d15bcbd
61 changed files with 1426 additions and 171 deletions

View File

@ -23,7 +23,6 @@ pub mod gsm;
pub mod health_check;
pub mod locker_migration;
pub mod mandates;
#[cfg(feature = "dynamic_routing")]
pub mod open_router;
pub mod organization;
pub mod payment_methods;

View File

@ -1,6 +1,6 @@
use std::{collections::HashMap, fmt::Debug};
use common_utils::{id_type, types::MinorUnit};
use common_utils::{errors, id_type, types::MinorUnit};
pub use euclid::{
dssa::types::EuclidAnalysable,
frontend::{
@ -10,7 +10,10 @@ pub use euclid::{
};
use serde::{Deserialize, Serialize};
use crate::enums::{Currency, PaymentMethod};
use crate::{
enums::{Currency, PaymentMethod},
payment_methods,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
@ -27,6 +30,7 @@ pub struct OpenRouterDecideGatewayRequest {
pub enum RankingAlgorithm {
SrBasedRouting,
PlBasedRouting,
NtwBasedRouting,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -38,7 +42,7 @@ pub struct PaymentInfo {
// customerId: Option<ETCu::CustomerId>,
// preferredGateway: Option<ETG::Gateway>,
pub payment_type: String,
// metadata: Option<String>,
pub metadata: Option<String>,
// internalMetadata: Option<String>,
// isEmi: Option<bool>,
// emiBank: Option<String>,
@ -48,7 +52,7 @@ pub struct PaymentInfo {
// paymentSource: Option<String>,
// authType: Option<ETCa::txn_card_info::AuthType>,
// cardIssuerBankName: Option<String>,
// cardIsin: Option<String>,
pub card_isin: Option<String>,
// cardType: Option<ETCa::card_type::CardType>,
// cardSwitchProvider: Option<Secret<String>>,
}
@ -56,6 +60,63 @@ pub struct PaymentInfo {
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct DecidedGateway {
pub gateway_priority_map: Option<HashMap<String, f64>>,
pub debit_routing_output: Option<DebitRoutingOutput>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct DebitRoutingOutput {
pub co_badged_card_networks: Vec<common_enums::CardNetwork>,
pub issuer_country: common_enums::CountryAlpha2,
pub is_regulated: bool,
pub regulated_name: Option<common_enums::RegulatedName>,
pub card_type: common_enums::CardType,
}
impl From<&DebitRoutingOutput> for payment_methods::CoBadgedCardData {
fn from(output: &DebitRoutingOutput) -> Self {
Self {
co_badged_card_networks: output.co_badged_card_networks.clone(),
issuer_country_code: output.issuer_country,
is_regulated: output.is_regulated,
regulated_name: output.regulated_name.clone(),
}
}
}
impl TryFrom<(payment_methods::CoBadgedCardData, String)> for DebitRoutingRequestData {
type Error = error_stack::Report<errors::ParsingError>;
fn try_from(
(output, card_type): (payment_methods::CoBadgedCardData, String),
) -> Result<Self, Self::Error> {
let parsed_card_type = card_type.parse::<common_enums::CardType>().map_err(|_| {
error_stack::Report::new(errors::ParsingError::EnumParseFailure("CardType"))
})?;
Ok(Self {
co_badged_card_networks: output.co_badged_card_networks,
issuer_country: output.issuer_country_code,
is_regulated: output.is_regulated,
regulated_name: output.regulated_name,
card_type: parsed_card_type,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoBadgedCardRequest {
pub merchant_category_code: common_enums::MerchantCategoryCode,
pub acquirer_country: common_enums::CountryAlpha2,
pub co_badged_card_data: Option<DebitRoutingRequestData>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct DebitRoutingRequestData {
pub co_badged_card_networks: Vec<common_enums::CardNetwork>,
pub issuer_country: common_enums::CountryAlpha2,
pub is_regulated: bool,
pub regulated_name: Option<common_enums::RegulatedName>,
pub card_type: common_enums::CardType,
}
#[derive(Debug, Serialize, Deserialize)]

View File

@ -985,6 +985,15 @@ pub struct CardDetailsPaymentMethod {
pub card_type: Option<String>,
#[serde(default = "saved_in_locker_default")]
pub saved_to_locker: bool,
pub co_badged_card_data: Option<CoBadgedCardData>,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
pub struct CoBadgedCardData {
pub co_badged_card_networks: Vec<api_enums::CardNetwork>,
pub issuer_country_code: common_enums::CountryAlpha2,
pub is_regulated: bool,
pub regulated_name: Option<common_enums::RegulatedName>,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)]
@ -1313,6 +1322,7 @@ impl From<CardDetail> for CardDetailsPaymentMethod {
card_network: item.card_network,
card_type: item.card_type.map(|card| card.to_string()),
saved_to_locker: true,
co_badged_card_data: None,
}
}
}
@ -1321,8 +1331,10 @@ impl From<CardDetail> for CardDetailsPaymentMethod {
any(feature = "v1", feature = "v2"),
not(feature = "payment_methods_v2")
))]
impl From<CardDetailFromLocker> for CardDetailsPaymentMethod {
fn from(item: CardDetailFromLocker) -> Self {
impl From<(CardDetailFromLocker, Option<&CoBadgedCardData>)> for CardDetailsPaymentMethod {
fn from(
(item, co_badged_card_data): (CardDetailFromLocker, Option<&CoBadgedCardData>),
) -> Self {
Self {
issuer_country: item.issuer_country,
last4_digits: item.last4_digits,
@ -1335,6 +1347,7 @@ impl From<CardDetailFromLocker> for CardDetailsPaymentMethod {
card_network: item.card_network,
card_type: item.card_type,
saved_to_locker: item.saved_to_locker,
co_badged_card_data: co_badged_card_data.cloned(),
}
}
}
@ -1354,6 +1367,7 @@ impl From<CardDetailFromLocker> for CardDetailsPaymentMethod {
card_network: item.card_network,
card_type: item.card_type,
saved_to_locker: item.saved_to_locker,
co_badged_card_data: None,
}
}
}