Network Token Payment Method

This commit is contained in:
Sagnik Mitra
2025-10-24 14:02:25 +05:30
parent 59628332de
commit 79a72e9f2e
31 changed files with 321 additions and 23 deletions

View File

@ -126,6 +126,10 @@ pub enum RecurringDetails {
/// Network transaction ID and Card Details for MIT payments when payment_method_data
/// is not stored in the application
NetworkTransactionIdAndCardDetails(NetworkTransactionIdAndCardDetails),
/// Network transaction ID and Network Token Details for MIT payments when payment_method_data
/// is not stored in the application
NetworkTransactionIdAndNetworkTokenDetails(NetworkTransactionIdAndNetworkTokenDetails),
}
/// Processor payment token for MIT payments where payment_method_data is not available
@ -181,8 +185,32 @@ pub struct NetworkTransactionIdAndCardDetails {
pub network_transaction_id: Secret<String>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema, PartialEq, Eq)]
pub struct NetworkTransactionIdAndNetworkTokenDetails {
/// The Network Token
#[schema(value_type = String, example = "4242424242424242")]
pub network_token: cards::CardNumber,
/// The token's expiry month
#[schema(value_type = String, example = "05")]
pub token_exp_month: Secret<String>,
/// The token's expiry year
#[schema(value_type = String, example = "24")]
pub token_exp_year: Secret<String>,
/// The network transaction ID provided by the card network during a Customer Initiated Transaction (CIT)
/// where `off_session` is true.
#[schema(value_type = String)]
pub network_transaction_id: Secret<String>,
}
impl RecurringDetails {
pub fn is_network_transaction_id_and_card_details_flow(self) -> bool {
matches!(self, Self::NetworkTransactionIdAndCardDetails(_))
}
pub fn is_network_transaction_id_and_network_token_details_flow(self) -> bool {
matches!(self, Self::NetworkTransactionIdAndNetworkTokenDetails(_))
}
}

View File

@ -2689,6 +2689,7 @@ mod payment_method_data_serde {
| PaymentMethodData::Upi(_)
| PaymentMethodData::Voucher(_)
| PaymentMethodData::Card(_)
| PaymentMethodData::NetworkToken(_)
| PaymentMethodData::MandatePayment
| PaymentMethodData::OpenBanking(_)
| PaymentMethodData::Wallet(_) => {
@ -2821,6 +2822,48 @@ pub struct VaultToken {
pub card_holder_name: Option<Secret<String>>,
}
#[derive(
Default,
Eq,
PartialEq,
Clone,
Debug,
serde::Deserialize,
serde::Serialize,
ToSchema,
)]
pub struct NetworkTokenData {
/// The network token
#[schema(value_type = String, example = "4242424242424242")]
pub network_token: CardNumber,
/// The token's expiry month
#[schema(value_type = String, example = "05")]
pub token_exp_month: Secret<String>,
/// The token's expiry year
#[schema(value_type = String, example = "24")]
pub token_exp_year: Secret<String>,
/// The token cryptogram
#[schema(value_type = Option<String>)]
pub token_cryptogram: Option<Secret<String>>,
}
#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct NetworkTokenResponse {
pub token_last_four: Option<String>,
#[schema(value_type = Option<String>)]
pub token_exp_month: Option<Secret<String>>,
#[schema(value_type = Option<String>)]
pub token_exp_year: Option<Secret<String>>,
#[schema(value_type = Option<String>)]
pub token_cryptogram: Option<Secret<String>>,
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema, Eq, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum PaymentMethodData {
@ -2858,6 +2901,8 @@ pub enum PaymentMethodData {
OpenBanking(OpenBankingData),
#[schema(title = "MobilePayment")]
MobilePayment(MobilePaymentData),
#[schema(title = "NetworkToken")]
NetworkToken(NetworkTokenData),
}
pub trait GetAddressFromPaymentMethodData {
@ -2883,7 +2928,8 @@ impl GetAddressFromPaymentMethodData for PaymentMethodData {
| Self::CardToken(_)
| Self::OpenBanking(_)
| Self::MandatePayment
| Self::MobilePayment(_) => None,
| Self::MobilePayment(_)
| Self::NetworkToken(_) => None,
}
}
}
@ -2922,6 +2968,7 @@ impl PaymentMethodData {
Self::GiftCard(_) => Some(api_enums::PaymentMethod::GiftCard),
Self::OpenBanking(_) => Some(api_enums::PaymentMethod::OpenBanking),
Self::MobilePayment(_) => Some(api_enums::PaymentMethod::MobilePayment),
Self::NetworkToken(_) => Some(api_enums::PaymentMethod::NetworkToken),
Self::CardToken(_) | Self::MandatePayment => None,
}
}
@ -3292,6 +3339,10 @@ pub enum AdditionalPaymentData {
#[serde(flatten)]
details: Option<MobilePaymentData>,
},
NetworkToken {
#[serde(flatten)]
details: Option<NetworkTokenData>,
}
}
impl AdditionalPaymentData {
@ -4543,7 +4594,8 @@ where
| PaymentMethodDataResponse::Wallet(_)
| PaymentMethodDataResponse::BankTransfer(_)
| PaymentMethodDataResponse::OpenBanking(_)
| PaymentMethodDataResponse::Voucher(_) => {
| PaymentMethodDataResponse::Voucher(_)
| PaymentMethodDataResponse::NetworkToken(_) => {
payment_method_data_response.serialize(serializer)
}
}
@ -4576,6 +4628,7 @@ pub enum PaymentMethodDataResponse {
CardToken(Box<CardTokenResponse>),
OpenBanking(Box<OpenBankingResponse>),
MobilePayment(Box<MobilePaymentResponse>),
NetworkToken(Box<NetworkTokenResponse>),
}
#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)]
@ -7141,6 +7194,25 @@ impl From<AdditionalPaymentData> for PaymentMethodDataResponse {
AdditionalPaymentData::MobilePayment { details } => {
Self::MobilePayment(Box::new(MobilePaymentResponse { details }))
}
AdditionalPaymentData::NetworkToken { details } => {
Self::NetworkToken(Box::new(NetworkTokenResponse {
token_last_four: details
.clone()
.map(|dt| dt.network_token
.peek()
.clone()
.chars()
.rev()
.take(4)
.collect::<String>()
.chars()
.rev()
.collect::<String>()),
token_exp_month: details.clone().map(|dt| dt.token_exp_month.clone()),
token_exp_year: details.clone().map(|dt| dt.token_exp_year.clone()),
token_cryptogram: details.clone().and_then(|dt| dt.token_cryptogram.clone()),
}))
}
}
}
}