diff --git a/crates/api_models/src/mandates.rs b/crates/api_models/src/mandates.rs index 6785232664..60e715e2bb 100644 --- a/crates/api_models/src/mandates.rs +++ b/crates/api_models/src/mandates.rs @@ -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, } +#[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, + + /// The token's expiry year + #[schema(value_type = String, example = "24")] + pub token_exp_year: Secret, + + /// 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, +} + 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(_)) + } } diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 6a51e5c5d7..89ef5598c2 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -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>, } +#[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, + + /// The token's expiry year + #[schema(value_type = String, example = "24")] + pub token_exp_year: Secret, + + /// The token cryptogram + #[schema(value_type = Option)] + pub token_cryptogram: Option>, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct NetworkTokenResponse { + pub token_last_four: Option, + + #[schema(value_type = Option)] + pub token_exp_month: Option>, + + #[schema(value_type = Option)] + pub token_exp_year: Option>, + + #[schema(value_type = Option)] + pub token_cryptogram: Option>, +} + #[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, }, + NetworkToken { + #[serde(flatten)] + details: Option, + } } 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), OpenBanking(Box), MobilePayment(Box), + NetworkToken(Box), } #[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] @@ -7141,6 +7194,25 @@ impl From 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::() + .chars() + .rev() + .collect::()), + 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()), + })) + } } } } diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index a42a266114..477341b5d4 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -2079,6 +2079,7 @@ pub enum PaymentMethodType { InstantBankTransferPoland, RevolutPay, IndonesianBankTransfer, + NetworkToken, } impl PaymentMethodType { @@ -2202,6 +2203,7 @@ impl PaymentMethodType { Self::DirectCarrierBilling => "Direct Carrier Billing", Self::RevolutPay => "RevolutPay", Self::IndonesianBankTransfer => "Indonesian Bank Transfer", + Self::NetworkToken => "Network Token", }; display_name.to_string() } @@ -2248,6 +2250,7 @@ pub enum PaymentMethod { GiftCard, OpenBanking, MobilePayment, + NetworkToken, } /// Indicates the gateway system through which the payment is processed. diff --git a/crates/common_enums/src/transformers.rs b/crates/common_enums/src/transformers.rs index 4eac0fb1fc..ae76f45202 100644 --- a/crates/common_enums/src/transformers.rs +++ b/crates/common_enums/src/transformers.rs @@ -1907,6 +1907,7 @@ impl From for PaymentMethod { PaymentMethodType::DirectCarrierBilling => Self::MobilePayment, PaymentMethodType::RevolutPay => Self::Wallet, PaymentMethodType::IndonesianBankTransfer => Self::BankTransfer, + PaymentMethodType::NetworkToken => Self::NetworkToken, } } } diff --git a/crates/connector_configs/src/response_modifier.rs b/crates/connector_configs/src/response_modifier.rs index 8a763b5921..9c5cfe7a24 100644 --- a/crates/connector_configs/src/response_modifier.rs +++ b/crates/connector_configs/src/response_modifier.rs @@ -234,6 +234,9 @@ impl ConnectorApiIntegrationPayload { } } } + api_models::enums::PaymentMethod::NetworkToken => { + // NetworkToken is not yet supported in the response modifier + } } } } diff --git a/crates/connector_configs/src/transformer.rs b/crates/connector_configs/src/transformer.rs index dce521efa2..bda2cec04b 100644 --- a/crates/connector_configs/src/transformer.rs +++ b/crates/connector_configs/src/transformer.rs @@ -151,7 +151,8 @@ impl DashboardRequestPayload { | PaymentMethod::GiftCard | PaymentMethod::OpenBanking | PaymentMethod::CardRedirect - | PaymentMethod::MobilePayment => { + | PaymentMethod::MobilePayment + | PaymentMethod::NetworkToken => { if let Some(provider) = payload.provider { let val = Self::transform_payment_method( request.connector, diff --git a/crates/euclid/src/dssa/graph.rs b/crates/euclid/src/dssa/graph.rs index 526667d362..65edf91637 100644 --- a/crates/euclid/src/dssa/graph.rs +++ b/crates/euclid/src/dssa/graph.rs @@ -82,6 +82,7 @@ impl cgraph::NodeViz for dir::DirValue { } Self::AcquirerCountry(acquirer_country) => acquirer_country.to_string(), Self::AcquirerFraudRate(acquirer_fraud_rate) => acquirer_fraud_rate.number.to_string(), + Self::NetworkTokenType(ntt) => ntt.to_string(), } } } diff --git a/crates/euclid/src/frontend/ast/lowering.rs b/crates/euclid/src/frontend/ast/lowering.rs index 41df1758c3..5eb8855848 100644 --- a/crates/euclid/src/frontend/ast/lowering.rs +++ b/crates/euclid/src/frontend/ast/lowering.rs @@ -275,6 +275,7 @@ fn lower_comparison_inner( dir::DirKeyKind::CustomerDeviceDisplaySize => lower_enum!(CustomerDeviceDisplaySize, value), dir::DirKeyKind::AcquirerCountry => lower_enum!(AcquirerCountry, value), dir::DirKeyKind::AcquirerFraudRate => lower_number!(AcquirerFraudRate, value, comparison), + dir::DirKeyKind::NetworkTokenType => lower_enum!(NetworkTokenType, value), } } diff --git a/crates/euclid/src/frontend/dir.rs b/crates/euclid/src/frontend/dir.rs index 62dbefab3f..95955c1678 100644 --- a/crates/euclid/src/frontend/dir.rs +++ b/crates/euclid/src/frontend/dir.rs @@ -334,6 +334,8 @@ pub enum DirKeyKind { )] #[serde(rename = "acquirer_fraud_rate")] AcquirerFraudRate, + #[serde(rename = "network_token")] + NetworkTokenType, } pub trait EuclidDirFilter: Sized @@ -391,6 +393,7 @@ impl DirKeyKind { Self::CustomerDeviceDisplaySize => types::DataType::EnumVariant, Self::AcquirerCountry => types::DataType::EnumVariant, Self::AcquirerFraudRate => types::DataType::Number, + Self::NetworkTokenType => types::DataType::EnumVariant, } } pub fn get_value_set(&self) -> Option> { @@ -555,6 +558,11 @@ impl DirKeyKind { .collect(), ), Self::AcquirerFraudRate => None, + Self::NetworkTokenType => Some( + enums::NetworkTokenType::iter() + .map(DirValue::NetworkTokenType) + .collect(), + ), } } } @@ -640,6 +648,8 @@ pub enum DirValue { AcquirerCountry(enums::Country), #[serde(rename = "acquirer_fraud_rate")] AcquirerFraudRate(types::NumValue), + #[serde(rename = "network_token")] + NetworkTokenType(enums::NetworkTokenType), } impl DirValue { @@ -683,6 +693,7 @@ impl DirValue { Self::CustomerDeviceDisplaySize(_) => (DirKeyKind::CustomerDeviceDisplaySize, None), Self::AcquirerCountry(_) => (DirKeyKind::AcquirerCountry, None), Self::AcquirerFraudRate(_) => (DirKeyKind::AcquirerFraudRate, None), + Self::NetworkTokenType(_) => (DirKeyKind::NetworkTokenType, None), }; DirKey::new(kind, data) @@ -727,6 +738,7 @@ impl DirValue { Self::CustomerDeviceDisplaySize(_) => None, Self::AcquirerCountry(_) => None, Self::AcquirerFraudRate(_) => None, + Self::NetworkTokenType(_) => None, } } @@ -782,6 +794,7 @@ impl DirValue { (Self::CustomerDeviceDisplaySize(s1), Self::CustomerDeviceDisplaySize(s2)) => s1 == s2, (Self::AcquirerCountry(c1), Self::AcquirerCountry(c2)) => c1 == c2, (Self::AcquirerFraudRate(r1), Self::AcquirerFraudRate(r2)) => r1 == r2, + (Self::NetworkTokenType(ntt1), Self::NetworkTokenType(ntt2)) => ntt1 == ntt2, _ => false, } } diff --git a/crates/euclid/src/frontend/dir/enums.rs b/crates/euclid/src/frontend/dir/enums.rs index 8c0240e98c..12146f7fe2 100644 --- a/crates/euclid/src/frontend/dir/enums.rs +++ b/crates/euclid/src/frontend/dir/enums.rs @@ -291,6 +291,25 @@ pub enum MobilePaymentType { DirectCarrierBilling, } +#[derive( + Clone, + Debug, + Hash, + PartialEq, + Eq, + strum::Display, + strum::VariantNames, + strum::EnumIter, + strum::EnumString, + serde::Serialize, + serde::Deserialize, +)] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum NetworkTokenType { + NetworkToken, +} + #[derive( Clone, Debug, @@ -504,6 +523,7 @@ collect_variants!(BankTransferType); collect_variants!(CardRedirectType); collect_variants!(OpenBankingType); collect_variants!(MobilePaymentType); +collect_variants!(NetworkTokenType); collect_variants!(CustomerDeviceType); collect_variants!(CustomerDevicePlatform); collect_variants!(CustomerDeviceDisplaySize); diff --git a/crates/euclid/src/frontend/dir/lowering.rs b/crates/euclid/src/frontend/dir/lowering.rs index 8fe8bdb229..9f529ec7bf 100644 --- a/crates/euclid/src/frontend/dir/lowering.rs +++ b/crates/euclid/src/frontend/dir/lowering.rs @@ -167,6 +167,14 @@ impl From for global_enums::PaymentMethodType { } } +impl From for global_enums::PaymentMethodType { + fn from(value: enums::NetworkTokenType) -> Self { + match value { + enums::NetworkTokenType::NetworkToken => Self::NetworkToken, + } + } +} + impl From for global_enums::PaymentMethodType { fn from(value: enums::BankRedirectType) -> Self { match value { @@ -286,6 +294,7 @@ fn lower_value(dir_value: dir::DirValue) -> Result EuclidValue::AcquirerCountry(country), dir::DirValue::AcquirerFraudRate(num_value) => EuclidValue::AcquirerFraudRate(num_value), + dir::DirValue::NetworkTokenType(nt) => EuclidValue::PaymentMethodType(nt.into()), }) } diff --git a/crates/euclid/src/frontend/dir/transformers.rs b/crates/euclid/src/frontend/dir/transformers.rs index b67ccb5c3a..23fc22a4c4 100644 --- a/crates/euclid/src/frontend/dir/transformers.rs +++ b/crates/euclid/src/frontend/dir/transformers.rs @@ -47,7 +47,8 @@ impl IntoDirValue for (global_enums::PaymentMethodType, global_enums::PaymentMet | global_enums::PaymentMethod::Voucher | global_enums::PaymentMethod::OpenBanking | global_enums::PaymentMethod::MobilePayment - | global_enums::PaymentMethod::GiftCard => Err(AnalysisErrorType::NotSupported), + | global_enums::PaymentMethod::GiftCard + | global_enums::PaymentMethod::NetworkToken => Err(AnalysisErrorType::NotSupported), }, global_enums::PaymentMethodType::Bacs => match self.1 { global_enums::PaymentMethod::BankDebit => Ok(dirval!(BankDebitType = Bacs)), @@ -64,7 +65,8 @@ impl IntoDirValue for (global_enums::PaymentMethodType, global_enums::PaymentMet | global_enums::PaymentMethod::Voucher | global_enums::PaymentMethod::OpenBanking | global_enums::PaymentMethod::MobilePayment - | global_enums::PaymentMethod::GiftCard => Err(AnalysisErrorType::NotSupported), + | global_enums::PaymentMethod::GiftCard + | global_enums::PaymentMethod::NetworkToken => Err(AnalysisErrorType::NotSupported), }, global_enums::PaymentMethodType::Becs => Ok(dirval!(BankDebitType = Becs)), global_enums::PaymentMethodType::Sepa => Ok(dirval!(BankDebitType = Sepa)), @@ -208,6 +210,7 @@ impl IntoDirValue for (global_enums::PaymentMethodType, global_enums::PaymentMet global_enums::PaymentMethodType::BhnCardNetwork => { Ok(dirval!(GiftCardType = BhnCardNetwork)) } + global_enums::PaymentMethodType::NetworkToken => Ok(dirval!(NetworkTokenType = NetworkToken)), } } } diff --git a/crates/euclid_wasm/src/lib.rs b/crates/euclid_wasm/src/lib.rs index 2aaee43f7e..be3d4d00c2 100644 --- a/crates/euclid_wasm/src/lib.rs +++ b/crates/euclid_wasm/src/lib.rs @@ -331,6 +331,7 @@ pub fn get_variant_values(key: &str) -> Result { dir::DirKeyKind::CustomerDeviceDisplaySize => { dir_enums::CustomerDeviceDisplaySize::VARIANTS } + dir::DirKeyKind::NetworkTokenType => dir_enums::MobilePaymentType::VARIANTS, dir::DirKeyKind::PaymentAmount | dir::DirKeyKind::Connector diff --git a/crates/hyperswitch_connectors/src/connectors/adyen.rs b/crates/hyperswitch_connectors/src/connectors/adyen.rs index bb4cdbda26..33a8cbd959 100644 --- a/crates/hyperswitch_connectors/src/connectors/adyen.rs +++ b/crates/hyperswitch_connectors/src/connectors/adyen.rs @@ -184,7 +184,8 @@ impl ConnectorValidation for Adyen { | PaymentMethodType::Sepa | PaymentMethodType::Vipps | PaymentMethodType::Venmo - | PaymentMethodType::Paypal => match capture_method { + | PaymentMethodType::Paypal + | PaymentMethodType::NetworkToken => match capture_method { enums::CaptureMethod::Automatic | enums::CaptureMethod::SequentialAutomatic | enums::CaptureMethod::Manual @@ -3129,6 +3130,17 @@ static ADYEN_SUPPORTED_PAYMENT_METHODS: LazyLock = Lazy }, ); + adyen_supported_payment_methods.add( + enums::PaymentMethod::NetworkToken, + PaymentMethodType::NetworkToken, + PaymentMethodDetails { + mandates: enums::FeatureStatus::Supported, + refunds: enums::FeatureStatus::Supported, + supported_capture_methods: supported_capture_methods1.clone(), + specific_features: None, + }, + ); + adyen_supported_payment_methods }); diff --git a/crates/hyperswitch_connectors/src/connectors/bankofamerica/transformers.rs b/crates/hyperswitch_connectors/src/connectors/bankofamerica/transformers.rs index 30454d3aae..275afad2d4 100644 --- a/crates/hyperswitch_connectors/src/connectors/bankofamerica/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/bankofamerica/transformers.rs @@ -412,7 +412,8 @@ impl | common_enums::PaymentMethod::Upi | common_enums::PaymentMethod::Voucher | common_enums::PaymentMethod::OpenBanking - | common_enums::PaymentMethod::GiftCard => None, + | common_enums::PaymentMethod::GiftCard + | common_enums::PaymentMethod::NetworkToken => None, }; Ok(Self { @@ -1716,7 +1717,8 @@ impl | common_enums::PaymentMethod::Upi | common_enums::PaymentMethod::Voucher | common_enums::PaymentMethod::OpenBanking - | common_enums::PaymentMethod::GiftCard => None, + | common_enums::PaymentMethod::GiftCard + | common_enums::PaymentMethod::NetworkToken => None, }; Ok(Self { @@ -1923,7 +1925,8 @@ impl | common_enums::PaymentMethod::Upi | common_enums::PaymentMethod::Voucher | common_enums::PaymentMethod::OpenBanking - | common_enums::PaymentMethod::GiftCard => None, + | common_enums::PaymentMethod::GiftCard + | common_enums::PaymentMethod::NetworkToken => None, }; let risk_info: Option = None; diff --git a/crates/hyperswitch_connectors/src/connectors/barclaycard/transformers.rs b/crates/hyperswitch_connectors/src/connectors/barclaycard/transformers.rs index b14d6c7409..a9823f674c 100644 --- a/crates/hyperswitch_connectors/src/connectors/barclaycard/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/barclaycard/transformers.rs @@ -2102,7 +2102,8 @@ impl | common_enums::PaymentMethod::Upi | common_enums::PaymentMethod::Voucher | common_enums::PaymentMethod::OpenBanking - | common_enums::PaymentMethod::GiftCard => None, + | common_enums::PaymentMethod::GiftCard + | common_enums::PaymentMethod::NetworkToken => None, }; Ok(Self { @@ -2322,7 +2323,8 @@ impl | common_enums::PaymentMethod::Upi | common_enums::PaymentMethod::Voucher | common_enums::PaymentMethod::OpenBanking - | common_enums::PaymentMethod::GiftCard => None, + | common_enums::PaymentMethod::GiftCard + | common_enums::PaymentMethod::NetworkToken => None, }; let risk_info: Option = None; diff --git a/crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs b/crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs index 4f9b555353..9d21b5ff77 100644 --- a/crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs @@ -513,7 +513,8 @@ impl TryFrom<&BraintreeRouterData<&types::PaymentsCompleteAuthorizeRouterData>> | api_models::enums::PaymentMethod::Upi | api_models::enums::PaymentMethod::OpenBanking | api_models::enums::PaymentMethod::Voucher - | api_models::enums::PaymentMethod::GiftCard => { + | api_models::enums::PaymentMethod::GiftCard + | api_models::enums::PaymentMethod::NetworkToken => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message( "complete authorize flow", diff --git a/crates/hyperswitch_connectors/src/connectors/cybersource.rs b/crates/hyperswitch_connectors/src/connectors/cybersource.rs index 03f3de84d6..282529e41b 100644 --- a/crates/hyperswitch_connectors/src/connectors/cybersource.rs +++ b/crates/hyperswitch_connectors/src/connectors/cybersource.rs @@ -2259,6 +2259,17 @@ static CYBERSOURCE_SUPPORTED_PAYMENT_METHODS: LazyLock }, ); + cybersource_supported_payment_methods.add( + enums::PaymentMethod::NetworkToken, + enums::PaymentMethodType::NetworkToken, + PaymentMethodDetails { + mandates: enums::FeatureStatus::Supported, + refunds: enums::FeatureStatus::Supported, + supported_capture_methods: supported_capture_methods.clone(), + specific_features: None, + }, + ); + cybersource_supported_payment_methods }); diff --git a/crates/hyperswitch_connectors/src/connectors/klarna.rs b/crates/hyperswitch_connectors/src/connectors/klarna.rs index 159c1d307e..6af8fd6ccd 100644 --- a/crates/hyperswitch_connectors/src/connectors/klarna.rs +++ b/crates/hyperswitch_connectors/src/connectors/klarna.rs @@ -652,7 +652,8 @@ impl ConnectorIntegration Err(error_stack::report!(errors::ConnectorError::NotSupported { message: payment_method_type.to_string(), connector: "klarna", @@ -778,7 +779,8 @@ impl ConnectorIntegration Err(error_stack::report!(errors::ConnectorError::NotSupported { message: payment_method_type.to_string(), connector: "klarna", @@ -910,7 +912,8 @@ impl ConnectorIntegration Err(error_stack::report!(errors::ConnectorError::NotSupported { message: payment_method_type.to_string(), connector: "klarna", diff --git a/crates/hyperswitch_connectors/src/connectors/payeezy/transformers.rs b/crates/hyperswitch_connectors/src/connectors/payeezy/transformers.rs index 2d97b2fb9b..d87c0ef545 100644 --- a/crates/hyperswitch_connectors/src/connectors/payeezy/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/payeezy/transformers.rs @@ -152,7 +152,8 @@ impl TryFrom<&PayeezyRouterData<&PaymentsAuthorizeRouterData>> for PayeezyPaymen | PaymentMethod::Upi | PaymentMethod::Voucher | PaymentMethod::OpenBanking - | PaymentMethod::GiftCard => { + | PaymentMethod::GiftCard + | PaymentMethod::NetworkToken => { Err(ConnectorError::NotImplemented("Payment methods".to_string()).into()) } } diff --git a/crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs b/crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs index 23d06999d6..7a397d2664 100644 --- a/crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs @@ -1271,7 +1271,8 @@ impl TryFrom<&PaypalRouterData<&PaymentsAuthorizeRouterData>> for PaypalPayments | enums::PaymentMethodType::Flexiti | enums::PaymentMethodType::RevolutPay | enums::PaymentMethodType::Breadpay - | enums::PaymentMethodType::UpiQr => { + | enums::PaymentMethodType::UpiQr + | enums::PaymentMethodType::NetworkToken => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("paypal"), )) diff --git a/crates/hyperswitch_connectors/src/connectors/peachpayments.rs b/crates/hyperswitch_connectors/src/connectors/peachpayments.rs index dd5c4869cf..5583687cdd 100644 --- a/crates/hyperswitch_connectors/src/connectors/peachpayments.rs +++ b/crates/hyperswitch_connectors/src/connectors/peachpayments.rs @@ -615,6 +615,17 @@ static PEACHPAYMENTS_SUPPORTED_PAYMENT_METHODS: LazyLock for StripePaymentMethodType { | enums::PaymentMethodType::Flexiti | enums::PaymentMethodType::Mifinity | enums::PaymentMethodType::Breadpay - | enums::PaymentMethodType::UpiQr => Err(ConnectorError::NotImplemented( + | enums::PaymentMethodType::UpiQr + | enums::PaymentMethodType::NetworkToken => Err(ConnectorError::NotImplemented( get_unimplemented_payment_method_error_message("stripe"), ) .into()), diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index 76f73293a5..7cd5610b96 100644 --- a/crates/hyperswitch_domain_models/src/payment_method_data.rs +++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs @@ -201,7 +201,8 @@ impl CardDetailsForNetworkTransactionId { ) => Some(network_transaction_id_and_card_details), mandates::RecurringDetails::MandateId(_) | mandates::RecurringDetails::PaymentMethodId(_) - | mandates::RecurringDetails::ProcessorPaymentToken(_) => None, + | mandates::RecurringDetails::ProcessorPaymentToken(_) + | mandates::RecurringDetails::NetworkTransactionIdAndNetworkTokenDetails(_) => None, }?; let mandate_reference_id = api_models::payments::MandateReferenceId::NetworkMandateId( @@ -963,6 +964,9 @@ impl From for PaymentMethodData { api_models::payments::PaymentMethodData::MobilePayment(mobile_payment_data) => { Self::MobilePayment(From::from(mobile_payment_data)) } + api_models::payments::PaymentMethodData::NetworkToken(network_token_data) => { + Self::NetworkToken(From::from(network_token_data)) + } } } } @@ -1969,6 +1973,69 @@ impl From for api_models::payments::MobilePaymentData { } } +#[cfg(feature = "v1")] +impl From for NetworkTokenData { + fn from(network_token_data: api_models::payments::NetworkTokenData) -> Self { + Self { + token_number: network_token_data.network_token, + token_exp_month: network_token_data.token_exp_month, + token_exp_year: network_token_data.token_exp_year, + token_cryptogram: network_token_data.token_cryptogram, + card_issuer: None, + card_network: None, + card_type: None, + card_issuing_country: None, + bank_code: None, + nick_name: None, + eci: None, + } + } +} + +#[cfg(feature = "v2")] +impl From for NetworkTokenData { + fn from(network_token_data: api_models::payments::NetworkTokenData) -> Self { + Self { + network_token: cards::NetworkToken::from(network_token_data.network_token), + network_token_exp_month: network_token_data.token_exp_month, + network_token_exp_year: network_token_data.token_exp_year, + cryptogram: network_token_data.token_cryptogram, + card_issuer: None, + card_network: None, + card_type: None, + card_issuing_country: None, + bank_code: None, + card_holder_name: None, + nick_name: None, + eci: None, + } + } +} + +#[cfg(feature = "v1")] +impl From for api_models::payments::NetworkTokenData { + fn from(network_token_data: NetworkTokenData) -> Self { + Self { + network_token: network_token_data.token_number, + token_exp_month: network_token_data.token_exp_month, + token_exp_year: network_token_data.token_exp_year, + token_cryptogram: network_token_data.token_cryptogram, + } + } +} + +#[cfg(feature = "v2")] +impl From for api_models::payments::NetworkTokenData { + fn from(network_token_data: NetworkTokenData) -> Self { + Self { + network_token: network_token_data.network_token.into(), + token_exp_month: network_token_data.network_token_exp_month, + token_exp_year: network_token_data.network_token_exp_year, + token_cryptogram: network_token_data.cryptogram, + } + } +} + #[derive(Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct TokenizedCardValue1 { diff --git a/crates/kgraph_utils/src/mca.rs b/crates/kgraph_utils/src/mca.rs index fd15c3415b..c7eeae530c 100644 --- a/crates/kgraph_utils/src/mca.rs +++ b/crates/kgraph_utils/src/mca.rs @@ -178,6 +178,7 @@ fn get_dir_value_payment_method( Ok(dirval!(MobilePaymentType = DirectCarrierBilling)) } api_enums::PaymentMethodType::RevolutPay => Ok(dirval!(WalletType = RevolutPay)), + api_enums::PaymentMethodType::NetworkToken => Ok(dirval!(NetworkTokenType = NetworkToken)), } } @@ -716,6 +717,7 @@ fn global_vec_pmt( global_vector.append(collect_global_variants!(CardRedirectType)); global_vector.append(collect_global_variants!(OpenBankingType)); global_vector.append(collect_global_variants!(MobilePaymentType)); + global_vector.append(collect_global_variants!(NetworkTokenType)); global_vector.push(dir::DirValue::PaymentMethod( dir::enums::PaymentMethod::Card, )); diff --git a/crates/kgraph_utils/src/transformers.rs b/crates/kgraph_utils/src/transformers.rs index aa0d81b774..e4eea31716 100644 --- a/crates/kgraph_utils/src/transformers.rs +++ b/crates/kgraph_utils/src/transformers.rs @@ -105,6 +105,7 @@ impl IntoDirValue for api_enums::PaymentMethod { Self::CardRedirect => Ok(dirval!(PaymentMethod = CardRedirect)), Self::OpenBanking => Ok(dirval!(PaymentMethod = OpenBanking)), Self::MobilePayment => Ok(dirval!(PaymentMethod = MobilePayment)), + Self::NetworkToken => Ok(dirval!(PaymentMethod = NetworkToken)), } } } @@ -170,7 +171,8 @@ impl IntoDirValue for (api_enums::PaymentMethodType, api_enums::PaymentMethod) { | api_enums::PaymentMethod::MobilePayment | api_enums::PaymentMethod::Voucher | api_enums::PaymentMethod::OpenBanking - | api_enums::PaymentMethod::GiftCard => Err(KgraphError::ContextConstructionError( + | api_enums::PaymentMethod::GiftCard + | api_enums::PaymentMethod::NetworkToken => Err(KgraphError::ContextConstructionError( Box::new(AnalysisErrorType::NotSupported), )), }, @@ -189,7 +191,8 @@ impl IntoDirValue for (api_enums::PaymentMethodType, api_enums::PaymentMethod) { | api_enums::PaymentMethod::MobilePayment | api_enums::PaymentMethod::Voucher | api_enums::PaymentMethod::OpenBanking - | api_enums::PaymentMethod::GiftCard => Err(KgraphError::ContextConstructionError( + | api_enums::PaymentMethod::GiftCard + | api_enums::PaymentMethod::NetworkToken => Err(KgraphError::ContextConstructionError( Box::new(AnalysisErrorType::NotSupported), )), }, @@ -324,6 +327,9 @@ impl IntoDirValue for (api_enums::PaymentMethodType, api_enums::PaymentMethod) { api_enums::PaymentMethodType::IndonesianBankTransfer => { Ok(dirval!(BankTransferType = IndonesianBankTransfer)) } + api_enums::PaymentMethodType::NetworkToken => { + Ok(dirval!(NetworkTokenType = NetworkToken)) + } } } } diff --git a/crates/payment_methods/src/helpers.rs b/crates/payment_methods/src/helpers.rs index 0bdcf99086..1de3d2be75 100644 --- a/crates/payment_methods/src/helpers.rs +++ b/crates/payment_methods/src/helpers.rs @@ -240,6 +240,10 @@ pub fn validate_payment_method_type_against_payment_method( payment_method_type, api_enums::PaymentMethodType::DirectCarrierBilling ), + api_enums::PaymentMethod::NetworkToken => matches!( + payment_method_type, + api_enums::PaymentMethodType::NetworkToken + ), } } diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 84b8bed45b..a8eb0c7a14 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -570,6 +570,10 @@ pub async fn get_token_pm_type_mandate_details( Some(payment_method_info), ) } + RecurringDetails::NetworkTransactionIdAndNetworkTokenDetails(_) => { + // NetworkToken is not yet fully implemented for recurring details + (None, request.payment_method, None, None, None, None, None) + } } } None => { @@ -5370,7 +5374,11 @@ pub async fn get_additional_payment_data( details: Some(mobile_payment.to_owned().into()), }, )), - domain::PaymentMethodData::NetworkToken(_) => Ok(None), + domain::PaymentMethodData::NetworkToken(network_token) => Ok(Some( + api_models::payments::AdditionalPaymentData::NetworkToken { + details: Some(network_token.to_owned().into()), + }, + )), } } diff --git a/crates/router/src/core/payments/routing/utils.rs b/crates/router/src/core/payments/routing/utils.rs index d1998d0e51..1b0496cf1d 100644 --- a/crates/router/src/core/payments/routing/utils.rs +++ b/crates/router/src/core/payments/routing/utils.rs @@ -1000,6 +1000,12 @@ fn insert_dirvalue_param(params: &mut HashMap>, dv: di Some(ValueType::EnumVariant(v.to_string())), ); } + dir::DirValue::NetworkTokenType(v) => { + params.insert( + "network_token".to_string(), + Some(ValueType::EnumVariant(v.to_string())), + ); + } other => { // all other values can be ignored for now as they don't converge with // payment method type diff --git a/crates/router/src/core/payout_link.rs b/crates/router/src/core/payout_link.rs index e96e1229e4..0303b12355 100644 --- a/crates/router/src/core/payout_link.rs +++ b/crates/router/src/core/payout_link.rs @@ -419,7 +419,8 @@ pub async fn filter_payout_methods( | common_enums::PaymentMethod::Upi | common_enums::PaymentMethod::Voucher | common_enums::PaymentMethod::OpenBanking - | common_enums::PaymentMethod::GiftCard => continue, + | common_enums::PaymentMethod::GiftCard + | common_enums::PaymentMethod::NetworkToken => continue, } } } diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 910ec21335..55d9f294f3 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -383,6 +383,7 @@ impl ForeignFrom for api_enums::PaymentMethod { | api_enums::PaymentMethodType::PromptPay | api_enums::PaymentMethodType::VietQr => Self::RealTimePayment, api_enums::PaymentMethodType::DirectCarrierBilling => Self::MobilePayment, + api_enums::PaymentMethodType::NetworkToken => Self::NetworkToken, } } } @@ -415,6 +416,7 @@ impl ForeignTryFrom for api_enums::PaymentMethod { message: ("Mandate payments cannot have payment_method_data field".to_string()), }) } + payments::PaymentMethodData::NetworkToken(..) => Ok(Self::NetworkToken), } } }