From 684df7779c8e4efdbbdfc193bfca9ecd600cf72b Mon Sep 17 00:00:00 2001 From: Prasunna Soppa Date: Thu, 12 Dec 2024 13:16:57 +0530 Subject: [PATCH 1/5] add vault operation in payment_data --- crates/router/src/core/payments.rs | 12 ++++++++++++ .../src/core/payments/operations/payment_approve.rs | 1 + .../src/core/payments/operations/payment_cancel.rs | 1 + .../src/core/payments/operations/payment_capture.rs | 1 + .../operations/payment_complete_authorize.rs | 1 + .../src/core/payments/operations/payment_confirm.rs | 1 + .../src/core/payments/operations/payment_create.rs | 1 + .../operations/payment_post_session_tokens.rs | 1 + .../src/core/payments/operations/payment_reject.rs | 1 + .../src/core/payments/operations/payment_session.rs | 1 + .../src/core/payments/operations/payment_start.rs | 1 + .../src/core/payments/operations/payment_status.rs | 1 + .../src/core/payments/operations/payment_update.rs | 1 + .../operations/payments_incremental_authorization.rs | 1 + .../src/core/payments/operations/tax_calculation.rs | 1 + crates/router/src/core/payments/transformers.rs | 4 ++-- 16 files changed, 28 insertions(+), 2 deletions(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index ceeb384ed214..f53d3d88bc72 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -4434,6 +4434,18 @@ where pub tax_data: Option, pub session_id: Option, pub service_details: Option, + pub vault_operation: Option, +} + +#[derive(Clone, serde::Serialize, Debug)] +pub enum PaymentMethodDataAction{ + VaultData(VaultData) +} + +#[derive(Clone, serde::Serialize, Debug)] +pub struct VaultData { + pub card_data: hyperswitch_domain_models::payment_method_data::Card, + pub network_token_data: hyperswitch_domain_models::payment_method_data::NetworkTokenData, } #[derive(Clone, serde::Serialize, Debug)] diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs index c830b7618d07..679deabf76e8 100644 --- a/crates/router/src/core/payments/operations/payment_approve.rs +++ b/crates/router/src/core/payments/operations/payment_approve.rs @@ -196,6 +196,7 @@ impl GetTracker, api::PaymentsCaptureR tax_data: None, session_id: None, service_details: None, + vault_operation:None }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs index c6679e481f1b..aa94e7edd023 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -207,6 +207,7 @@ impl GetTracker, api::PaymentsCancelRe tax_data: None, session_id: None, service_details: None, + vault_operation:None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index ebe49f59f649..159f89230dfd 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -256,6 +256,7 @@ impl GetTracker, api::Paymen tax_data: None, session_id: None, service_details: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_complete_authorize.rs b/crates/router/src/core/payments/operations/payment_complete_authorize.rs index 72c04c6a5497..9381acddafed 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -351,6 +351,7 @@ impl GetTracker, api::PaymentsRequest> tax_data: None, session_id: None, service_details: None, + vault_operation: None, }; let customer_details = Some(CustomerDetails { diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index a87fab9b17ad..c41e2f3fc5ca 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -823,6 +823,7 @@ impl GetTracker, api::PaymentsRequest> tax_data: None, session_id: None, service_details: request.ctp_service_details.clone(), + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index ed7b84e8329b..cd818080e65d 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -616,6 +616,7 @@ impl GetTracker, api::PaymentsRequest> tax_data: None, session_id: None, service_details: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs index 0e189583d0a2..bb063d70e812 100644 --- a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs +++ b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs @@ -167,6 +167,7 @@ impl GetTracker, api::PaymentsPostSess tax_data: None, session_id: None, service_details: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { operation: Box::new(self), diff --git a/crates/router/src/core/payments/operations/payment_reject.rs b/crates/router/src/core/payments/operations/payment_reject.rs index e5321b1f9847..16031010423d 100644 --- a/crates/router/src/core/payments/operations/payment_reject.rs +++ b/crates/router/src/core/payments/operations/payment_reject.rs @@ -194,6 +194,7 @@ impl GetTracker, PaymentsCancelRequest tax_data: None, session_id: None, service_details: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index 0e94fbe09c6f..dae8d7f487cb 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -214,6 +214,7 @@ impl GetTracker, api::PaymentsSessionR tax_data: None, session_id: None, service_details: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index 1da9a1a2264f..d0d05542a30b 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -201,6 +201,7 @@ impl GetTracker, api::PaymentsStartReq tax_data: None, session_id: None, service_details: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index dd28043ba2b8..3ac7ec71e24d 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -523,6 +523,7 @@ async fn get_tracker_for_sync< tax_data: None, session_id: None, service_details: None, + vault_operation:None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 0e60407aa7ca..902271778034 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -493,6 +493,7 @@ impl GetTracker, api::PaymentsRequest> tax_data: None, session_id: None, service_details: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs index 2c816ad39d1d..e7a0489d84d7 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -173,6 +173,7 @@ impl tax_data: None, session_id: None, service_details: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/tax_calculation.rs b/crates/router/src/core/payments/operations/tax_calculation.rs index 5b9c90f3add5..7db40764c1e9 100644 --- a/crates/router/src/core/payments/operations/tax_calculation.rs +++ b/crates/router/src/core/payments/operations/tax_calculation.rs @@ -181,6 +181,7 @@ impl tax_data: Some(tax_data), session_id: request.session_id.clone(), service_details: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { operation: Box::new(self), diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 70db7a581a20..5c1d24e5fd9d 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -2782,7 +2782,7 @@ impl TryFrom> for types::PaymentsAuthoriz } else { None }; - let payment_method_data = payment_data.payment_method_data.or_else(|| { + let payment_method_data = payment_data.payment_method_data.or_else(|| { // if payment_data.mandate_id.is_some() { Some(domain::PaymentMethodData::MandatePayment) } else { @@ -2816,7 +2816,7 @@ impl TryFrom> for types::PaymentsAuthoriz let shipping_cost = payment_data.payment_intent.shipping_cost; Ok(Self { - payment_method_data: (payment_method_data.get_required_value("payment_method_data")?), + payment_method_data: (payment_method_data.get_required_value("payment_method_data")?), // setup_future_usage: payment_data.payment_intent.setup_future_usage, mandate_id: payment_data.mandate_id.clone(), off_session: payment_data.mandate_id.as_ref().map(|_| true), From 96bf6c41d2fe0edd674eb364aaad7213caa4947a Mon Sep 17 00:00:00 2001 From: Sagnik Mitra Date: Wed, 18 Dec 2024 11:44:05 +0530 Subject: [PATCH 2/5] pre payment network tokenization --- crates/api_models/src/admin.rs | 22 ++ crates/diesel_models/src/business_profile.rs | 6 + crates/diesel_models/src/schema.rs | 1 + .../src/business_profile.rs | 27 +++ crates/router/src/core/admin.rs | 2 + .../payment_methods/network_tokenization.rs | 15 +- crates/router/src/core/payments.rs | 190 ++++++++++++++++-- .../payments/operations/payment_approve.rs | 2 +- .../payments/operations/payment_cancel.rs | 2 +- .../payments/operations/payment_capture.rs | 2 +- .../operations/payment_post_session_tokens.rs | 2 +- .../payments/operations/payment_status.rs | 2 +- .../payments/operations/payment_update.rs | 2 +- .../payments_incremental_authorization.rs | 2 +- .../payments/operations/tax_calculation.rs | 2 +- .../router/src/core/payments/tokenization.rs | 80 +++++++- .../router/src/core/payments/transformers.rs | 4 +- crates/router/src/types/api/admin.rs | 2 + .../down.sql | 2 + .../up.sql | 2 + 20 files changed, 330 insertions(+), 39 deletions(-) create mode 100644 migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/down.sql create mode 100644 migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/up.sql diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 321ee5305f18..cd152f9bb573 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -1867,6 +1867,10 @@ pub struct ProfileCreate { #[schema(value_type = Option, example = r#"{ "click_to_pay": "mca_ushduqwhdohwd", "netcetera": "mca_kwqhudqwd" }"#)] pub authentication_product_ids: Option, + + /// Indicates if network tokenization before first payment is enabled or not + #[serde(default)] + pub is_tokenize_before_payment_enabled: bool, } #[nutype::nutype( @@ -1985,6 +1989,10 @@ pub struct ProfileCreate { #[schema(value_type = Option, example = r#"{ "click_to_pay": "mca_ushduqwhdohwd", "netcetera": "mca_kwqhudqwd" }"#)] pub authentication_product_ids: Option, + + /// Indicates if network tokenization before first payment is enabled or not + #[serde(default)] + pub is_tokenize_before_payment_enabled: bool, } #[cfg(feature = "v1")] @@ -2122,6 +2130,9 @@ pub struct ProfileResponse { #[schema(value_type = Option, example = r#"{ "click_to_pay": "mca_ushduqwhdohwd", "netcetera": "mca_kwqhudqwd" }"#)] pub authentication_product_ids: Option, + + /// Indicates if network tokenization before first payment is enabled or not + pub is_tokenize_before_payment_enabled: bool, } #[cfg(feature = "v2")] @@ -2246,6 +2257,9 @@ pub struct ProfileResponse { #[schema(value_type = Option, example = r#"{ "click_to_pay": "mca_ushduqwhdohwd", "netcetera": "mca_kwqhudqwd" }"#)] pub authentication_product_ids: Option, + + /// Indicates if network tokenization before first payment is enabled or not + pub is_tokenize_before_payment_enabled: bool, } #[cfg(feature = "v1")] @@ -2377,6 +2391,10 @@ pub struct ProfileUpdate { #[schema(value_type = Option, example = r#"{ "click_to_pay": "mca_ushduqwhdohwd", "netcetera": "mca_kwqhudqwd" }"#)] pub authentication_product_ids: Option, + + /// Indicates if network tokenization before first payment is enabled or not + #[schema(default = false, example = false)] + pub is_tokenize_before_payment_enabled: Option, } #[cfg(feature = "v2")] @@ -2489,6 +2507,10 @@ pub struct ProfileUpdate { #[schema(value_type = Option, example = r#"{ "click_to_pay": "mca_ushduqwhdohwd", "netcetera": "mca_kwqhudqwd" }"#)] pub authentication_product_ids: Option, + + /// Indicates if network tokenization before first payment is enabled or not + #[schema(default = false, example = false)] + pub is_tokenize_before_payment_enabled: Option, } #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs index 06aa21fe9d3f..1d5ad52384e0 100644 --- a/crates/diesel_models/src/business_profile.rs +++ b/crates/diesel_models/src/business_profile.rs @@ -60,6 +60,7 @@ pub struct Profile { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, + pub is_tokenize_before_payment_enabled: bool, } #[cfg(feature = "v1")] @@ -106,6 +107,7 @@ pub struct ProfileNew { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, + pub is_tokenize_before_payment_enabled: Option, } #[cfg(feature = "v1")] @@ -149,6 +151,7 @@ pub struct ProfileUpdateInternal { pub is_click_to_pay_enabled: Option, pub authentication_product_ids: Option, + pub is_tokenize_before_payment_enabled: Option, } #[cfg(feature = "v1")] @@ -190,6 +193,7 @@ impl ProfileUpdateInternal { max_auto_retries_enabled, is_click_to_pay_enabled, authentication_product_ids, + is_tokenize_before_payment_enabled, } = self; Profile { profile_id: source.profile_id, @@ -253,6 +257,8 @@ impl ProfileUpdateInternal { .unwrap_or(source.is_click_to_pay_enabled), authentication_product_ids: authentication_product_ids .or(source.authentication_product_ids), + is_tokenize_before_payment_enabled: is_tokenize_before_payment_enabled + .unwrap_or(source.is_tokenize_before_payment_enabled), } } } diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index dfe3d5acc239..d01bae3fe462 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -216,6 +216,7 @@ diesel::table! { max_auto_retries_enabled -> Nullable, is_click_to_pay_enabled -> Bool, authentication_product_ids -> Nullable, + is_tokenize_before_payment_enabled -> Bool, } } diff --git a/crates/hyperswitch_domain_models/src/business_profile.rs b/crates/hyperswitch_domain_models/src/business_profile.rs index 47c505e8ca24..8b34206c3fbc 100644 --- a/crates/hyperswitch_domain_models/src/business_profile.rs +++ b/crates/hyperswitch_domain_models/src/business_profile.rs @@ -61,6 +61,7 @@ pub struct Profile { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, + pub is_tokenize_before_payment_enabled: bool, } #[cfg(feature = "v1")] @@ -104,6 +105,7 @@ pub struct ProfileSetter { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, + pub is_tokenize_before_payment_enabled: bool, } #[cfg(feature = "v1")] @@ -153,6 +155,7 @@ impl From for Profile { max_auto_retries_enabled: value.max_auto_retries_enabled, is_click_to_pay_enabled: value.is_click_to_pay_enabled, authentication_product_ids: value.authentication_product_ids, + is_tokenize_before_payment_enabled: value.is_tokenize_before_payment_enabled, } } } @@ -205,6 +208,7 @@ pub struct ProfileGeneralUpdate { pub is_click_to_pay_enabled: Option, pub authentication_product_ids: Option, + pub is_tokenize_before_payment_enabled: Option, } #[cfg(feature = "v1")] @@ -269,6 +273,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled, is_click_to_pay_enabled, authentication_product_ids, + is_tokenize_before_payment_enabled, } = *update; Self { @@ -308,6 +313,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled, is_click_to_pay_enabled, authentication_product_ids, + is_tokenize_before_payment_enabled, } } ProfileUpdate::RoutingAlgorithmUpdate { @@ -349,6 +355,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, + is_tokenize_before_payment_enabled: None, }, ProfileUpdate::DynamicRoutingAlgorithmUpdate { dynamic_routing_algorithm, @@ -388,6 +395,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, + is_tokenize_before_payment_enabled: None, }, ProfileUpdate::ExtendedCardInfoUpdate { is_extended_card_info_enabled, @@ -427,6 +435,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, + is_tokenize_before_payment_enabled: None, }, ProfileUpdate::ConnectorAgnosticMitUpdate { is_connector_agnostic_mit_enabled, @@ -466,6 +475,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, + is_tokenize_before_payment_enabled: None, }, ProfileUpdate::NetworkTokenizationUpdate { is_network_tokenization_enabled, @@ -505,6 +515,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, + is_tokenize_before_payment_enabled: None, }, } } @@ -563,6 +574,7 @@ impl super::behaviour::Conversion for Profile { max_auto_retries_enabled: self.max_auto_retries_enabled, is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, + is_tokenize_before_payment_enabled: self.is_tokenize_before_payment_enabled, }) } @@ -633,6 +645,7 @@ impl super::behaviour::Conversion for Profile { max_auto_retries_enabled: item.max_auto_retries_enabled, is_click_to_pay_enabled: item.is_click_to_pay_enabled, authentication_product_ids: item.authentication_product_ids, + is_tokenize_before_payment_enabled: item.is_network_tokenization_enabled, }) } .await @@ -687,6 +700,7 @@ impl super::behaviour::Conversion for Profile { max_auto_retries_enabled: self.max_auto_retries_enabled, is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, + is_tokenize_before_payment_enabled: Some(self.is_tokenize_before_payment_enabled), }) } } @@ -734,6 +748,7 @@ pub struct Profile { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, + pub is_tokenize_before_payment_enabled: bool, } #[cfg(feature = "v2")] @@ -777,6 +792,7 @@ pub struct ProfileSetter { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, + pub is_tokenize_before_payment_enabled: bool, } #[cfg(feature = "v2")] @@ -826,6 +842,7 @@ impl From for Profile { is_network_tokenization_enabled: value.is_network_tokenization_enabled, is_click_to_pay_enabled: value.is_click_to_pay_enabled, authentication_product_ids: value.authentication_product_ids, + is_tokenize_before_payment_enabled: value.is_tokenize_before_payment_enabled, } } } @@ -979,6 +996,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids, + is_tokenize_before_payment_enabled: None, } } ProfileUpdate::RoutingAlgorithmUpdate { @@ -1022,6 +1040,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, + is_tokenize_before_payment_enabled: None, }, ProfileUpdate::ExtendedCardInfoUpdate { is_extended_card_info_enabled, @@ -1063,6 +1082,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, + is_tokenize_before_payment_enabled: None, }, ProfileUpdate::ConnectorAgnosticMitUpdate { is_connector_agnostic_mit_enabled, @@ -1104,6 +1124,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, + is_tokenize_before_payment_enabled: None, }, ProfileUpdate::DefaultRoutingFallbackUpdate { default_fallback_routing, @@ -1145,6 +1166,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, + is_tokenize_before_payment_enabled: None, }, ProfileUpdate::NetworkTokenizationUpdate { is_network_tokenization_enabled, @@ -1186,6 +1208,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, + is_tokenize_before_payment_enabled: None, }, ProfileUpdate::CollectCvvDuringPaymentUpdate { should_collect_cvv_during_payment, @@ -1227,6 +1250,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, + is_tokenize_before_payment_enabled: None, }, } } @@ -1288,6 +1312,7 @@ impl super::behaviour::Conversion for Profile { max_auto_retries_enabled: None, is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, + is_tokenize_before_payment_enabled: self.is_tokenize_before_payment_enabled, }) } @@ -1358,6 +1383,7 @@ impl super::behaviour::Conversion for Profile { is_network_tokenization_enabled: item.is_network_tokenization_enabled, is_click_to_pay_enabled: item.is_click_to_pay_enabled, authentication_product_ids: item.authentication_product_ids, + is_tokenize_before_payment_enabled: item.is_tokenize_before_payment_enabled, }) } .await @@ -1415,6 +1441,7 @@ impl super::behaviour::Conversion for Profile { max_auto_retries_enabled: None, is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, + is_tokenize_before_payment_enabled: self.is_tokenize_before_payment_enabled, }) } } diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 356b4a31cc62..447a2fe3f90c 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -3689,6 +3689,7 @@ impl ProfileCreateBridge for api::ProfileCreate { max_auto_retries_enabled: self.max_auto_retries_enabled.map(i16::from), is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, + is_tokenize_before_payment_enabled: self.is_tokenize_before_payment_enabled, })) } @@ -4049,6 +4050,7 @@ impl ProfileUpdateBridge for api::ProfileUpdate { max_auto_retries_enabled: self.max_auto_retries_enabled.map(i16::from), is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, + is_tokenize_before_payment_enabled: self.is_tokenize_before_payment_enabled, }, ))) } diff --git a/crates/router/src/core/payment_methods/network_tokenization.rs b/crates/router/src/core/payment_methods/network_tokenization.rs index bb730caad2b5..deac9efbcc44 100644 --- a/crates/router/src/core/payment_methods/network_tokenization.rs +++ b/crates/router/src/core/payment_methods/network_tokenization.rs @@ -79,21 +79,22 @@ pub struct GetCardToken { } #[derive(Debug, Deserialize)] pub struct AuthenticationDetails { - cryptogram: Secret, - token: CardNumber, //network token + pub cryptogram: Secret, + pub token: CardNumber, //network token } #[derive(Debug, Serialize, Deserialize)] pub struct TokenDetails { - exp_month: Secret, - exp_year: Secret, + pub exp_month: Secret, + pub exp_year: Secret, } #[derive(Debug, Deserialize)] pub struct TokenResponse { - authentication_details: AuthenticationDetails, - network: api_enums::CardNetwork, - token_details: TokenDetails, + pub authentication_details: AuthenticationDetails, + pub network: api_enums::CardNetwork, + pub token_details: TokenDetails, + pub eci: Option, } #[derive(Debug, Serialize, Deserialize)] diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index f53d3d88bc72..54f775889e64 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -450,6 +450,15 @@ where } _ => (), }; + let customer_acceptance = payment_data + .get_payment_attempt() + .customer_acceptance + .clone(); + let customer_id = payment_data.get_payment_intent().customer_id.clone(); + let payment_method_data = payment_data.get_payment_method_data(); + let is_pre_tokenization_enabled = business_profile.is_network_tokenization_enabled + && business_profile.is_tokenize_before_payment_enabled + && customer_acceptance.is_some(); payment_data = match connector_details { ConnectorCallType::PreDetermined(connector) => { #[cfg(all(feature = "dynamic_routing", feature = "v1"))] @@ -470,6 +479,62 @@ where } else { None }; + let filtered_nt_supported_connectors = + get_filtered_nt_supported_connectors(&state, [connector.clone()].to_vec()); + + let is_nt_supported_connector_available = + filtered_nt_supported_connectors.first().is_some(); + + if is_pre_tokenization_enabled && is_nt_supported_connector_available { + let pre_tokenization_response = tokenization::pre_payment_tokenization( + state, + customer_id, + payment_method_data, + ) + .await?; + let pm_data = payment_data.get_payment_method_data(); + match pre_tokenization_response { + (Some(token_response), Some(_token_ref)) => { + let token_data = domain::NetworkTokenData { + token_number: token_response.authentication_details.token, + token_exp_month: token_response.token_details.exp_month, + token_exp_year: token_response.token_details.exp_year, + token_cryptogram: Some( + token_response.authentication_details.cryptogram, + ), + card_issuer: None, + card_network: Some(token_response.network), + card_type: None, + card_issuing_country: None, + bank_code: None, + nick_name: None, + eci: token_response.eci, + }; + match pm_data { + Some(domain::PaymentMethodData::Card(card_data)) => { + let vault_data = VaultData { + card_data: card_data.clone(), + network_token_data: token_data.clone(), + }; + payment_data.set_vault_operation( + PaymentMethodDataAction::VaultData(vault_data.clone()), + ) + } + _ => (), + } + payment_data.set_payment_method_data(Some( + domain::PaymentMethodData::NetworkToken(token_data), + )); + } + _ => match pm_data { + Some(domain::PaymentMethodData::Card(card_data)) => payment_data + .set_vault_operation(PaymentMethodDataAction::SaveCardData( + card_data.clone(), + )), + _ => (), + }, + } + } let (router_data, mca) = call_connector_service( state, req_state.clone(), @@ -555,10 +620,66 @@ where .map_err(|e| logger::error!(routable_connector_error=?e)) .unwrap_or_default(); + let filtered_nt_supported_connectors = + get_filtered_nt_supported_connectors(&state, connectors.clone()); + let is_nt_supported_connector_available = + filtered_nt_supported_connectors.first().is_some(); + let mut connectors = connectors.into_iter(); let connector_data = get_connector_data(&mut connectors)?; + if is_pre_tokenization_enabled && is_nt_supported_connector_available { + let pre_tokenization_response = tokenization::pre_payment_tokenization( + state, + customer_id, + payment_method_data, + ) + .await?; + let pm_data = payment_data.get_payment_method_data(); + match pre_tokenization_response { + (Some(token_response), Some(_token_ref)) => { + let token_data = domain::NetworkTokenData { + token_number: token_response.authentication_details.token, + token_exp_month: token_response.token_details.exp_month, + token_exp_year: token_response.token_details.exp_year, + token_cryptogram: Some( + token_response.authentication_details.cryptogram, + ), + card_issuer: None, + card_network: Some(token_response.network), + card_type: None, + card_issuing_country: None, + bank_code: None, + nick_name: None, + eci: token_response.eci, + }; + match pm_data { + Some(domain::PaymentMethodData::Card(card_data)) => { + let vault_data = VaultData { + card_data: card_data.clone(), + network_token_data: token_data.clone(), + }; + payment_data.set_vault_operation( + PaymentMethodDataAction::VaultData(vault_data.clone()), + ) + } + _ => (), + } + payment_data.set_payment_method_data(Some( + domain::PaymentMethodData::NetworkToken(token_data), + )); + } + _ => match pm_data { + Some(domain::PaymentMethodData::Card(card_data)) => payment_data + .set_vault_operation(PaymentMethodDataAction::SaveCardData( + card_data.clone(), + )), + _ => (), + }, + } + } + let schedule_time = if should_add_task_to_process_tracker { payment_sync::get_sync_process_schedule_time( &*state.store, @@ -4438,8 +4559,10 @@ where } #[derive(Clone, serde::Serialize, Debug)] -pub enum PaymentMethodDataAction{ - VaultData(VaultData) +pub enum PaymentMethodDataAction { + SaveCardData(hyperswitch_domain_models::payment_method_data::Card), + SaveNetworkTokenData(hyperswitch_domain_models::payment_method_data::NetworkTokenData), + VaultData(VaultData), } #[derive(Clone, serde::Serialize, Debug)] @@ -5639,25 +5762,8 @@ where .get_required_value("payment_method_info")? .clone(); - //fetch connectors that support ntid flow - let ntid_supported_connectors = &state - .conf - .network_transaction_id_supported_connectors - .connector_list; - //filered connectors list with ntid_supported_connectors - let filtered_ntid_supported_connectors = - filter_ntid_supported_connectors(connectors.clone(), ntid_supported_connectors); - - //fetch connectors that support network tokenization flow - let network_tokenization_supported_connectors = &state - .conf - .network_tokenization_supported_connectors - .connector_list; - //filered connectors list with ntid_supported_connectors and network_tokenization_supported_connectors - let filtered_nt_supported_connectors = filter_network_tokenization_supported_connectors( - filtered_ntid_supported_connectors, - network_tokenization_supported_connectors, - ); + let filtered_nt_supported_connectors = + get_filtered_nt_supported_connectors(&state, connectors.clone()); let action_type = decide_action_type( state, @@ -5942,6 +6048,31 @@ pub fn filter_network_tokenization_supported_connectors( .collect() } +pub fn get_filtered_nt_supported_connectors( + state: &SessionState, + connectors: Vec, +) -> Vec { + //fetch connectors that support ntid flow + let ntid_supported_connectors = &state + .conf + .network_transaction_id_supported_connectors + .connector_list; + //filered connectors list with ntid_supported_connectors + let filtered_ntid_supported_connectors = + filter_ntid_supported_connectors(connectors.clone(), ntid_supported_connectors); + + //fetch connectors that support network tokenization flow + let network_tokenization_supported_connectors = &state + .conf + .network_tokenization_supported_connectors + .connector_list; + //filered connectors list with ntid_supported_connectors and network_tokenization_supported_connectors + filter_network_tokenization_supported_connectors( + filtered_ntid_supported_connectors, + network_tokenization_supported_connectors, + ) +} + #[cfg(feature = "v1")] pub async fn decide_action_type( state: &SessionState, @@ -6969,6 +7100,7 @@ pub trait OperationSessionSetters { straight_through_algorithm: serde_json::Value, ); fn set_connector_in_payment_attempt(&mut self, connector: Option); + fn set_vault_operation(&mut self, vault_operation: PaymentMethodDataAction); } #[cfg(feature = "v1")] @@ -7217,6 +7349,10 @@ impl OperationSessionSetters for PaymentData { fn set_connector_in_payment_attempt(&mut self, connector: Option) { self.payment_attempt.connector = connector; } + + fn set_vault_operation(&mut self, vault_operation: PaymentMethodDataAction) { + self.vault_operation = Some(vault_operation); + } } #[cfg(feature = "v2")] @@ -7430,6 +7566,10 @@ impl OperationSessionSetters for PaymentIntentData { fn set_connector_in_payment_attempt(&mut self, _connector: Option) { todo!() } + + fn set_vault_operation(&mut self, vault_operation: PaymentMethodDataAction) { + todo!() + } } #[cfg(feature = "v2")] @@ -7643,6 +7783,10 @@ impl OperationSessionSetters for PaymentConfirmData { fn set_connector_in_payment_attempt(&mut self, connector: Option) { self.payment_attempt.connector = connector; } + + fn set_vault_operation(&mut self, vault_operation: PaymentMethodDataAction) { + self.vault_operation = Some(vault_operation); + } } #[cfg(feature = "v2")] @@ -7856,6 +8000,10 @@ impl OperationSessionSetters for PaymentStatusData { fn set_connector_in_payment_attempt(&mut self, connector: Option) { todo!() } + + fn set_vault_operation(&mut self, vault_operation: PaymentMethodDataAction) { + todo!() + } } #[cfg(feature = "v2")] diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs index 679deabf76e8..439b639d216d 100644 --- a/crates/router/src/core/payments/operations/payment_approve.rs +++ b/crates/router/src/core/payments/operations/payment_approve.rs @@ -196,7 +196,7 @@ impl GetTracker, api::PaymentsCaptureR tax_data: None, session_id: None, service_details: None, - vault_operation:None + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs index aa94e7edd023..1276be6a24b7 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -207,7 +207,7 @@ impl GetTracker, api::PaymentsCancelRe tax_data: None, session_id: None, service_details: None, - vault_operation:None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index 159f89230dfd..b1cbe6c86fe8 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -256,7 +256,7 @@ impl GetTracker, api::Paymen tax_data: None, session_id: None, service_details: None, - vault_operation: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs index bb063d70e812..72fb3daabd39 100644 --- a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs +++ b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs @@ -167,7 +167,7 @@ impl GetTracker, api::PaymentsPostSess tax_data: None, session_id: None, service_details: None, - vault_operation: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { operation: Box::new(self), diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index 3ac7ec71e24d..82285c76a2e4 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -523,7 +523,7 @@ async fn get_tracker_for_sync< tax_data: None, session_id: None, service_details: None, - vault_operation:None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 902271778034..33ee4a4a8e7d 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -493,7 +493,7 @@ impl GetTracker, api::PaymentsRequest> tax_data: None, session_id: None, service_details: None, - vault_operation: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs index e7a0489d84d7..6b741aa8f554 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -173,7 +173,7 @@ impl tax_data: None, session_id: None, service_details: None, - vault_operation: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/tax_calculation.rs b/crates/router/src/core/payments/operations/tax_calculation.rs index 7db40764c1e9..609cea8dda92 100644 --- a/crates/router/src/core/payments/operations/tax_calculation.rs +++ b/crates/router/src/core/payments/operations/tax_calculation.rs @@ -181,7 +181,7 @@ impl tax_data: Some(tax_data), session_id: request.session_id.clone(), service_details: None, - vault_operation: None, + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { operation: Box::new(self), diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 84f848ef0ab1..3b38df9919bc 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -12,7 +12,9 @@ use common_enums::{ConnectorMandateStatus, PaymentMethod}; use common_utils::{ crypto::Encryptable, ext_traits::{AsyncExt, Encode, ValueExt}, - id_type, pii, + id_type, + metrics::utils::record_operation_time, + pii, }; use error_stack::{report, ResultExt}; use masking::{ExposeInterface, Secret}; @@ -808,6 +810,82 @@ where todo!() } +pub async fn pre_payment_tokenization( + state: &SessionState, + customer_id: Option, + payment_method_data: Option<&domain::PaymentMethodData>, +) -> RouterResult<(Option, Option)> { + let customer_id = customer_id.to_owned().get_required_value("customer_id")?; + match payment_method_data { + Some(domain::PaymentMethodData::Card(card)) => { + let network_tokenization_supported_card_networks = &state + .conf + .network_tokenization_supported_card_networks + .card_networks; + + if card + .card_network + .as_ref() + .filter(|cn| network_tokenization_supported_card_networks.contains(cn)) + .is_some() + { + match network_tokenization::make_card_network_tokenization_request( + state, + card, + &customer_id, + ) + .await + { + Ok((_token_response, network_token_requestor_ref_id)) => { + let network_tokenization_service = &state.conf.network_tokenization_service; + match ( + network_token_requestor_ref_id.clone(), + network_tokenization_service, + ) { + (Some(token_ref), Some(network_tokenization_service)) => { + let network_token = record_operation_time( + async { + network_tokenization::get_network_token( + state, + customer_id, + token_ref, + network_tokenization_service.get_inner(), + ) + .await + .inspect_err( + |e| logger::error!(error=?e, "Error while fetching token from tokenization service") + ) + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Fetch network token failed") + }, + &metrics::FETCH_NETWORK_TOKEN_TIME, + &[], + ) + .await; + match network_token { + Ok(token_response) => Ok(( + Some(token_response), + network_token_requestor_ref_id.clone(), + )), + _ => Ok((None, None)), + } + } + _ => Ok((None, None)), + } + } + Err(err) => { + logger::error!("Failed to tokenize card: {:?}", err); + Ok((None, None)) //None will be returned in case of error when calling network tokenization service + } + } + } else { + Ok((None, None)) //None will be returned in case of unsupported card network. + } + } + _ => Ok((None, None)), //network_token_resp is None in case of other payment methods + } +} + #[cfg(all( any(feature = "v1", feature = "v2"), not(feature = "payment_methods_v2") diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 5c1d24e5fd9d..70db7a581a20 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -2782,7 +2782,7 @@ impl TryFrom> for types::PaymentsAuthoriz } else { None }; - let payment_method_data = payment_data.payment_method_data.or_else(|| { // + let payment_method_data = payment_data.payment_method_data.or_else(|| { if payment_data.mandate_id.is_some() { Some(domain::PaymentMethodData::MandatePayment) } else { @@ -2816,7 +2816,7 @@ impl TryFrom> for types::PaymentsAuthoriz let shipping_cost = payment_data.payment_intent.shipping_cost; Ok(Self { - payment_method_data: (payment_method_data.get_required_value("payment_method_data")?), // + payment_method_data: (payment_method_data.get_required_value("payment_method_data")?), setup_future_usage: payment_data.payment_intent.setup_future_usage, mandate_id: payment_data.mandate_id.clone(), off_session: payment_data.mandate_id.as_ref().map(|_| true), diff --git a/crates/router/src/types/api/admin.rs b/crates/router/src/types/api/admin.rs index 28533e33e178..70a5c8dad5c1 100644 --- a/crates/router/src/types/api/admin.rs +++ b/crates/router/src/types/api/admin.rs @@ -178,6 +178,7 @@ impl ForeignTryFrom for ProfileResponse { max_auto_retries_enabled: item.max_auto_retries_enabled, is_click_to_pay_enabled: item.is_click_to_pay_enabled, authentication_product_ids: item.authentication_product_ids, + is_tokenize_before_payment_enabled: item.is_tokenize_before_payment_enabled, }) } } @@ -377,5 +378,6 @@ pub async fn create_profile_from_merchant_account( max_auto_retries_enabled: request.max_auto_retries_enabled.map(i16::from), is_click_to_pay_enabled: request.is_click_to_pay_enabled, authentication_product_ids: request.authentication_product_ids, + is_tokenize_before_payment_enabled: request.is_network_tokenization_enabled, })) } diff --git a/migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/down.sql b/migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/down.sql new file mode 100644 index 000000000000..56559f452ee4 --- /dev/null +++ b/migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE business_profile DROP COLUMN IF EXISTS is_tokenize_before_payment_enabled; \ No newline at end of file diff --git a/migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/up.sql b/migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/up.sql new file mode 100644 index 000000000000..d481781c3a8a --- /dev/null +++ b/migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/up.sql @@ -0,0 +1,2 @@ +-- Your SQL goes here +ALTER TABLE business_profile ADD COLUMN IF NOT EXISTS is_tokenize_before_payment_enabled BOOLEAN NOT NULL DEFAULT FALSE; \ No newline at end of file From 17f5577fbdbdf332cae9875fa58a045a7231e891 Mon Sep 17 00:00:00 2001 From: Sagnik Mitra Date: Wed, 25 Dec 2024 11:42:44 +0530 Subject: [PATCH 3/5] post payment processing --- crates/api_models/src/admin.rs | 24 +- crates/diesel_models/src/business_profile.rs | 18 +- crates/diesel_models/src/schema.rs | 2 +- crates/diesel_models/src/schema_v2.rs | 1 + .../src/business_profile.rs | 56 +-- crates/router/src/core/admin.rs | 6 +- crates/router/src/core/payments.rs | 299 +++++++-------- .../payments/operations/payment_response.rs | 11 +- .../router/src/core/payments/tokenization.rs | 343 ++++++++++++++---- crates/router/src/types/api/admin.rs | 5 +- .../down.sql | 2 - .../up.sql | 2 - .../down.sql | 2 + .../up.sql | 2 + 14 files changed, 504 insertions(+), 269 deletions(-) delete mode 100644 migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/down.sql delete mode 100644 migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/up.sql create mode 100644 migrations/2025-01-22-110625_add_is_pre_network_tokenization_enabled_in_business_profile/down.sql create mode 100644 migrations/2025-01-22-110625_add_is_pre_network_tokenization_enabled_in_business_profile/up.sql diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index cd152f9bb573..7c9df019fb1f 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -1868,9 +1868,9 @@ pub struct ProfileCreate { pub authentication_product_ids: Option, - /// Indicates if network tokenization before first payment is enabled or not + /// Indicates if pre network tokenization is enabled or not #[serde(default)] - pub is_tokenize_before_payment_enabled: bool, + pub is_pre_network_tokenization_enabled: bool, } #[nutype::nutype( @@ -1990,9 +1990,9 @@ pub struct ProfileCreate { pub authentication_product_ids: Option, - /// Indicates if network tokenization before first payment is enabled or not + /// Indicates if pre network tokenization is enabled or not #[serde(default)] - pub is_tokenize_before_payment_enabled: bool, + pub is_pre_network_tokenization_enabled: bool, } #[cfg(feature = "v1")] @@ -2131,8 +2131,8 @@ pub struct ProfileResponse { pub authentication_product_ids: Option, - /// Indicates if network tokenization before first payment is enabled or not - pub is_tokenize_before_payment_enabled: bool, + /// Indicates if pre network tokenization is enabled or not + pub is_pre_network_tokenization_enabled: bool, } #[cfg(feature = "v2")] @@ -2258,8 +2258,8 @@ pub struct ProfileResponse { pub authentication_product_ids: Option, - /// Indicates if network tokenization before first payment is enabled or not - pub is_tokenize_before_payment_enabled: bool, + /// Indicates if pre network tokenization is enabled or not + pub is_pre_network_tokenization_enabled: bool, } #[cfg(feature = "v1")] @@ -2392,9 +2392,9 @@ pub struct ProfileUpdate { pub authentication_product_ids: Option, - /// Indicates if network tokenization before first payment is enabled or not + /// Indicates if pre network tokenization is enabled or not #[schema(default = false, example = false)] - pub is_tokenize_before_payment_enabled: Option, + pub is_pre_network_tokenization_enabled: Option, } #[cfg(feature = "v2")] @@ -2508,9 +2508,9 @@ pub struct ProfileUpdate { pub authentication_product_ids: Option, - /// Indicates if network tokenization before first payment is enabled or not + /// Indicates if pre network tokenization is enabled or not #[schema(default = false, example = false)] - pub is_tokenize_before_payment_enabled: Option, + pub is_pre_network_tokenization_enabled: Option, } #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs index 1d5ad52384e0..da78186715fa 100644 --- a/crates/diesel_models/src/business_profile.rs +++ b/crates/diesel_models/src/business_profile.rs @@ -60,7 +60,7 @@ pub struct Profile { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, - pub is_tokenize_before_payment_enabled: bool, + pub is_pre_network_tokenization_enabled: bool, } #[cfg(feature = "v1")] @@ -107,7 +107,7 @@ pub struct ProfileNew { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, - pub is_tokenize_before_payment_enabled: Option, + pub is_pre_network_tokenization_enabled: Option, } #[cfg(feature = "v1")] @@ -151,7 +151,7 @@ pub struct ProfileUpdateInternal { pub is_click_to_pay_enabled: Option, pub authentication_product_ids: Option, - pub is_tokenize_before_payment_enabled: Option, + pub is_pre_network_tokenization_enabled: Option, } #[cfg(feature = "v1")] @@ -193,7 +193,7 @@ impl ProfileUpdateInternal { max_auto_retries_enabled, is_click_to_pay_enabled, authentication_product_ids, - is_tokenize_before_payment_enabled, + is_pre_network_tokenization_enabled, } = self; Profile { profile_id: source.profile_id, @@ -257,8 +257,8 @@ impl ProfileUpdateInternal { .unwrap_or(source.is_click_to_pay_enabled), authentication_product_ids: authentication_product_ids .or(source.authentication_product_ids), - is_tokenize_before_payment_enabled: is_tokenize_before_payment_enabled - .unwrap_or(source.is_tokenize_before_payment_enabled), + is_pre_network_tokenization_enabled: is_pre_network_tokenization_enabled + .unwrap_or(source.is_pre_network_tokenization_enabled), } } } @@ -316,6 +316,7 @@ pub struct Profile { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, + pub is_pre_network_tokenization_enabled: bool, } impl Profile { @@ -377,6 +378,7 @@ pub struct ProfileNew { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, + pub is_pre_network_tokenization_enabled: Option, } #[cfg(feature = "v2")] @@ -422,6 +424,7 @@ pub struct ProfileUpdateInternal { pub is_click_to_pay_enabled: Option, pub authentication_product_ids: Option, + pub is_pre_network_tokenization_enabled: Option, } #[cfg(feature = "v2")] @@ -465,6 +468,7 @@ impl ProfileUpdateInternal { max_auto_retries_enabled, is_click_to_pay_enabled, authentication_product_ids, + is_pre_network_tokenization_enabled, } = self; Profile { id: source.id, @@ -533,6 +537,8 @@ impl ProfileUpdateInternal { .unwrap_or(source.is_click_to_pay_enabled), authentication_product_ids: authentication_product_ids .or(source.authentication_product_ids), + is_pre_network_tokenization_enabled: is_pre_network_tokenization_enabled + .unwrap_or(source.is_pre_network_tokenization_enabled) } } } diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index d01bae3fe462..aca30da620be 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -216,7 +216,7 @@ diesel::table! { max_auto_retries_enabled -> Nullable, is_click_to_pay_enabled -> Bool, authentication_product_ids -> Nullable, - is_tokenize_before_payment_enabled -> Bool, + is_pre_network_tokenization_enabled -> Bool, } } diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index b5361f4c95cd..4b6721b4d819 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -224,6 +224,7 @@ diesel::table! { max_auto_retries_enabled -> Nullable, is_click_to_pay_enabled -> Bool, authentication_product_ids -> Nullable, + is_pre_network_tokenization_enabled -> Bool, } } diff --git a/crates/hyperswitch_domain_models/src/business_profile.rs b/crates/hyperswitch_domain_models/src/business_profile.rs index 8b34206c3fbc..ef09ecf84001 100644 --- a/crates/hyperswitch_domain_models/src/business_profile.rs +++ b/crates/hyperswitch_domain_models/src/business_profile.rs @@ -61,7 +61,7 @@ pub struct Profile { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, - pub is_tokenize_before_payment_enabled: bool, + pub is_pre_network_tokenization_enabled: bool, } #[cfg(feature = "v1")] @@ -105,7 +105,7 @@ pub struct ProfileSetter { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, - pub is_tokenize_before_payment_enabled: bool, + pub is_pre_network_tokenization_enabled: bool, } #[cfg(feature = "v1")] @@ -155,7 +155,7 @@ impl From for Profile { max_auto_retries_enabled: value.max_auto_retries_enabled, is_click_to_pay_enabled: value.is_click_to_pay_enabled, authentication_product_ids: value.authentication_product_ids, - is_tokenize_before_payment_enabled: value.is_tokenize_before_payment_enabled, + is_pre_network_tokenization_enabled: value.is_pre_network_tokenization_enabled, } } } @@ -208,7 +208,7 @@ pub struct ProfileGeneralUpdate { pub is_click_to_pay_enabled: Option, pub authentication_product_ids: Option, - pub is_tokenize_before_payment_enabled: Option, + pub is_pre_network_tokenization_enabled: Option, } #[cfg(feature = "v1")] @@ -273,7 +273,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled, is_click_to_pay_enabled, authentication_product_ids, - is_tokenize_before_payment_enabled, + is_pre_network_tokenization_enabled, } = *update; Self { @@ -313,7 +313,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled, is_click_to_pay_enabled, authentication_product_ids, - is_tokenize_before_payment_enabled, + is_pre_network_tokenization_enabled, } } ProfileUpdate::RoutingAlgorithmUpdate { @@ -355,7 +355,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, - is_tokenize_before_payment_enabled: None, + is_pre_network_tokenization_enabled: None, }, ProfileUpdate::DynamicRoutingAlgorithmUpdate { dynamic_routing_algorithm, @@ -395,7 +395,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, - is_tokenize_before_payment_enabled: None, + is_pre_network_tokenization_enabled: None, }, ProfileUpdate::ExtendedCardInfoUpdate { is_extended_card_info_enabled, @@ -435,7 +435,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, - is_tokenize_before_payment_enabled: None, + is_pre_network_tokenization_enabled: None, }, ProfileUpdate::ConnectorAgnosticMitUpdate { is_connector_agnostic_mit_enabled, @@ -475,7 +475,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, - is_tokenize_before_payment_enabled: None, + is_pre_network_tokenization_enabled: None, }, ProfileUpdate::NetworkTokenizationUpdate { is_network_tokenization_enabled, @@ -515,7 +515,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, - is_tokenize_before_payment_enabled: None, + is_pre_network_tokenization_enabled: None, }, } } @@ -574,7 +574,7 @@ impl super::behaviour::Conversion for Profile { max_auto_retries_enabled: self.max_auto_retries_enabled, is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, - is_tokenize_before_payment_enabled: self.is_tokenize_before_payment_enabled, + is_pre_network_tokenization_enabled: self.is_pre_network_tokenization_enabled, }) } @@ -645,7 +645,7 @@ impl super::behaviour::Conversion for Profile { max_auto_retries_enabled: item.max_auto_retries_enabled, is_click_to_pay_enabled: item.is_click_to_pay_enabled, authentication_product_ids: item.authentication_product_ids, - is_tokenize_before_payment_enabled: item.is_network_tokenization_enabled, + is_pre_network_tokenization_enabled: item.is_network_tokenization_enabled, }) } .await @@ -700,7 +700,7 @@ impl super::behaviour::Conversion for Profile { max_auto_retries_enabled: self.max_auto_retries_enabled, is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, - is_tokenize_before_payment_enabled: Some(self.is_tokenize_before_payment_enabled), + is_pre_network_tokenization_enabled: Some(self.is_pre_network_tokenization_enabled), }) } } @@ -748,7 +748,7 @@ pub struct Profile { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, - pub is_tokenize_before_payment_enabled: bool, + pub is_pre_network_tokenization_enabled: bool, } #[cfg(feature = "v2")] @@ -792,7 +792,7 @@ pub struct ProfileSetter { pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, - pub is_tokenize_before_payment_enabled: bool, + pub is_pre_network_tokenization_enabled: bool, } #[cfg(feature = "v2")] @@ -842,7 +842,7 @@ impl From for Profile { is_network_tokenization_enabled: value.is_network_tokenization_enabled, is_click_to_pay_enabled: value.is_click_to_pay_enabled, authentication_product_ids: value.authentication_product_ids, - is_tokenize_before_payment_enabled: value.is_tokenize_before_payment_enabled, + is_pre_network_tokenization_enabled: value.is_pre_network_tokenization_enabled, } } } @@ -896,6 +896,7 @@ pub struct ProfileGeneralUpdate { pub is_click_to_pay_enabled: Option, pub authentication_product_ids: Option, + pub is_pre_network_tokenization_enabled: Option, } #[cfg(feature = "v2")] @@ -956,6 +957,7 @@ impl From for ProfileUpdateInternal { is_network_tokenization_enabled, is_click_to_pay_enabled, authentication_product_ids, + is_pre_network_tokenization_enabled, } = *update; Self { profile_name, @@ -996,7 +998,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids, - is_tokenize_before_payment_enabled: None, + is_pre_network_tokenization_enabled, } } ProfileUpdate::RoutingAlgorithmUpdate { @@ -1040,7 +1042,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, - is_tokenize_before_payment_enabled: None, + is_pre_network_tokenization_enabled: None, }, ProfileUpdate::ExtendedCardInfoUpdate { is_extended_card_info_enabled, @@ -1082,7 +1084,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, - is_tokenize_before_payment_enabled: None, + is_pre_network_tokenization_enabled: None, }, ProfileUpdate::ConnectorAgnosticMitUpdate { is_connector_agnostic_mit_enabled, @@ -1124,7 +1126,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, - is_tokenize_before_payment_enabled: None, + is_pre_network_tokenization_enabled: None, }, ProfileUpdate::DefaultRoutingFallbackUpdate { default_fallback_routing, @@ -1166,7 +1168,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, - is_tokenize_before_payment_enabled: None, + is_pre_network_tokenization_enabled: None, }, ProfileUpdate::NetworkTokenizationUpdate { is_network_tokenization_enabled, @@ -1208,7 +1210,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, - is_tokenize_before_payment_enabled: None, + is_pre_network_tokenization_enabled: None, }, ProfileUpdate::CollectCvvDuringPaymentUpdate { should_collect_cvv_during_payment, @@ -1250,7 +1252,7 @@ impl From for ProfileUpdateInternal { max_auto_retries_enabled: None, is_click_to_pay_enabled: None, authentication_product_ids: None, - is_tokenize_before_payment_enabled: None, + is_pre_network_tokenization_enabled: None, }, } } @@ -1312,7 +1314,7 @@ impl super::behaviour::Conversion for Profile { max_auto_retries_enabled: None, is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, - is_tokenize_before_payment_enabled: self.is_tokenize_before_payment_enabled, + is_pre_network_tokenization_enabled: self.is_pre_network_tokenization_enabled, }) } @@ -1383,7 +1385,7 @@ impl super::behaviour::Conversion for Profile { is_network_tokenization_enabled: item.is_network_tokenization_enabled, is_click_to_pay_enabled: item.is_click_to_pay_enabled, authentication_product_ids: item.authentication_product_ids, - is_tokenize_before_payment_enabled: item.is_tokenize_before_payment_enabled, + is_pre_network_tokenization_enabled: item.is_pre_network_tokenization_enabled, }) } .await @@ -1441,7 +1443,7 @@ impl super::behaviour::Conversion for Profile { max_auto_retries_enabled: None, is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, - is_tokenize_before_payment_enabled: self.is_tokenize_before_payment_enabled, + is_pre_network_tokenization_enabled: Some(self.is_pre_network_tokenization_enabled), }) } } diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 447a2fe3f90c..cda8f60fb0ee 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -3689,7 +3689,7 @@ impl ProfileCreateBridge for api::ProfileCreate { max_auto_retries_enabled: self.max_auto_retries_enabled.map(i16::from), is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, - is_tokenize_before_payment_enabled: self.is_tokenize_before_payment_enabled, + is_pre_network_tokenization_enabled: self.is_pre_network_tokenization_enabled, })) } @@ -3799,6 +3799,7 @@ impl ProfileCreateBridge for api::ProfileCreate { is_network_tokenization_enabled: self.is_network_tokenization_enabled, is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, + is_pre_network_tokenization_enabled: self.is_pre_network_tokenization_enabled, })) } } @@ -4050,7 +4051,7 @@ impl ProfileUpdateBridge for api::ProfileUpdate { max_auto_retries_enabled: self.max_auto_retries_enabled.map(i16::from), is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, - is_tokenize_before_payment_enabled: self.is_tokenize_before_payment_enabled, + is_pre_network_tokenization_enabled: self.is_pre_network_tokenization_enabled, }, ))) } @@ -4149,6 +4150,7 @@ impl ProfileUpdateBridge for api::ProfileUpdate { is_network_tokenization_enabled: self.is_network_tokenization_enabled, is_click_to_pay_enabled: self.is_click_to_pay_enabled, authentication_product_ids: self.authentication_product_ids, + is_pre_network_tokenization_enabled: self.is_pre_network_tokenization_enabled, }, ))) } diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 54f775889e64..92d69f2af22e 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -454,11 +454,6 @@ where .get_payment_attempt() .customer_acceptance .clone(); - let customer_id = payment_data.get_payment_intent().customer_id.clone(); - let payment_method_data = payment_data.get_payment_method_data(); - let is_pre_tokenization_enabled = business_profile.is_network_tokenization_enabled - && business_profile.is_tokenize_before_payment_enabled - && customer_acceptance.is_some(); payment_data = match connector_details { ConnectorCallType::PreDetermined(connector) => { #[cfg(all(feature = "dynamic_routing", feature = "v1"))] @@ -479,61 +474,18 @@ where } else { None }; - let filtered_nt_supported_connectors = - get_filtered_nt_supported_connectors(&state, [connector.clone()].to_vec()); - let is_nt_supported_connector_available = - filtered_nt_supported_connectors.first().is_some(); - - if is_pre_tokenization_enabled && is_nt_supported_connector_available { - let pre_tokenization_response = tokenization::pre_payment_tokenization( + if is_pre_network_tokenization_enabled( + state, + &business_profile, + customer_acceptance, + connector.connector_name, + ) { + set_payment_method_data_for_pre_network_tokenization( state, - customer_id, - payment_method_data, + &mut payment_data, ) - .await?; - let pm_data = payment_data.get_payment_method_data(); - match pre_tokenization_response { - (Some(token_response), Some(_token_ref)) => { - let token_data = domain::NetworkTokenData { - token_number: token_response.authentication_details.token, - token_exp_month: token_response.token_details.exp_month, - token_exp_year: token_response.token_details.exp_year, - token_cryptogram: Some( - token_response.authentication_details.cryptogram, - ), - card_issuer: None, - card_network: Some(token_response.network), - card_type: None, - card_issuing_country: None, - bank_code: None, - nick_name: None, - eci: token_response.eci, - }; - match pm_data { - Some(domain::PaymentMethodData::Card(card_data)) => { - let vault_data = VaultData { - card_data: card_data.clone(), - network_token_data: token_data.clone(), - }; - payment_data.set_vault_operation( - PaymentMethodDataAction::VaultData(vault_data.clone()), - ) - } - _ => (), - } - payment_data.set_payment_method_data(Some( - domain::PaymentMethodData::NetworkToken(token_data), - )); - } - _ => match pm_data { - Some(domain::PaymentMethodData::Card(card_data)) => payment_data - .set_vault_operation(PaymentMethodDataAction::SaveCardData( - card_data.clone(), - )), - _ => (), - }, - } + .await } let (router_data, mca) = call_connector_service( state, @@ -620,64 +572,21 @@ where .map_err(|e| logger::error!(routable_connector_error=?e)) .unwrap_or_default(); - let filtered_nt_supported_connectors = - get_filtered_nt_supported_connectors(&state, connectors.clone()); - let is_nt_supported_connector_available = - filtered_nt_supported_connectors.first().is_some(); - let mut connectors = connectors.into_iter(); let connector_data = get_connector_data(&mut connectors)?; - if is_pre_tokenization_enabled && is_nt_supported_connector_available { - let pre_tokenization_response = tokenization::pre_payment_tokenization( + if is_pre_network_tokenization_enabled( + state, + &business_profile, + customer_acceptance, + connector_data.connector_name, + ) { + set_payment_method_data_for_pre_network_tokenization( state, - customer_id, - payment_method_data, + &mut payment_data, ) - .await?; - let pm_data = payment_data.get_payment_method_data(); - match pre_tokenization_response { - (Some(token_response), Some(_token_ref)) => { - let token_data = domain::NetworkTokenData { - token_number: token_response.authentication_details.token, - token_exp_month: token_response.token_details.exp_month, - token_exp_year: token_response.token_details.exp_year, - token_cryptogram: Some( - token_response.authentication_details.cryptogram, - ), - card_issuer: None, - card_network: Some(token_response.network), - card_type: None, - card_issuing_country: None, - bank_code: None, - nick_name: None, - eci: token_response.eci, - }; - match pm_data { - Some(domain::PaymentMethodData::Card(card_data)) => { - let vault_data = VaultData { - card_data: card_data.clone(), - network_token_data: token_data.clone(), - }; - payment_data.set_vault_operation( - PaymentMethodDataAction::VaultData(vault_data.clone()), - ) - } - _ => (), - } - payment_data.set_payment_method_data(Some( - domain::PaymentMethodData::NetworkToken(token_data), - )); - } - _ => match pm_data { - Some(domain::PaymentMethodData::Card(card_data)) => payment_data - .set_vault_operation(PaymentMethodDataAction::SaveCardData( - card_data.clone(), - )), - _ => (), - }, - } + .await; } let schedule_time = if should_add_task_to_process_tracker { @@ -4560,15 +4469,26 @@ where #[derive(Clone, serde::Serialize, Debug)] pub enum PaymentMethodDataAction { - SaveCardData(hyperswitch_domain_models::payment_method_data::Card), - SaveNetworkTokenData(hyperswitch_domain_models::payment_method_data::NetworkTokenData), - VaultData(VaultData), + SaveCardData(Box), + SaveCardAndNetworkTokenData(Box), } -#[derive(Clone, serde::Serialize, Debug)] -pub struct VaultData { +#[derive(Default, Clone, serde::Serialize, Debug)] +pub struct CardAndNetworkTokenData { pub card_data: hyperswitch_domain_models::payment_method_data::Card, + pub network_token: NetworkTokenDataForVault, +} + +#[derive(Default, Clone, serde::Serialize, Debug)] +pub struct NetworkTokenDataForVault { pub network_token_data: hyperswitch_domain_models::payment_method_data::NetworkTokenData, + pub network_token_req_ref_id: String, +} + +#[derive(Default, Clone, serde::Serialize, Debug)] +pub struct CardDataForVault { + pub card_data: hyperswitch_domain_models::payment_method_data::Card, + pub network_token_req_ref_id: Option, } #[derive(Clone, serde::Serialize, Debug)] @@ -5115,6 +5035,105 @@ where Ok(()) } +#[cfg(feature = "v1")] +pub fn is_pre_network_tokenization_enabled( + state: &SessionState, + business_profile: &domain::Profile, + customer_acceptance: Option>, + connector_name: enums::Connector, +) -> bool { + let ntid_supported_connectors = &state + .conf + .network_transaction_id_supported_connectors + .connector_list; + + let is_nt_supported_connector = ntid_supported_connectors.contains(&connector_name); + + business_profile.is_network_tokenization_enabled + && business_profile.is_pre_network_tokenization_enabled + && customer_acceptance.is_some() + && is_nt_supported_connector +} + +#[cfg(feature = "v1")] +impl From for domain::NetworkTokenData { + fn from(token_response: network_tokenization::TokenResponse) -> Self { + Self { + token_number: token_response.authentication_details.token, + token_exp_month: token_response.token_details.exp_month, + token_exp_year: token_response.token_details.exp_year, + token_cryptogram: Some(token_response.authentication_details.cryptogram), + card_issuer: None, + card_network: Some(token_response.network), + card_type: None, + card_issuing_country: None, + bank_code: None, + nick_name: None, + eci: token_response.eci, + } + } +} + +#[cfg(feature = "v1")] +pub async fn set_payment_method_data_for_pre_network_tokenization( + state: &SessionState, + payment_data: &mut D, +) +where + F: Send + Clone, + D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, +{ + let customer_id = payment_data.get_payment_intent().customer_id.clone(); + let payment_method_data = payment_data.get_payment_method_data(); + let pre_tokenization_response = + tokenization::pre_payment_tokenization(state, customer_id, payment_method_data) + .await + .ok(); + if let Some(domain::PaymentMethodData::Card(card_data)) = payment_method_data { + match pre_tokenization_response { + Some((Some(token_response), Some(token_ref))) => { + let token_data = domain::NetworkTokenData::from(token_response); + let network_token_data_for_vault = NetworkTokenDataForVault { + network_token_data: token_data.clone(), + network_token_req_ref_id: token_ref, + }; + + let card_and_network_token_data = CardAndNetworkTokenData { + card_data: card_data.clone(), + network_token: network_token_data_for_vault.clone(), + }; + payment_data.set_vault_operation( + PaymentMethodDataAction::SaveCardAndNetworkTokenData( + Box::new(card_and_network_token_data.clone()), + ), + ); + + payment_data.set_payment_method_data(Some( + domain::PaymentMethodData::NetworkToken(token_data), + )); + } + Some((None, Some(token_ref))) => { + let card_data_for_vault = CardDataForVault { + card_data: card_data.clone(), + network_token_req_ref_id: Some(token_ref), + }; + payment_data.set_vault_operation(PaymentMethodDataAction::SaveCardData( + Box::new(card_data_for_vault.clone()), + )) + } + _ => { + let card_data_for_vault = CardDataForVault { + card_data: card_data.clone(), + network_token_req_ref_id: None, + }; + payment_data.set_vault_operation(PaymentMethodDataAction::SaveCardData( + Box::new(card_data_for_vault.clone()), + )) + } + } + } +} + #[cfg(feature = "v1")] #[allow(clippy::too_many_arguments)] pub async fn get_connector_choice( @@ -5762,8 +5781,25 @@ where .get_required_value("payment_method_info")? .clone(); - let filtered_nt_supported_connectors = - get_filtered_nt_supported_connectors(&state, connectors.clone()); + //fetch connectors that support ntid flow + let ntid_supported_connectors = &state + .conf + .network_transaction_id_supported_connectors + .connector_list; + //filered connectors list with ntid_supported_connectors + let filtered_ntid_supported_connectors = + filter_ntid_supported_connectors(connectors.clone(), ntid_supported_connectors); + + //fetch connectors that support network tokenization flow + let network_tokenization_supported_connectors = &state + .conf + .network_tokenization_supported_connectors + .connector_list; + //filered connectors list with ntid_supported_connectors and network_tokenization_supported_connectors + let filtered_nt_supported_connectors = filter_network_tokenization_supported_connectors( + filtered_ntid_supported_connectors, + network_tokenization_supported_connectors, + ); let action_type = decide_action_type( state, @@ -6048,31 +6084,6 @@ pub fn filter_network_tokenization_supported_connectors( .collect() } -pub fn get_filtered_nt_supported_connectors( - state: &SessionState, - connectors: Vec, -) -> Vec { - //fetch connectors that support ntid flow - let ntid_supported_connectors = &state - .conf - .network_transaction_id_supported_connectors - .connector_list; - //filered connectors list with ntid_supported_connectors - let filtered_ntid_supported_connectors = - filter_ntid_supported_connectors(connectors.clone(), ntid_supported_connectors); - - //fetch connectors that support network tokenization flow - let network_tokenization_supported_connectors = &state - .conf - .network_tokenization_supported_connectors - .connector_list; - //filered connectors list with ntid_supported_connectors and network_tokenization_supported_connectors - filter_network_tokenization_supported_connectors( - filtered_ntid_supported_connectors, - network_tokenization_supported_connectors, - ) -} - #[cfg(feature = "v1")] pub async fn decide_action_type( state: &SessionState, @@ -7785,7 +7796,7 @@ impl OperationSessionSetters for PaymentConfirmData { } fn set_vault_operation(&mut self, vault_operation: PaymentMethodDataAction) { - self.vault_operation = Some(vault_operation); + todo!() } } @@ -8219,4 +8230,8 @@ impl OperationSessionSetters for PaymentCaptureData { fn set_connector_in_payment_attempt(&mut self, connector: Option) { todo!() } + + fn set_vault_operation(&mut self, vault_operation: PaymentMethodDataAction) { + todo!() + } } diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 9692b1ca8a5c..7cd961ce663a 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -163,6 +163,8 @@ impl PostUpdateTracker, types::PaymentsAuthor .and_then(|billing_details| billing_details.address.as_ref()) .and_then(|address| address.get_optional_full_name()); let mut should_avoid_saving = false; + let vault_operation = payment_data.vault_operation.clone(); + let payment_method_info = payment_data.payment_method_info.clone(); if let Some(payment_method_info) = &payment_data.payment_method_info { if payment_data.payment_intent.off_session.is_none() && resp.response.is_ok() { @@ -201,6 +203,8 @@ impl PostUpdateTracker, types::PaymentsAuthor business_profile, connector_mandate_reference_id.clone(), merchant_connector_id.clone(), + vault_operation.clone(), + payment_method_info.clone(), )); let is_connector_mandate = resp.request.customer_acceptance.is_some() @@ -317,6 +321,8 @@ impl PostUpdateTracker, types::PaymentsAuthor &business_profile, connector_mandate_reference_id, merchant_connector_id.clone(), + vault_operation.clone(), + payment_method_info.clone(), )) .await; @@ -1083,7 +1089,8 @@ impl PostUpdateTracker, types::SetupMandateRequestDa .connector_mandate_detail .as_ref() .map(|detail| ConnectorMandateReferenceId::foreign_from(detail.clone())); - + let vault_operation = payment_data.vault_operation.clone(); + let payment_method_info = payment_data.payment_method_info.clone(); let merchant_connector_id = payment_data.payment_attempt.merchant_connector_id.clone(); let tokenization::SavePaymentMethodDataResponse { payment_method_id, @@ -1102,6 +1109,8 @@ impl PostUpdateTracker, types::SetupMandateRequestDa business_profile, connector_mandate_reference_id, merchant_connector_id.clone(), + vault_operation, + payment_method_info, )) .await?; diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs index 3b38df9919bc..e1d7984d52ec 100644 --- a/crates/router/src/core/payments/tokenization.rs +++ b/crates/router/src/core/payments/tokenization.rs @@ -86,6 +86,8 @@ pub async fn save_payment_method( business_profile: &domain::Profile, mut original_connector_mandate_reference_id: Option, merchant_connector_id: Option, + vault_operation: Option, + payment_method_info: Option, ) -> RouterResult where FData: mandate::MandateBehaviour + Clone, @@ -205,41 +207,215 @@ where .await?; ((res, dc, None), None) } else { - pm_status = Some(common_enums::PaymentMethodStatus::from( + let payment_method_status = common_enums::PaymentMethodStatus::from( save_payment_method_data.attempt_status, - )); - let (res, dc) = Box::pin(save_in_locker( - state, - merchant_account, - payment_method_create_request.to_owned(), - )) - .await?; + ); + pm_status = Some(payment_method_status); - if is_network_tokenization_enabled { - let pm_data = &save_payment_method_data.request.get_payment_method_data(); - match pm_data { - domain::PaymentMethodData::Card(card) => { - let ( - network_token_resp, - _network_token_duplication_check, //the duplication check is discarded, since each card has only one token, handling card duplication check will be suffice - network_token_requestor_ref_id, - ) = Box::pin(save_network_token_in_locker( + if let Some(payment_method_data_action) = vault_operation { + let network_token_requestor_reference_id = + payment_method_info.and_then(|pm_info| { + pm_info.network_token_requestor_reference_id.clone() + }); + match payment_method_data_action { + payments::PaymentMethodDataAction::SaveCardData(card) => { + let card_data = api::CardDetail { + card_number: card.card_data.card_number.clone(), + card_exp_month: card.card_data.card_exp_month.clone(), + card_exp_year: card.card_data.card_exp_year.clone(), + card_holder_name: None, + nick_name: None, + card_issuing_country: None, + card_network: card.card_data.card_network.clone(), + card_issuer: None, + card_type: None, + }; + if let (Some(nt_ref_id), Some(tokenization_service)) = ( + card.network_token_req_ref_id.clone(), + &state.conf.network_tokenization_service, + ) { + let _ = record_operation_time( + async { + network_tokenization::delete_network_token_from_tokenization_service( + state, + nt_ref_id.clone(), + &customer_id, + tokenization_service.get_inner(), + ) + .await + }, + &metrics::DELETE_NETWORK_TOKEN_TIME, + &[], + ) + .await; + } + let (res, dc) = Box::pin(save_in_locker( state, merchant_account, - card, - payment_method_create_request.clone(), + payment_method_create_request.to_owned(), + Some(card_data), )) - .await?; + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Add Card In Locker Failed")?; - ( - (res, dc, network_token_requestor_ref_id), - network_token_resp, - ) + ((res, dc, None), None) + } + payments::PaymentMethodDataAction::SaveCardAndNetworkTokenData( + save_card_and_network_token_data, + ) => { + let card_data = api::CardDetail { + card_number: save_card_and_network_token_data + .card_data + .card_number + .clone(), + card_exp_month: save_card_and_network_token_data + .card_data + .card_exp_month + .clone(), + card_exp_year: save_card_and_network_token_data + .card_data + .card_exp_year + .clone(), + card_holder_name: None, + nick_name: None, + card_issuing_country: None, + card_network: save_card_and_network_token_data + .card_data + .card_network + .clone(), + card_issuer: None, + card_type: None, + }; + let network_token_data = api::CardDetail { + card_number: save_card_and_network_token_data + .network_token + .network_token_data + .token_number + .clone(), + card_exp_month: save_card_and_network_token_data + .network_token + .network_token_data + .token_exp_month + .clone(), + card_exp_year: save_card_and_network_token_data + .network_token + .network_token_data + .token_exp_year + .clone(), + card_holder_name: None, + nick_name: None, + card_issuing_country: None, + card_network: save_card_and_network_token_data + .network_token + .network_token_data + .card_network + .clone(), + card_issuer: None, + card_type: None, + }; + + if payment_method_status + == common_enums::PaymentMethodStatus::Active + { + let (res, dc) = Box::pin(save_in_locker( + state, + merchant_account, + payment_method_create_request.to_owned(), + Some(card_data), + )) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Add Card In Locker Failed")?; + + let (network_token_resp, _dc, _) = Box::pin( + save_network_token_in_locker( + state, + merchant_account, + &save_card_and_network_token_data.card_data, + Some(network_token_data), + payment_method_create_request.clone(), + ), + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Add Network Token In Locker Failed")?; + + ( + (res, dc, network_token_requestor_reference_id), + network_token_resp, + ) + } else { + if let (Some(nt_ref_id), Some(tokenization_service)) = ( + network_token_requestor_reference_id.clone(), + &state.conf.network_tokenization_service, + ) { + let _ = record_operation_time( + async { + network_tokenization::delete_network_token_from_tokenization_service( + state, + nt_ref_id.clone(), + &customer_id, + tokenization_service.get_inner(), + ) + .await + }, + &metrics::DELETE_NETWORK_TOKEN_TIME, + &[], + ) + .await; + } + let (res, dc) = Box::pin(save_in_locker( + state, + merchant_account, + payment_method_create_request.to_owned(), + Some(card_data), + )) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Add Card In Locker Failed")?; + + ((res, dc, None), None) + } } - _ => ((res, dc, None), None), //network_token_resp is None in case of other payment methods } } else { - ((res, dc, None), None) + let (res, dc) = Box::pin(save_in_locker( + state, + merchant_account, + payment_method_create_request.to_owned(), + None, + )) + .await?; + + if is_network_tokenization_enabled { + let pm_data = + &save_payment_method_data.request.get_payment_method_data(); + match pm_data { + domain::PaymentMethodData::Card(card) => { + let ( + network_token_resp, + _network_token_duplication_check, //the duplication check is discarded, since each card has only one token, handling card duplication check will be suffice + network_token_requestor_ref_id, + ) = Box::pin(save_network_token_in_locker( + state, + merchant_account, + card, + None, + payment_method_create_request.clone(), + )) + .await?; + + ( + (res, dc, network_token_requestor_ref_id), + network_token_resp, + ) + } + _ => ((res, dc, None), None), //network_token_resp is None in case of other payment methods + } + } else { + ((res, dc, None), None) + } } }; let network_token_locker_id = match network_token_resp { @@ -810,6 +986,7 @@ where todo!() } +#[cfg(feature = "v1")] pub async fn pre_payment_tokenization( state: &SessionState, customer_id: Option, @@ -867,9 +1044,10 @@ pub async fn pre_payment_tokenization( Some(token_response), network_token_requestor_ref_id.clone(), )), - _ => Ok((None, None)), + _ => Ok((None, network_token_requestor_ref_id.clone())), } } + (Some(token_ref), _) => Ok((None, Some(token_ref))), _ => Ok((None, None)), } } @@ -997,6 +1175,7 @@ pub async fn save_in_locker( state: &SessionState, merchant_account: &domain::MerchantAccount, payment_method_request: api::PaymentMethodCreate, + card_detail: Option, ) -> RouterResult<( api_models::payment_methods::PaymentMethodResponse, Option, @@ -1007,8 +1186,8 @@ pub async fn save_in_locker( .customer_id .clone() .get_required_value("customer_id")?; - match payment_method_request.card.clone() { - Some(card) => Box::pin(payment_methods::cards::add_card_to_locker( + match (payment_method_request.card.clone(), card_detail) { + (_, Some(card)) | (Some(card), _) => Box::pin(payment_methods::cards::add_card_to_locker( state, payment_method_request, &card, @@ -1019,7 +1198,7 @@ pub async fn save_in_locker( .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("Add Card Failed"), - None => { + _ => { let pm_id = common_utils::generate_id(consts::ID_LENGTH, "pm"); let payment_method_response = api::PaymentMethodResponse { merchant_id: merchant_id.clone(), @@ -1077,6 +1256,7 @@ pub async fn save_network_token_in_locker( state: &SessionState, merchant_account: &domain::MerchantAccount, card_data: &domain::Card, + network_token_data: Option, payment_method_request: api::PaymentMethodCreate, ) -> RouterResult<( Option, @@ -1092,54 +1272,73 @@ pub async fn save_network_token_in_locker( .network_tokenization_supported_card_networks .card_networks; - if card_data - .card_network - .as_ref() - .filter(|cn| network_tokenization_supported_card_networks.contains(cn)) - .is_some() - { - match network_tokenization::make_card_network_tokenization_request( - state, - card_data, - &customer_id, - ) - .await - { - Ok((token_response, network_token_requestor_ref_id)) => { - // Only proceed if the tokenization was successful - let network_token_data = api::CardDetail { - card_number: token_response.token.clone(), - card_exp_month: token_response.token_expiry_month.clone(), - card_exp_year: token_response.token_expiry_year.clone(), - card_holder_name: None, - nick_name: None, - card_issuing_country: None, - card_network: Some(token_response.card_brand.clone()), - card_issuer: None, - card_type: None, - }; - - let (res, dc) = Box::pin(payment_methods::cards::add_card_to_locker( + match network_token_data { + Some(nt_data) => { + let (res, dc) = Box::pin(payment_methods::cards::add_card_to_locker( + state, + payment_method_request, + &nt_data, + &customer_id, + merchant_account, + None, + )) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Add Network Token Failed")?; + + Ok((Some(res), dc, None)) + } + None => { + if card_data + .card_network + .as_ref() + .filter(|cn| network_tokenization_supported_card_networks.contains(cn)) + .is_some() + { + match network_tokenization::make_card_network_tokenization_request( state, - payment_method_request, - &network_token_data, + card_data, &customer_id, - merchant_account, - None, - )) + ) .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Add Network Token Failed")?; + { + Ok((token_response, network_token_requestor_ref_id)) => { + // Only proceed if the tokenization was successful + let network_token_data = api::CardDetail { + card_number: token_response.token.clone(), + card_exp_month: token_response.token_expiry_month.clone(), + card_exp_year: token_response.token_expiry_year.clone(), + card_holder_name: None, + nick_name: None, + card_issuing_country: None, + card_network: Some(token_response.card_brand.clone()), + card_issuer: None, + card_type: None, + }; - Ok((Some(res), dc, network_token_requestor_ref_id)) - } - Err(err) => { - logger::error!("Failed to tokenize card: {:?}", err); - Ok((None, None, None)) //None will be returned in case of error when calling network tokenization service + let (res, dc) = Box::pin(payment_methods::cards::add_card_to_locker( + state, + payment_method_request, + &network_token_data, + &customer_id, + merchant_account, + None, + )) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Add Network Token Failed")?; + + Ok((Some(res), dc, network_token_requestor_ref_id)) + } + Err(err) => { + logger::error!("Failed to tokenize card: {:?}", err); + Ok((None, None, None)) //None will be returned in case of error when calling network tokenization service + } + } + } else { + Ok((None, None, None)) //None will be returned in case of unsupported card network. } } - } else { - Ok((None, None, None)) //None will be returned in case of unsupported card network. } } diff --git a/crates/router/src/types/api/admin.rs b/crates/router/src/types/api/admin.rs index 70a5c8dad5c1..3a4220680b77 100644 --- a/crates/router/src/types/api/admin.rs +++ b/crates/router/src/types/api/admin.rs @@ -178,7 +178,7 @@ impl ForeignTryFrom for ProfileResponse { max_auto_retries_enabled: item.max_auto_retries_enabled, is_click_to_pay_enabled: item.is_click_to_pay_enabled, authentication_product_ids: item.authentication_product_ids, - is_tokenize_before_payment_enabled: item.is_tokenize_before_payment_enabled, + is_pre_network_tokenization_enabled: item.is_pre_network_tokenization_enabled, }) } } @@ -250,6 +250,7 @@ impl ForeignTryFrom for ProfileResponse { is_network_tokenization_enabled: item.is_network_tokenization_enabled, is_click_to_pay_enabled: item.is_click_to_pay_enabled, authentication_product_ids: item.authentication_product_ids, + is_pre_network_tokenization_enabled: item.is_pre_network_tokenization_enabled, }) } } @@ -378,6 +379,6 @@ pub async fn create_profile_from_merchant_account( max_auto_retries_enabled: request.max_auto_retries_enabled.map(i16::from), is_click_to_pay_enabled: request.is_click_to_pay_enabled, authentication_product_ids: request.authentication_product_ids, - is_tokenize_before_payment_enabled: request.is_network_tokenization_enabled, + is_pre_network_tokenization_enabled: request.is_network_tokenization_enabled, })) } diff --git a/migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/down.sql b/migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/down.sql deleted file mode 100644 index 56559f452ee4..000000000000 --- a/migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/down.sql +++ /dev/null @@ -1,2 +0,0 @@ --- This file should undo anything in `up.sql` -ALTER TABLE business_profile DROP COLUMN IF EXISTS is_tokenize_before_payment_enabled; \ No newline at end of file diff --git a/migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/up.sql b/migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/up.sql deleted file mode 100644 index d481781c3a8a..000000000000 --- a/migrations/2024-12-02-113838_add_is_tokenize_before_payment_enabled_in_business_profile/up.sql +++ /dev/null @@ -1,2 +0,0 @@ --- Your SQL goes here -ALTER TABLE business_profile ADD COLUMN IF NOT EXISTS is_tokenize_before_payment_enabled BOOLEAN NOT NULL DEFAULT FALSE; \ No newline at end of file diff --git a/migrations/2025-01-22-110625_add_is_pre_network_tokenization_enabled_in_business_profile/down.sql b/migrations/2025-01-22-110625_add_is_pre_network_tokenization_enabled_in_business_profile/down.sql new file mode 100644 index 000000000000..6d40bb557337 --- /dev/null +++ b/migrations/2025-01-22-110625_add_is_pre_network_tokenization_enabled_in_business_profile/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE business_profile DROP COLUMN IF EXISTS is_pre_network_tokenization_enabled; \ No newline at end of file diff --git a/migrations/2025-01-22-110625_add_is_pre_network_tokenization_enabled_in_business_profile/up.sql b/migrations/2025-01-22-110625_add_is_pre_network_tokenization_enabled_in_business_profile/up.sql new file mode 100644 index 000000000000..149471b0b8c9 --- /dev/null +++ b/migrations/2025-01-22-110625_add_is_pre_network_tokenization_enabled_in_business_profile/up.sql @@ -0,0 +1,2 @@ +-- Your SQL goes here +ALTER TABLE business_profile ADD COLUMN IF NOT EXISTS is_pre_network_tokenization_enabled BOOLEAN NOT NULL DEFAULT FALSE; \ No newline at end of file From dc5253fabb023135fe0338cf1870c12212d2a64b Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 11:31:51 +0000 Subject: [PATCH 4/5] docs(openapi): re-generate OpenAPI specification --- api-reference-v2/openapi_spec.json | 11 ++++++++++- api-reference/openapi_spec.json | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 892931256bc2..4e1b44cbcddb 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -18120,6 +18120,10 @@ "type": "object", "description": "Product authentication ids", "nullable": true + }, + "is_pre_network_tokenization_enabled": { + "type": "boolean", + "description": "Indicates if pre network tokenization is enabled or not" } }, "additionalProperties": false @@ -18153,7 +18157,8 @@ "is_tax_connector_enabled", "is_network_tokenization_enabled", "should_collect_cvv_during_payment", - "is_click_to_pay_enabled" + "is_click_to_pay_enabled", + "is_pre_network_tokenization_enabled" ], "properties": { "merchant_id": { @@ -18344,6 +18349,10 @@ "type": "object", "description": "Product authentication ids", "nullable": true + }, + "is_pre_network_tokenization_enabled": { + "type": "boolean", + "description": "Indicates if pre network tokenization is enabled or not" } } }, diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index d218e4d2074b..791d1ca7fdd9 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -22566,6 +22566,10 @@ "type": "object", "description": "Product authentication ids", "nullable": true + }, + "is_pre_network_tokenization_enabled": { + "type": "boolean", + "description": "Indicates if pre network tokenization is enabled or not" } }, "additionalProperties": false @@ -22599,7 +22603,8 @@ "is_tax_connector_enabled", "is_network_tokenization_enabled", "is_auto_retries_enabled", - "is_click_to_pay_enabled" + "is_click_to_pay_enabled", + "is_pre_network_tokenization_enabled" ], "properties": { "merchant_id": { @@ -22807,6 +22812,10 @@ "type": "object", "description": "Product authentication ids", "nullable": true + }, + "is_pre_network_tokenization_enabled": { + "type": "boolean", + "description": "Indicates if pre network tokenization is enabled or not" } } }, From a56539e10223e52a70199f0a4ef42d0136c60b5c Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 11:33:04 +0000 Subject: [PATCH 5/5] chore: run formatter --- crates/diesel_models/src/business_profile.rs | 2 +- crates/router/src/core/payments.rs | 21 ++++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs index da78186715fa..4208614f5f27 100644 --- a/crates/diesel_models/src/business_profile.rs +++ b/crates/diesel_models/src/business_profile.rs @@ -538,7 +538,7 @@ impl ProfileUpdateInternal { authentication_product_ids: authentication_product_ids .or(source.authentication_product_ids), is_pre_network_tokenization_enabled: is_pre_network_tokenization_enabled - .unwrap_or(source.is_pre_network_tokenization_enabled) + .unwrap_or(source.is_pre_network_tokenization_enabled), } } } diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 92d69f2af22e..95a46615a164 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -5078,8 +5078,7 @@ impl From for domain::NetworkTokenData { pub async fn set_payment_method_data_for_pre_network_tokenization( state: &SessionState, payment_data: &mut D, -) -where +) where F: Send + Clone, D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, { @@ -5103,9 +5102,9 @@ where network_token: network_token_data_for_vault.clone(), }; payment_data.set_vault_operation( - PaymentMethodDataAction::SaveCardAndNetworkTokenData( - Box::new(card_and_network_token_data.clone()), - ), + PaymentMethodDataAction::SaveCardAndNetworkTokenData(Box::new( + card_and_network_token_data.clone(), + )), ); payment_data.set_payment_method_data(Some( @@ -5117,18 +5116,18 @@ where card_data: card_data.clone(), network_token_req_ref_id: Some(token_ref), }; - payment_data.set_vault_operation(PaymentMethodDataAction::SaveCardData( - Box::new(card_data_for_vault.clone()), - )) + payment_data.set_vault_operation(PaymentMethodDataAction::SaveCardData(Box::new( + card_data_for_vault.clone(), + ))) } _ => { let card_data_for_vault = CardDataForVault { card_data: card_data.clone(), network_token_req_ref_id: None, }; - payment_data.set_vault_operation(PaymentMethodDataAction::SaveCardData( - Box::new(card_data_for_vault.clone()), - )) + payment_data.set_vault_operation(PaymentMethodDataAction::SaveCardData(Box::new( + card_data_for_vault.clone(), + ))) } } }