From d6ed475454c46188caa28f18afb1a6b6fb38794e Mon Sep 17 00:00:00 2001 From: Prasunna Soppa Date: Tue, 10 Dec 2024 23:52:41 +0530 Subject: [PATCH 01/11] add clear pan possible to gsm --- crates/api_models/src/gsm.rs | 6 ++++++ crates/diesel_models/src/gsm.rs | 6 ++++++ crates/diesel_models/src/schema.rs | 18 ++++++++++++++++++ crates/router/src/core/gsm.rs | 2 ++ crates/router/src/core/payments/retry.rs | 2 ++ crates/router/src/types/transformers.rs | 2 ++ .../down.sql | 2 ++ .../up.sql | 2 ++ 8 files changed, 40 insertions(+) create mode 100644 migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/down.sql create mode 100644 migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/up.sql diff --git a/crates/api_models/src/gsm.rs b/crates/api_models/src/gsm.rs index b95794ef707b..7ffc9c69413b 100644 --- a/crates/api_models/src/gsm.rs +++ b/crates/api_models/src/gsm.rs @@ -29,6 +29,8 @@ pub struct GsmCreateRequest { pub unified_message: Option, /// category in which error belongs to pub error_category: Option, + /// indicates if retry with pan is possible + pub clear_pan_possible: bool, } #[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)] @@ -93,6 +95,8 @@ pub struct GsmUpdateRequest { pub unified_message: Option, /// category in which error belongs to pub error_category: Option, + /// indicates if retry with pan is possible + pub clear_pan_possible: Option, } #[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)] @@ -148,4 +152,6 @@ pub struct GsmResponse { pub unified_message: Option, /// category in which error belongs to pub error_category: Option, + /// indicates if retry with pan is possible + pub clear_pan_possible: bool, } diff --git a/crates/diesel_models/src/gsm.rs b/crates/diesel_models/src/gsm.rs index aba8d75a6ebb..46583a5b22c5 100644 --- a/crates/diesel_models/src/gsm.rs +++ b/crates/diesel_models/src/gsm.rs @@ -41,6 +41,7 @@ pub struct GatewayStatusMap { pub unified_code: Option, pub unified_message: Option, pub error_category: Option, + pub clear_pan_possible: bool, } #[derive(Clone, Debug, Eq, PartialEq, Insertable)] @@ -58,6 +59,7 @@ pub struct GatewayStatusMappingNew { pub unified_code: Option, pub unified_message: Option, pub error_category: Option, + pub clear_pan_possible: bool, } #[derive( @@ -78,6 +80,7 @@ pub struct GatewayStatusMapperUpdateInternal { pub unified_message: Option, pub error_category: Option, pub last_modified: PrimitiveDateTime, + pub clear_pan_possible: Option, } #[derive(Debug)] @@ -89,6 +92,7 @@ pub struct GatewayStatusMappingUpdate { pub unified_code: Option, pub unified_message: Option, pub error_category: Option, + pub clear_pan_possible: Option, } impl From for GatewayStatusMapperUpdateInternal { @@ -101,6 +105,7 @@ impl From for GatewayStatusMapperUpdateInternal { unified_code, unified_message, error_category, + clear_pan_possible, } = value; Self { status, @@ -116,6 +121,7 @@ impl From for GatewayStatusMapperUpdateInternal { sub_flow: None, code: None, message: None, + clear_pan_possible, } } } diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index c30562de9913..5dbf629819e4 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -217,6 +217,22 @@ diesel::table! { } } +diesel::table! { + use diesel::sql_types::*; + use crate::enums::diesel_exports::*; + + callback_mapper (id, type_) { + #[max_length = 128] + id -> Varchar, + #[sql_name = "type"] + #[max_length = 64] + type_ -> Varchar, + data -> Jsonb, + created_at -> Timestamp, + last_modified_at -> Timestamp, + } +} + diesel::table! { use diesel::sql_types::*; use crate::enums::diesel_exports::*; @@ -540,6 +556,7 @@ diesel::table! { unified_message -> Nullable, #[max_length = 64] error_category -> Nullable, + clear_pan_possible -> Bool, } } @@ -1437,6 +1454,7 @@ diesel::allow_tables_to_appear_in_same_query!( blocklist_fingerprint, blocklist_lookup, business_profile, + callback_mapper, captures, cards_info, configs, diff --git a/crates/router/src/core/gsm.rs b/crates/router/src/core/gsm.rs index c7daee111a9a..6c544791a18e 100644 --- a/crates/router/src/core/gsm.rs +++ b/crates/router/src/core/gsm.rs @@ -68,6 +68,7 @@ pub async fn update_gsm_rule( unified_code, unified_message, error_category, + clear_pan_possible, } = gsm_request; GsmInterface::update_gsm_rule( db, @@ -84,6 +85,7 @@ pub async fn update_gsm_rule( unified_code, unified_message, error_category, + clear_pan_possible, }, ) .await diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index fed28b680110..361f4feeb7c3 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -93,6 +93,7 @@ where } else { false }; + //clear-pan retries if should_step_up { router_data = do_retry( @@ -110,6 +111,7 @@ where true, frm_suggestion, business_profile, + ) .await?; } diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 55a523b528eb..bdcf4cfdce31 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -1691,6 +1691,7 @@ impl ForeignFrom for storage::GatewayStatusMapp unified_code: value.unified_code, unified_message: value.unified_message, error_category: value.error_category, + clear_pan_possible: value.clear_pan_possible, } } } @@ -1710,6 +1711,7 @@ impl ForeignFrom for gsm_api_types::GsmResponse { unified_code: value.unified_code, unified_message: value.unified_message, error_category: value.error_category, + clear_pan_possible: value.clear_pan_possible, } } } diff --git a/migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/down.sql b/migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/down.sql new file mode 100644 index 000000000000..80199b9a3348 --- /dev/null +++ b/migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE gateway_status_map DROP COLUMN IF EXISTS clear_pan_possible; \ No newline at end of file diff --git a/migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/up.sql b/migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/up.sql new file mode 100644 index 000000000000..4423df380c44 --- /dev/null +++ b/migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/up.sql @@ -0,0 +1,2 @@ +-- Your SQL goes here +ALTER TABLE gateway_status_map ADD COLUMN IF NOT EXISTS clear_pan_possible BOOLEAN NOT NULL DEFAULT FALSE; \ No newline at end of file From e32db7d889f560362d1f0810486540c4a2f798c1 Mon Sep 17 00:00:00 2001 From: Prasunna Soppa Date: Thu, 12 Dec 2024 13:16:57 +0530 Subject: [PATCH 02/11] 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/retry.rs | 3 +-- crates/router/src/core/payments/transformers.rs | 4 ++-- 17 files changed, 29 insertions(+), 4 deletions(-) diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index dea0ca351231..3714ead78d68 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -4270,6 +4270,18 @@ where pub poll_config: Option, pub tax_data: Option, pub session_id: 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 97832a081846..df0148c8bc30 100644 --- a/crates/router/src/core/payments/operations/payment_approve.rs +++ b/crates/router/src/core/payments/operations/payment_approve.rs @@ -194,6 +194,7 @@ impl GetTracker, api::PaymentsCaptureRequest> poll_config: None, tax_data: None, session_id: 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 ef6570abf8c1..1a81294e98d1 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -203,6 +203,7 @@ impl GetTracker, api::PaymentsCancelRequest> poll_config: None, tax_data: None, session_id: 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 2451cbcd8e9d..845373e4b578 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -254,6 +254,7 @@ impl GetTracker, api::PaymentsCaptu poll_config: None, tax_data: None, session_id: 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 b296d6c3052c..97557f7f9594 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -346,6 +346,7 @@ impl GetTracker, api::PaymentsRequest> for Co poll_config: None, tax_data: None, session_id: 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 67829f1fb732..1759066c49dd 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -812,6 +812,7 @@ impl GetTracker, api::PaymentsRequest> for Pa poll_config: None, tax_data: None, session_id: None, + 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 3bd5b9abcdde..108473a89487 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -613,6 +613,7 @@ impl GetTracker, api::PaymentsRequest> for Pa poll_config: None, tax_data: None, session_id: 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 846f739e0823..0c4f44a23307 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 @@ -165,6 +165,7 @@ impl GetTracker, api::PaymentsPostSessionToke poll_config: None, tax_data: None, session_id: 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 c747c7d984a8..18d2fdad5b0f 100644 --- a/crates/router/src/core/payments/operations/payment_reject.rs +++ b/crates/router/src/core/payments/operations/payment_reject.rs @@ -190,6 +190,7 @@ impl GetTracker, PaymentsCancelRequest> for P poll_config: None, tax_data: None, session_id: 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 ebc663aaf395..6b8265f1e394 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -212,6 +212,7 @@ impl GetTracker, api::PaymentsSessionRequest> poll_config: None, tax_data: None, session_id: 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 edcb0282bdd3..ddd8675fabdd 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -197,6 +197,7 @@ impl GetTracker, api::PaymentsStartRequest> f poll_config: None, tax_data: None, session_id: 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 ab3a70aa1bb4..2369c18c5535 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -506,6 +506,7 @@ async fn get_tracker_for_sync< poll_config: None, tax_data: None, session_id: 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 61a52e7dfb58..774ec98d8ebb 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -490,6 +490,7 @@ impl GetTracker, api::PaymentsRequest> for Pa poll_config: None, tax_data: None, session_id: 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 1b7acc796ec5..ea1178fc683f 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -171,6 +171,7 @@ impl poll_config: None, tax_data: None, session_id: 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 712dff35c7a1..5567beca830a 100644 --- a/crates/router/src/core/payments/operations/tax_calculation.rs +++ b/crates/router/src/core/payments/operations/tax_calculation.rs @@ -178,6 +178,7 @@ impl GetTracker, api::PaymentsDynamicTaxCalcu poll_config: None, tax_data: Some(tax_data), session_id: request.session_id.clone(), + vault_operation: None, }; let get_trackers_response = operations::GetTrackerResponse { operation: Box::new(self), diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index 361f4feeb7c3..dfc4e4152789 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -93,7 +93,6 @@ where } else { false }; - //clear-pan retries if should_step_up { router_data = do_retry( @@ -111,7 +110,7 @@ where true, frm_suggestion, business_profile, - + ) .await?; } diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 6e277ed460f0..1bf67db0f415 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -2580,7 +2580,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 { @@ -2621,7 +2621,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 1ecbe626e828bbae85bb15005643b722c33140cd Mon Sep 17 00:00:00 2001 From: Prasunna Soppa Date: Thu, 19 Dec 2024 00:56:14 +0530 Subject: [PATCH 03/11] add support for clear pan retries --- crates/api_models/src/admin.rs | 9 + crates/api_models/src/payments.rs | 7 + crates/common_utils/src/ext_traits.rs | 46 ++- crates/diesel_models/src/business_profile.rs | 5 + crates/diesel_models/src/schema.rs | 1 + .../src/business_profile.rs | 14 + crates/router/src/core/admin.rs | 2 + crates/router/src/core/payment_methods.rs | 72 ++-- crates/router/src/core/payments.rs | 51 ++- crates/router/src/core/payments/helpers.rs | 319 +++++++++++++++--- crates/router/src/core/payments/operations.rs | 5 + .../operations/payment_complete_authorize.rs | 2 + .../payments/operations/payment_confirm.rs | 2 + .../payments/operations/payment_create.rs | 2 + .../operations/payment_post_session_tokens.rs | 1 + .../payments/operations/payment_session.rs | 1 + .../core/payments/operations/payment_start.rs | 3 + .../payments/operations/payment_status.rs | 1 + .../payments/operations/payment_update.rs | 2 + .../payments_incremental_authorization.rs | 1 + .../payments/operations/tax_calculation.rs | 1 + crates/router/src/core/payments/retry.rs | 17 +- crates/router/src/types/api/admin.rs | 2 + .../down.sql | 2 + .../up.sql | 2 + 25 files changed, 473 insertions(+), 97 deletions(-) create mode 100644 migrations/2024-12-15-171444_add-clear-pan-retries-enabled-to-profile/down.sql create mode 100644 migrations/2024-12-15-171444_add-clear-pan-retries-enabled-to-profile/up.sql diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs index 53ce86789665..dc6643db5219 100644 --- a/crates/api_models/src/admin.rs +++ b/crates/api_models/src/admin.rs @@ -1970,6 +1970,9 @@ pub struct ProfileCreate { /// Indicates if click to pay is enabled or not. #[serde(default)] pub is_click_to_pay_enabled: bool, + + ///Indicates if clear pan retries is enabled or not. + pub is_clear_pan_retries_enabled: Option, } #[nutype::nutype( @@ -2214,6 +2217,9 @@ pub struct ProfileResponse { /// Indicates if click to pay is enabled or not. #[schema(default = false, example = false)] pub is_click_to_pay_enabled: bool, + + ///Indicates if clear pan retries is enabled or not. + pub is_clear_pan_retries_enabled: bool, } #[cfg(feature = "v2")] @@ -2459,6 +2465,9 @@ pub struct ProfileUpdate { /// Indicates if click to pay is enabled or not. #[schema(default = false, example = false)] pub is_click_to_pay_enabled: Option, + + ///Indicates if clear pan retries is enabled or not. + pub is_clear_pan_retries_enabled: Option, } #[cfg(feature = "v2")] diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 6a7f7148bd3a..874af8dc42f2 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -1459,6 +1459,13 @@ impl MandateIds { Some(MandateReferenceId::NetworkMandateId(_)) ) } + + pub fn is_network_token_with_nti_flow(&self) -> bool { + matches!( + self.mandate_reference_id, + Some(MandateReferenceId::NetworkTokenWithNTI(_)) + ) + } } #[derive(Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] diff --git a/crates/common_utils/src/ext_traits.rs b/crates/common_utils/src/ext_traits.rs index 945056aafefd..369ff4ce0800 100644 --- a/crates/common_utils/src/ext_traits.rs +++ b/crates/common_utils/src/ext_traits.rs @@ -295,28 +295,34 @@ impl StringExt for String { /// Extending functionalities of Wrapper types for idiomatic #[cfg(feature = "async_ext")] #[cfg_attr(feature = "async_ext", async_trait::async_trait)] -pub trait AsyncExt { +pub trait AsyncExt { /// Output type of the map function type WrappedSelf; /// Extending map by allowing functions which are async - async fn async_map(self, func: F) -> Self::WrappedSelf + async fn async_map(self, func: F) -> Self::WrappedSelf where F: FnOnce(A) -> Fut + Send, Fut: futures::Future + Send; /// Extending the `and_then` by allowing functions which are async - async fn async_and_then(self, func: F) -> Self::WrappedSelf + async fn async_and_then(self, func: F) -> Self::WrappedSelf where F: FnOnce(A) -> Fut + Send, Fut: futures::Future> + Send; + + /// Extending `unwrap_or_else` to allow async fallback + async fn async_unwrap_or_else(self, func: F) -> A + where + F: FnOnce() -> Fut + Send, + Fut: futures::Future + Send; } #[cfg(feature = "async_ext")] #[cfg_attr(feature = "async_ext", async_trait::async_trait)] -impl AsyncExt for Result { +impl AsyncExt for Result { type WrappedSelf = Result; - async fn async_and_then(self, func: F) -> Self::WrappedSelf + async fn async_and_then(self, func: F) -> Self::WrappedSelf where F: FnOnce(A) -> Fut + Send, Fut: futures::Future> + Send, @@ -327,7 +333,7 @@ impl AsyncExt for Result { } } - async fn async_map(self, func: F) -> Self::WrappedSelf + async fn async_map(self, func: F) -> Self::WrappedSelf where F: FnOnce(A) -> Fut + Send, Fut: futures::Future + Send, @@ -337,13 +343,24 @@ impl AsyncExt for Result { Err(err) => Err(err), } } + + async fn async_unwrap_or_else(self, func: F) -> A + where + F: FnOnce() -> Fut + Send, + Fut: futures::Future + Send, + { + match self { + Ok(a) => a, + Err(_) => func().await, + } + } } #[cfg(feature = "async_ext")] #[cfg_attr(feature = "async_ext", async_trait::async_trait)] -impl AsyncExt for Option { +impl AsyncExt for Option { type WrappedSelf = Option; - async fn async_and_then(self, func: F) -> Self::WrappedSelf + async fn async_and_then(self, func: F) -> Self::WrappedSelf where F: FnOnce(A) -> Fut + Send, Fut: futures::Future> + Send, @@ -354,7 +371,7 @@ impl AsyncExt for Option { } } - async fn async_map(self, func: F) -> Self::WrappedSelf + async fn async_map(self, func: F) -> Self::WrappedSelf where F: FnOnce(A) -> Fut + Send, Fut: futures::Future + Send, @@ -364,6 +381,17 @@ impl AsyncExt for Option { None => None, } } + + async fn async_unwrap_or_else(self, func: F) -> A + where + F: FnOnce() -> Fut + Send, + Fut: futures::Future + Send, + { + match self { + Some(a) => a, + None => func().await, + } + } } /// Extension trait for validating application configuration. This trait provides utilities to diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs index 484a1c0c699e..e860d47e4f60 100644 --- a/crates/diesel_models/src/business_profile.rs +++ b/crates/diesel_models/src/business_profile.rs @@ -58,6 +58,7 @@ pub struct Profile { pub is_auto_retries_enabled: Option, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: bool, + pub is_clear_pan_retries_enabled: Option, } #[cfg(feature = "v1")] @@ -102,6 +103,7 @@ pub struct ProfileNew { pub is_auto_retries_enabled: Option, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: bool, + pub is_clear_pan_retries_enabled: Option, } #[cfg(feature = "v1")] @@ -143,6 +145,7 @@ pub struct ProfileUpdateInternal { pub is_auto_retries_enabled: Option, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: Option, + pub is_clear_pan_retries_enabled: Option, } #[cfg(feature = "v1")] @@ -183,6 +186,7 @@ impl ProfileUpdateInternal { is_auto_retries_enabled, max_auto_retries_enabled, is_click_to_pay_enabled, + is_clear_pan_retries_enabled, } = self; Profile { profile_id: source.profile_id, @@ -244,6 +248,7 @@ impl ProfileUpdateInternal { max_auto_retries_enabled: max_auto_retries_enabled.or(source.max_auto_retries_enabled), is_click_to_pay_enabled: is_click_to_pay_enabled .unwrap_or(source.is_click_to_pay_enabled), + is_clear_pan_retries_enabled: is_clear_pan_retries_enabled.or(source.is_clear_pan_retries_enabled), } } } diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 5dbf629819e4..177ace45d534 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -214,6 +214,7 @@ diesel::table! { is_auto_retries_enabled -> Nullable, max_auto_retries_enabled -> Nullable, is_click_to_pay_enabled -> Bool, + is_clear_pan_retries_enabled -> Nullable, } } diff --git a/crates/hyperswitch_domain_models/src/business_profile.rs b/crates/hyperswitch_domain_models/src/business_profile.rs index 433353b2f813..9d594feeb2e8 100644 --- a/crates/hyperswitch_domain_models/src/business_profile.rs +++ b/crates/hyperswitch_domain_models/src/business_profile.rs @@ -59,6 +59,7 @@ pub struct Profile { pub is_auto_retries_enabled: bool, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: bool, + pub is_clear_pan_retries_enabled: bool, } #[cfg(feature = "v1")] @@ -100,6 +101,7 @@ pub struct ProfileSetter { pub is_auto_retries_enabled: bool, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: bool, + pub is_clear_pan_retries_enabled: bool, } #[cfg(feature = "v1")] @@ -148,6 +150,7 @@ impl From for Profile { is_auto_retries_enabled: value.is_auto_retries_enabled, max_auto_retries_enabled: value.max_auto_retries_enabled, is_click_to_pay_enabled: value.is_click_to_pay_enabled, + is_clear_pan_retries_enabled: value.is_clear_pan_retries_enabled, } } } @@ -198,6 +201,7 @@ pub struct ProfileGeneralUpdate { pub is_auto_retries_enabled: Option, pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: Option, + pub is_clear_pan_retries_enabled: Option, } #[cfg(feature = "v1")] @@ -261,6 +265,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled, max_auto_retries_enabled, is_click_to_pay_enabled, + is_clear_pan_retries_enabled, } = *update; Self { @@ -299,6 +304,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled, max_auto_retries_enabled, is_click_to_pay_enabled, + is_clear_pan_retries_enabled, } } ProfileUpdate::RoutingAlgorithmUpdate { @@ -339,6 +345,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + is_clear_pan_retries_enabled: None, }, ProfileUpdate::DynamicRoutingAlgorithmUpdate { dynamic_routing_algorithm, @@ -377,6 +384,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + is_clear_pan_retries_enabled: None, }, ProfileUpdate::ExtendedCardInfoUpdate { is_extended_card_info_enabled, @@ -415,6 +423,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + is_clear_pan_retries_enabled: None, }, ProfileUpdate::ConnectorAgnosticMitUpdate { is_connector_agnostic_mit_enabled, @@ -453,6 +462,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + is_clear_pan_retries_enabled: None, }, ProfileUpdate::NetworkTokenizationUpdate { is_network_tokenization_enabled, @@ -491,6 +501,7 @@ impl From for ProfileUpdateInternal { is_auto_retries_enabled: None, max_auto_retries_enabled: None, is_click_to_pay_enabled: None, + is_clear_pan_retries_enabled: None, }, } } @@ -548,6 +559,7 @@ impl super::behaviour::Conversion for Profile { is_auto_retries_enabled: Some(self.is_auto_retries_enabled), max_auto_retries_enabled: self.max_auto_retries_enabled, is_click_to_pay_enabled: self.is_click_to_pay_enabled, + is_clear_pan_retries_enabled: Some(self.is_clear_pan_retries_enabled), }) } @@ -617,6 +629,7 @@ impl super::behaviour::Conversion for Profile { is_auto_retries_enabled: item.is_auto_retries_enabled.unwrap_or(false), max_auto_retries_enabled: item.max_auto_retries_enabled, is_click_to_pay_enabled: item.is_click_to_pay_enabled, + is_clear_pan_retries_enabled: item.is_clear_pan_retries_enabled.unwrap_or(false), }) } .await @@ -670,6 +683,7 @@ impl super::behaviour::Conversion for Profile { is_auto_retries_enabled: Some(self.is_auto_retries_enabled), max_auto_retries_enabled: self.max_auto_retries_enabled, is_click_to_pay_enabled: self.is_click_to_pay_enabled, + is_clear_pan_retries_enabled: Some(self.is_clear_pan_retries_enabled), }) } } diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs index 40ed4e755210..efbf5fe4361f 100644 --- a/crates/router/src/core/admin.rs +++ b/crates/router/src/core/admin.rs @@ -3694,6 +3694,7 @@ impl ProfileCreateBridge for api::ProfileCreate { is_auto_retries_enabled: self.is_auto_retries_enabled.unwrap_or_default(), max_auto_retries_enabled: self.max_auto_retries_enabled.map(i16::from), is_click_to_pay_enabled: self.is_click_to_pay_enabled, + is_clear_pan_retries_enabled: self.is_clear_pan_retries_enabled.unwrap_or_default(), })) } @@ -4052,6 +4053,7 @@ impl ProfileUpdateBridge for api::ProfileUpdate { is_auto_retries_enabled: self.is_auto_retries_enabled, max_auto_retries_enabled: self.max_auto_retries_enabled.map(i16::from), is_click_to_pay_enabled: self.is_click_to_pay_enabled, + is_clear_pan_retries_enabled: self.is_clear_pan_retries_enabled, }, ))) } diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index 53ec01298967..f582cf5bb2ab 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -20,7 +20,7 @@ use api_models::payment_methods; #[cfg(feature = "payouts")] pub use api_models::{enums::PayoutConnectors, payouts as payout_types}; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -use common_utils::ext_traits::Encode; +use common_utils::ext_traits::{Encode, OptionExt}; use common_utils::{consts::DEFAULT_LOCALE, id_type}; #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] use common_utils::{ @@ -66,7 +66,7 @@ use crate::{ consts, core::{ errors::{self, RouterResult}, - payments::helpers as payment_helpers, + payments::{self, helpers as payment_helpers}, }, routes::{app::StorageInterface, SessionState}, services, @@ -531,6 +531,8 @@ pub async fn retrieve_payment_method_with_token( mandate_id: Option, payment_method_info: Option, business_profile: &domain::Profile, + should_retry_with_pan: bool, + vault_data: Option<&payments::VaultDataEnum>, ) -> RouterResult { let token = match token_data { storage::PaymentTokenData::TemporaryGeneric(generic_token) => { @@ -574,37 +576,39 @@ pub async fn retrieve_payment_method_with_token( } storage::PaymentTokenData::Permanent(card_token) => { - payment_helpers::retrieve_card_with_permanent_token( - state, - card_token.locker_id.as_ref().unwrap_or(&card_token.token), - card_token - .payment_method_id - .as_ref() - .unwrap_or(&card_token.token), - payment_intent, - card_token_data, - merchant_key_store, - storage_scheme, - mandate_id, - payment_method_info, - business_profile, - ) - .await - .map(|card| Some((card, enums::PaymentMethod::Card)))? - .map( - |(payment_method_data, payment_method)| storage::PaymentMethodDataWithId { - payment_method_data: Some(payment_method_data), - payment_method: Some(payment_method), - payment_method_id: Some( - card_token - .payment_method_id - .as_ref() - .unwrap_or(&card_token.token) - .to_string(), - ), - }, - ) - .unwrap_or_default() + payment_helpers::retrieve_card_with_permanent_token( + state, + card_token.locker_id.as_ref().unwrap_or(&card_token.token), + card_token + .payment_method_id + .as_ref() + .unwrap_or(&card_token.token), + payment_intent, + card_token_data, + merchant_key_store, + storage_scheme, + mandate_id, + payment_method_info, + business_profile, + should_retry_with_pan, + vault_data, + ) + .await + .map(|card| Some((card, enums::PaymentMethod::Card)))? + .map( + |(payment_method_data, payment_method)| storage::PaymentMethodDataWithId { + payment_method_data: Some(payment_method_data), + payment_method: Some(payment_method), + payment_method_id: Some( + card_token + .payment_method_id + .as_ref() + .unwrap_or(&card_token.token) + .to_string(), + ), + }, + ) + .unwrap_or_default() } storage::PaymentTokenData::PermanentCard(card_token) => { @@ -622,6 +626,8 @@ pub async fn retrieve_payment_method_with_token( mandate_id, payment_method_info, business_profile, + should_retry_with_pan, + vault_data, ) .await .map(|card| Some((card, enums::PaymentMethod::Card)))? diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 3714ead78d68..6b5b6a3f85ea 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -202,6 +202,7 @@ where None, &profile, false, + false, ) .await?; @@ -462,6 +463,7 @@ where None, &business_profile, false, + false, ) .await?; @@ -564,6 +566,7 @@ where None, &business_profile, false, + false, ) .await?; @@ -2412,6 +2415,7 @@ pub async fn call_connector_service( frm_suggestion: Option, business_profile: &domain::Profile, is_retry_payment: bool, + should_retry_with_pan: bool, ) -> RouterResult<( RouterData, helpers::MerchantConnectorAccountType, @@ -2464,6 +2468,7 @@ where key_store, customer, business_profile, + should_retry_with_pan ) .await?; *payment_data = pd; @@ -2664,6 +2669,7 @@ pub async fn call_connector_service( frm_suggestion: Option, business_profile: &domain::Profile, is_retry_payment: bool, + should_retry_with_pan: bool, ) -> RouterResult> where F: Send + Clone + Sync, @@ -4034,6 +4040,7 @@ pub async fn get_connector_tokenization_action_when_confirm_true( merchant_key_store: &domain::MerchantKeyStore, customer: &Option, business_profile: &domain::Profile, + should_retry_with_pan: bool, ) -> RouterResult<(D, TokenizationAction)> where F: Send + Clone, @@ -4104,6 +4111,7 @@ where merchant_key_store, customer, business_profile, + should_retry_with_pan, ) .await?; payment_data.set_payment_method_data(payment_method_data); @@ -4123,6 +4131,7 @@ where merchant_key_store, customer, business_profile, + should_retry_with_pan, ) .await?; @@ -4206,6 +4215,7 @@ where merchant_key_store, customer, business_profile, + false, ) .await?; payment_data.set_payment_method_data(payment_method_data); @@ -4275,15 +4285,43 @@ where #[derive(Clone, serde::Serialize, Debug)] pub enum PaymentMethodDataAction{ - VaultData(VaultData) + SaveCard(hyperswitch_domain_models::payment_method_data::Card), + VaultDataVariant(VaultDataEnum) } #[derive(Clone, serde::Serialize, Debug)] +pub enum VaultDataEnum{ + CardVaultData(hyperswitch_domain_models::payment_method_data::Card), + NetworkTokenVaultData(hyperswitch_domain_models::payment_method_data::NetworkTokenData), + CardAndNetworkToken(VaultData) +} + + +#[derive(Default, 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, } +impl VaultDataEnum{ + pub fn get_card_vault_data(&self) -> Option{ + match self{ + VaultDataEnum::CardVaultData(card_data) => Some(card_data.clone()), + VaultDataEnum::NetworkTokenVaultData(_network_token_data) => None, + VaultDataEnum::CardAndNetworkToken(vault_data) => Some(vault_data.card_data.clone()) + } + } + + pub fn get_network_token_data(&self) -> Option{ + match self{ + VaultDataEnum::CardVaultData(_card_data) => None, + VaultDataEnum::NetworkTokenVaultData(network_token_data) => Some(network_token_data.clone()), + VaultDataEnum::CardAndNetworkToken(vault_data) => Some(vault_data.network_token_data.clone()) + } + } +} + + #[derive(Clone, serde::Serialize, Debug)] pub struct TaxData { pub shipping_details: hyperswitch_domain_models::address::Address, @@ -6395,6 +6433,7 @@ pub async fn payment_external_authentication( &key_store, storage_scheme, &business_profile, + ) .await? .ok_or(errors::ApiErrorResponse::InternalServerError) @@ -6754,6 +6793,7 @@ pub trait OperationSessionGetters { fn get_mandate_connector(&self) -> Option<&MandateConnectorDetails>; fn get_force_sync(&self) -> Option; fn get_capture_method(&self) -> Option; + fn get_vault_operation(&self) -> Option<&PaymentMethodDataAction>; #[cfg(feature = "v2")] fn get_optional_payment_attempt(&self) -> Option<&storage::PaymentAttempt>; @@ -6799,6 +6839,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")] @@ -6931,6 +6972,10 @@ impl OperationSessionGetters for PaymentData { self.payment_attempt.capture_method } + fn get_vault_operation(&self) -> Option<&PaymentMethodDataAction>{ + self.vault_operation.as_ref() + } + // #[cfg(feature = "v2")] // fn get_capture_method(&self) -> Option { // Some(self.payment_intent.capture_method) @@ -7047,6 +7092,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")] diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 6d40593060dd..6c51f715646f 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1902,6 +1902,114 @@ pub async fn retrieve_card_with_permanent_token( todo!() } +pub enum VaultFetchAction{ + FetchCardDetailsFromLocker, + FetchCardDetailsForNetworkTransactionFlowFromLocker, + FetchNetworkTokenDataFromTokenizationService, + FetchNetworkTokenDetailsFromLocker, +} + +pub fn decide_vault_fetch_action( + is_network_tokenization_enabled: bool, + mandate_id: Option, +) -> VaultFetchAction{ + //check for connectors as well if network tokenization is enabled + + let is_network_transaction_id_flow = mandate_id.as_ref() + .map(|mandate_ids| mandate_ids.is_network_transaction_id_flow()) + .unwrap_or(false); + let is_network_token_with_nti_flow = mandate_id + .map(|mandate_ids| mandate_ids.is_network_token_with_nti_flow()) + .unwrap_or(false); + + + if !is_network_tokenization_enabled{ + if is_network_transaction_id_flow{ + VaultFetchAction::FetchCardDetailsForNetworkTransactionFlowFromLocker + } + else{ + VaultFetchAction::FetchCardDetailsFromLocker + } + }else{ + if is_network_token_with_nti_flow{ + VaultFetchAction::FetchNetworkTokenDetailsFromLocker + }else if is_network_transaction_id_flow{ + VaultFetchAction::FetchCardDetailsForNetworkTransactionFlowFromLocker + }else{ + VaultFetchAction::FetchNetworkTokenDataFromTokenizationService + } + + } + +} + +#[cfg(all( + any(feature = "v2", feature = "v1"), + not(feature = "payment_methods_v2") +))] +#[allow(clippy::too_many_arguments)] +pub async fn retrieve_payment_method_data_with_permanent_token( + state: &SessionState, + locker_id: &str, + _payment_method_id: &str, + payment_intent: &PaymentIntent, + card_token_data: Option<&domain::CardToken>, + _merchant_key_store: &domain::MerchantKeyStore, + _storage_scheme: enums::MerchantStorageScheme, + mandate_id: Option, + payment_method_info: Option, + business_profile: &domain::Profile, + should_retry_with_pan: bool, + vault_data: Option<&payments::VaultDataEnum>, +) -> RouterResult{ + let customer_id = payment_intent + .customer_id + .as_ref() + .get_required_value("customer_id") + .change_context(errors::ApiErrorResponse::UnprocessableEntity { + message: "no customer id provided for the payment".to_string(), + })?; + + let vault_fetch_action = decide_vault_fetch_action(business_profile.is_network_tokenization_enabled, mandate_id); + + match vault_fetch_action{ + VaultFetchAction::FetchCardDetailsFromLocker => { + let card_result = vault_data.unwrap().get_card_vault_data().map(Ok).async_unwrap_or_else(|| async{ + fetch_card_details_from_locker( + state, + customer_id, + &payment_intent.merchant_id, + locker_id, + card_token_data, + ) + .await + }).await?; + + Ok(domain::PaymentMethodData::Card(card_result)) + + }, + VaultFetchAction::FetchCardDetailsForNetworkTransactionFlowFromLocker => { + fetch_card_details_for_network_transaction_flow_from_locker( + state, + customer_id, + &payment_intent.merchant_id, + locker_id, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to fetch card information from the permanent locker") + + }, + VaultFetchAction::FetchNetworkTokenDataFromTokenizationService => { + todo!() + }, + VaultFetchAction::FetchNetworkTokenDetailsFromLocker => todo!(), + } + + +} + + #[cfg(all( any(feature = "v2", feature = "v1"), not(feature = "payment_methods_v2") @@ -1918,6 +2026,8 @@ pub async fn retrieve_card_with_permanent_token( mandate_id: Option, payment_method_info: Option, business_profile: &domain::Profile, + should_retry_with_pan: bool, + vault_data: Option<&payments::VaultDataEnum>, ) -> RouterResult { let customer_id = payment_intent .customer_id @@ -1933,7 +2043,7 @@ pub async fn retrieve_card_with_permanent_token( .unwrap_or(false); if is_network_transaction_id_flow { - let card_details_from_locker = cards::get_card_from_locker( + fetch_card_details_for_network_transaction_flow_from_locker( state, customer_id, &payment_intent.merchant_id, @@ -1941,35 +2051,7 @@ pub async fn retrieve_card_with_permanent_token( ) .await .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to fetch card details from locker")?; - - let card_network = card_details_from_locker - .card_brand - .map(|card_brand| enums::CardNetwork::from_str(&card_brand)) - .transpose() - .map_err(|e| { - logger::error!("Failed to parse card network {e:?}"); - }) - .ok() - .flatten(); - - let card_details_for_network_transaction_id = hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId { - card_number: card_details_from_locker.card_number, - card_exp_month: card_details_from_locker.card_exp_month, - card_exp_year: card_details_from_locker.card_exp_year, - card_issuer: None, - card_network, - card_type: None, - card_issuing_country: None, - bank_code: None, - nick_name: card_details_from_locker.nick_name.map(masking::Secret::new), - }; - - Ok( - domain::PaymentMethodData::CardDetailsForNetworkTransactionId( - card_details_for_network_transaction_id, - ), - ) + .attach_printable("failed to fetch card information from the permanent locker") } else { fetch_card_details_from_locker( state, @@ -2003,7 +2085,7 @@ pub async fn retrieve_card_with_permanent_token( Err(err) => { logger::info!("Failed to fetch network token data from tokenization service {err:?}"); logger::info!("Falling back to fetch card details from locker"); - fetch_card_details_from_locker( + Ok(domain::PaymentMethodData::Card(fetch_card_details_from_locker( state, customer_id, &payment_intent.merchant_id, @@ -2014,11 +2096,11 @@ pub async fn retrieve_card_with_permanent_token( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable( "failed to fetch card information from the permanent locker", - ) + )?)) } } } else { - fetch_card_details_from_locker( + Ok(domain::PaymentMethodData::Card(fetch_card_details_from_locker( state, customer_id, &payment_intent.merchant_id, @@ -2027,7 +2109,7 @@ pub async fn retrieve_card_with_permanent_token( ) .await .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to fetch card information from the permanent locker") + .attach_printable("failed to fetch card information from the permanent locker")?)) } } (Some(ref pm_data), Some(mandate_ids)) => { @@ -2126,13 +2208,47 @@ pub async fn retrieve_card_with_permanent_token( } } +#[cfg(all( + any(feature = "v2", feature = "v1"), + not(feature = "payment_methods_v2") +))] +#[allow(clippy::too_many_arguments)] +pub async fn retrieve_card_with_permanent_token_for_external_authentication( + state: &SessionState, + locker_id: &str, + payment_intent: &PaymentIntent, + card_token_data: Option<&domain::CardToken>, + _merchant_key_store: &domain::MerchantKeyStore, + _storage_scheme: enums::MerchantStorageScheme, +) -> RouterResult { + + let customer_id = payment_intent + .customer_id + .as_ref() + .get_required_value("customer_id") + .change_context(errors::ApiErrorResponse::UnprocessableEntity { + message: "no customer id provided for the payment".to_string(), + })?; + Ok(domain::PaymentMethodData::Card(fetch_card_details_from_locker( + state, + customer_id, + &payment_intent.merchant_id, + locker_id, + card_token_data, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to fetch card information from the permanent locker")?)) + +} + pub async fn fetch_card_details_from_locker( state: &SessionState, customer_id: &id_type::CustomerId, merchant_id: &id_type::MerchantId, locker_id: &str, card_token_data: Option<&domain::CardToken>, -) -> RouterResult { +) -> RouterResult { let card = cards::get_card_from_locker(state, customer_id, merchant_id, locker_id) .await .change_context(errors::ApiErrorResponse::InternalServerError) @@ -2177,7 +2293,53 @@ pub async fn fetch_card_details_from_locker( card_issuing_country: None, bank_code: None, }; - Ok(domain::PaymentMethodData::Card(api_card.into())) + Ok(api_card.into()) +} + + +pub async fn fetch_card_details_for_network_transaction_flow_from_locker( + state: &SessionState, + customer_id: &id_type::CustomerId, + merchant_id: &id_type::MerchantId, + locker_id: &str, +) -> RouterResult { + let card_details_from_locker = cards::get_card_from_locker( + state, + customer_id, + &merchant_id, + locker_id, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to fetch card details from locker")?; + + let card_network = card_details_from_locker + .card_brand + .map(|card_brand| enums::CardNetwork::from_str(&card_brand)) + .transpose() + .map_err(|e| { + logger::error!("Failed to parse card network {e:?}"); + }) + .ok() + .flatten(); + + let card_details_for_network_transaction_id = hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId { + card_number: card_details_from_locker.card_number, + card_exp_month: card_details_from_locker.card_exp_month, + card_exp_year: card_details_from_locker.card_exp_year, + card_issuer: None, + card_network, + card_type: None, + card_issuing_country: None, + bank_code: None, + nick_name: card_details_from_locker.nick_name.map(masking::Secret::new), + }; + + Ok( + domain::PaymentMethodData::CardDetailsForNetworkTransactionId( + card_details_for_network_transaction_id, + ), + ) } #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] @@ -2307,6 +2469,26 @@ pub async fn make_pm_data<'a, F: Clone, R, D>( todo!() } +// fn my_function(pd: PaymentData, profile: &domain::Profile) { +// let is_network_tokenization_enabled = profile.is_network_tokenization_enabled; +// let is_network_transaction_id_flow = pd +// .mandate_id +// .as_ref() +// .map(|mandate_ids| mandate_ids.is_network_transaction_id_flow()) +// .unwrap_or(false); + +// if is_network_tokenization_enabled && is_network_transaction_id_flow { +// get_network() +// } else { +// get_card() +// } + +// // pd.get_vault_operation().and_then(|data| match data { +// // payments::PaymentMethodDataAction::SaveCard(_) => None, +// // payments::PaymentMethodDataAction::VaultData(vd) => Some(vd), +// // }).or(get_card_from_locker); +// } + #[cfg(all( any(feature = "v1", feature = "v2"), not(feature = "payment_methods_v2") @@ -2319,11 +2501,19 @@ pub async fn make_pm_data<'a, F: Clone, R, D>( customer: &Option, storage_scheme: common_enums::enums::MerchantStorageScheme, business_profile: &domain::Profile, + should_retry_with_pan: bool, ) -> RouterResult<( BoxedOperation<'a, F, R, D>, Option, Option, -)> { +)> +where + F: Clone, +{ + use crate::core::payments::OperationSessionGetters; + + use super::OperationSessionSetters; + let request = payment_data.payment_method_data.clone(); let mut card_token_data = payment_data @@ -2371,6 +2561,20 @@ pub async fn make_pm_data<'a, F: Clone, R, D>( // TODO: Handle case where payment method and token both are present in request properly. let (payment_method, pm_id) = match (&request, payment_data.token_data.as_ref()) { (_, Some(hyperswitch_token)) => { + let stalled_payment_method_data = payment_data.get_vault_operation(); + // valut data : card data, token data(opt, opt) + // vault data : Card(card), Networktoken(NT), CARD and Network (token) + + + let vd = stalled_payment_method_data + .and_then(|data| match data { + payments::PaymentMethodDataAction::SaveCard(_) => None, + payments::PaymentMethodDataAction::VaultDataVariant(vd) => Some(vd), + + }); + + + let pm_data = Box::pin(payment_methods::retrieve_payment_method_with_token( state, merchant_key_store, @@ -2383,11 +2587,34 @@ pub async fn make_pm_data<'a, F: Clone, R, D>( mandate_id, payment_data.payment_method_info.clone(), business_profile, + should_retry_with_pan, + vd, )) .await; let payment_method_details = pm_data.attach_printable("in 'make_pm_data'")?; + // if let Some(ref payment_method_data) = payment_method_details.payment_method_data { + // match payment_method_data { + // domain::PaymentMethodData::Card(card) => { + // payment_data.set_vault_operation( + // payments::PaymentMethodDataAction::VaultData(payments::VaultData { + // card_data: Some(card.clone()), + // network_token_data: vd.network_token_data, + // }), + // ); + // } + // domain::PaymentMethodData::NetworkToken(nt_data) => { + // payment_data.set_vault_operation( + // payments::PaymentMethodDataAction::VaultData(payments::VaultData { + // card_data: vd.card_data, + // network_token_data: Some(nt_data.clone()), + // }), + // ); + // } + // _ => {} + // } + // }; Ok::<_, error_stack::Report>( if let Some(payment_method_data) = payment_method_details.payment_method_data { payment_data.payment_attempt.payment_method = @@ -5765,38 +5992,24 @@ pub async fn get_payment_method_details_from_payment_token( .await } - storage::PaymentTokenData::Permanent(card_token) => retrieve_card_with_permanent_token( + storage::PaymentTokenData::Permanent(card_token) => retrieve_card_with_permanent_token_for_external_authentication( state, &card_token.token, - card_token - .payment_method_id - .as_ref() - .unwrap_or(&card_token.token), payment_intent, None, key_store, storage_scheme, - None, - None, - business_profile, ) .await .map(|card| Some((card, enums::PaymentMethod::Card))), - storage::PaymentTokenData::PermanentCard(card_token) => retrieve_card_with_permanent_token( + storage::PaymentTokenData::PermanentCard(card_token) => retrieve_card_with_permanent_token_for_external_authentication( state, &card_token.token, - card_token - .payment_method_id - .as_ref() - .unwrap_or(&card_token.token), payment_intent, None, key_store, storage_scheme, - None, - None, - business_profile, ) .await .map(|card| Some((card, enums::PaymentMethod::Card))), diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs index f957b939acfe..15f98dd1d77c 100644 --- a/crates/router/src/core/payments/operations.rs +++ b/crates/router/src/core/payments/operations.rs @@ -235,6 +235,7 @@ pub trait Domain: Send + Sync { merchant_key_store: &domain::MerchantKeyStore, customer: &Option, business_profile: &domain::Profile, + should_retry_with_pan: bool, ) -> RouterResult<( BoxedOperation<'a, F, R, D>, Option, @@ -516,6 +517,7 @@ where _merchant_key_store: &domain::MerchantKeyStore, _customer: &Option, _business_profile: &domain::Profile, + _should_retry_with_pan: bool, ) -> RouterResult<( BoxedOperation<'a, F, api::PaymentsRetrieveRequest, D>, Option, @@ -610,6 +612,7 @@ where _merchant_key_store: &domain::MerchantKeyStore, _customer: &Option, _business_profile: &domain::Profile, + _should_retry_with_pan: bool, ) -> RouterResult<( BoxedOperation<'a, F, api::PaymentsCaptureRequest, D>, Option, @@ -715,6 +718,7 @@ where _merchant_key_store: &domain::MerchantKeyStore, _customer: &Option, _business_profile: &domain::Profile, + _should_retry_with_pan: bool, ) -> RouterResult<( BoxedOperation<'a, F, api::PaymentsCancelRequest, D>, Option, @@ -799,6 +803,7 @@ where _merchant_key_store: &domain::MerchantKeyStore, _customer: &Option, _business_profile: &domain::Profile, + _should_retry_with_pan: bool, ) -> RouterResult<( BoxedOperation<'a, F, api::PaymentsRejectRequest, D>, Option, 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 97557f7f9594..63a3027861f3 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -404,6 +404,7 @@ impl Domain> for Comple merchant_key_store: &domain::MerchantKeyStore, customer: &Option, business_profile: &domain::Profile, + should_retry_with_pan: bool, ) -> RouterResult<( CompleteAuthorizeOperation<'a, F>, Option, @@ -417,6 +418,7 @@ impl Domain> for Comple customer, storage_scheme, business_profile, + should_retry_with_pan, )) .await?; Ok((op, payment_method_data, pm_id)) diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index 1759066c49dd..d25f3ca4c0a4 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -862,6 +862,7 @@ impl Domain> for Paymen key_store: &domain::MerchantKeyStore, customer: &Option, business_profile: &domain::Profile, + should_retry_with_pan: bool, ) -> RouterResult<( PaymentConfirmOperation<'a, F>, Option, @@ -875,6 +876,7 @@ impl Domain> for Paymen customer, storage_scheme, business_profile, + should_retry_with_pan, )) .await?; diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 108473a89487..0035b4d84c98 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -765,6 +765,7 @@ impl Domain> for Paymen merchant_key_store: &domain::MerchantKeyStore, customer: &Option, business_profile: &domain::Profile, + should_retry_with_pan: bool, ) -> RouterResult<( PaymentCreateOperation<'a, F>, Option, @@ -778,6 +779,7 @@ impl Domain> for Paymen customer, storage_scheme, business_profile, + should_retry_with_pan, )) .await } 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 0c4f44a23307..ba64c7ab8325 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 @@ -210,6 +210,7 @@ impl Domain, _business_profile: &domain::Profile, + _should_retry_with_pan: bool, ) -> RouterResult<( PaymentPostSessionTokensOperation<'a, F>, Option, diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index 6b8265f1e394..cf710c7d9d01 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -333,6 +333,7 @@ where _merchant_key_store: &domain::MerchantKeyStore, _customer: &Option, _business_profile: &domain::Profile, + _should_retry_with_pan: bool, ) -> RouterResult<( PaymentSessionOperation<'b, F>, Option, diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index ddd8675fabdd..9a4c89da6d93 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -305,6 +305,7 @@ where merchant_key_store: &domain::MerchantKeyStore, customer: &Option, business_profile: &domain::Profile, + should_retry_with_pan: bool, ) -> RouterResult<( PaymentSessionOperation<'a, F>, Option, @@ -325,6 +326,8 @@ where customer, storage_scheme, business_profile, + should_retry_with_pan, + )) .await } else { diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index 2369c18c5535..12d70a811427 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -94,6 +94,7 @@ impl Domain> for Paymen _merchant_key_store: &domain::MerchantKeyStore, _customer: &Option, _business_profile: &domain::Profile, + _should_retry_with_pan: bool, ) -> RouterResult<( PaymentStatusOperation<'a, F, api::PaymentsRequest>, Option, diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 774ec98d8ebb..e4662a85e865 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -641,6 +641,7 @@ impl Domain> for Paymen merchant_key_store: &domain::MerchantKeyStore, customer: &Option, business_profile: &domain::Profile, + should_retry_with_pan: bool, ) -> RouterResult<( PaymentUpdateOperation<'a, F>, Option, @@ -654,6 +655,7 @@ impl Domain> for Paymen customer, storage_scheme, business_profile, + should_retry_with_pan, )) .await } 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 ea1178fc683f..e49ab1de3401 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -340,6 +340,7 @@ impl Domain, _business_profile: &domain::Profile, + _should_retry_with_pan: bool, ) -> RouterResult<( PaymentIncrementalAuthorizationOperation<'a, F>, Option, diff --git a/crates/router/src/core/payments/operations/tax_calculation.rs b/crates/router/src/core/payments/operations/tax_calculation.rs index 5567beca830a..5632e3fe029f 100644 --- a/crates/router/src/core/payments/operations/tax_calculation.rs +++ b/crates/router/src/core/payments/operations/tax_calculation.rs @@ -333,6 +333,7 @@ impl Domain, _business_profile: &domain::Profile, + _should_retry_with_pan: bool, ) -> RouterResult<( PaymentSessionUpdateOperation<'a, F>, Option, diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index dfc4e4152789..c93c74196173 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -110,7 +110,7 @@ where true, frm_suggestion, business_profile, - + false, ) .await?; } @@ -143,6 +143,18 @@ where let connector = super::get_connector_data(&mut connectors)?; + let clear_pan_possible = initial_gsm + .clone() + .map(|gsm| gsm.clear_pan_possible) + .unwrap_or(false); + + let should_retry_with_pan = if clear_pan_possible && business_profile.is_clear_pan_retries_enabled{ + true + } else { + false + }; + + router_data = do_retry( &state.clone(), req_state.clone(), @@ -159,6 +171,7 @@ where false, frm_suggestion, business_profile, + should_retry_with_pan ) .await?; @@ -310,6 +323,7 @@ pub async fn do_retry( is_step_up: bool, frm_suggestion: Option, business_profile: &domain::Profile, + should_retry_with_pan: bool, ) -> RouterResult> where F: Clone + Send + Sync, @@ -353,6 +367,7 @@ where frm_suggestion, business_profile, true, + should_retry_with_pan ) .await?; diff --git a/crates/router/src/types/api/admin.rs b/crates/router/src/types/api/admin.rs index 7207f63aa0fc..f338119c9312 100644 --- a/crates/router/src/types/api/admin.rs +++ b/crates/router/src/types/api/admin.rs @@ -175,6 +175,7 @@ impl ForeignTryFrom for ProfileResponse { is_auto_retries_enabled: item.is_auto_retries_enabled, max_auto_retries_enabled: item.max_auto_retries_enabled, is_click_to_pay_enabled: item.is_click_to_pay_enabled, + is_clear_pan_retries_enabled: item.is_clear_pan_retries_enabled, }) } } @@ -370,5 +371,6 @@ pub async fn create_profile_from_merchant_account( is_auto_retries_enabled: request.is_auto_retries_enabled.unwrap_or_default(), max_auto_retries_enabled: request.max_auto_retries_enabled.map(i16::from), is_click_to_pay_enabled: request.is_click_to_pay_enabled, + is_clear_pan_retries_enabled: request.is_clear_pan_retries_enabled.unwrap_or_default(), })) } diff --git a/migrations/2024-12-15-171444_add-clear-pan-retries-enabled-to-profile/down.sql b/migrations/2024-12-15-171444_add-clear-pan-retries-enabled-to-profile/down.sql new file mode 100644 index 000000000000..ac61e6b3dcad --- /dev/null +++ b/migrations/2024-12-15-171444_add-clear-pan-retries-enabled-to-profile/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE business_profile DROP COLUMN IF EXISTS is_clear_pan_retries_enabled; \ No newline at end of file diff --git a/migrations/2024-12-15-171444_add-clear-pan-retries-enabled-to-profile/up.sql b/migrations/2024-12-15-171444_add-clear-pan-retries-enabled-to-profile/up.sql new file mode 100644 index 000000000000..160bd8704a43 --- /dev/null +++ b/migrations/2024-12-15-171444_add-clear-pan-retries-enabled-to-profile/up.sql @@ -0,0 +1,2 @@ +-- Your SQL goes here +ALTER TABLE business_profile ADD COLUMN IF NOT EXISTS is_clear_pan_retries_enabled BOOLEAN; \ No newline at end of file From a10794e4c413bb3d2f77a5cc01630ad4f862ad18 Mon Sep 17 00:00:00 2001 From: Prasunna Soppa Date: Fri, 20 Dec 2024 02:43:37 +0530 Subject: [PATCH 04/11] add support for clear pan retries --- crates/router/src/core/payment_methods.rs | 8 +- crates/router/src/core/payments.rs | 1 - crates/router/src/core/payments/helpers.rs | 644 ++++++++++----------- 3 files changed, 304 insertions(+), 349 deletions(-) diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index bc99bbb0d8ee..b8b21f308562 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -24,7 +24,7 @@ use api_models::payment_methods; #[cfg(feature = "payouts")] pub use api_models::{enums::PayoutConnectors, payouts as payout_types}; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -use common_utils::ext_traits::{Encode, OptionExt}; +use common_utils::ext_traits::Encode; use common_utils::{consts::DEFAULT_LOCALE, id_type}; #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] use common_utils::{ @@ -580,7 +580,7 @@ pub async fn retrieve_payment_method_with_token( } storage::PaymentTokenData::Permanent(card_token) => { - payment_helpers::retrieve_card_with_permanent_token( + payment_helpers::retrieve_payment_method_data_with_permanent_token( state, card_token.locker_id.as_ref().unwrap_or(&card_token.token), card_token @@ -594,7 +594,7 @@ pub async fn retrieve_payment_method_with_token( mandate_id, payment_method_info, business_profile, - payment_attempt.connector.clone(), + payment_attempt.connector.clone(), should_retry_with_pan, vault_data, ) @@ -617,7 +617,7 @@ pub async fn retrieve_payment_method_with_token( } storage::PaymentTokenData::PermanentCard(card_token) => { - payment_helpers::retrieve_card_with_permanent_token( + payment_helpers::retrieve_payment_method_data_with_permanent_token( state, card_token.locker_id.as_ref().unwrap_or(&card_token.token), card_token diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 0961a1feee50..fd336523c7c1 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -6513,7 +6513,6 @@ pub async fn payment_external_authentication( &payment_intent, &key_store, storage_scheme, - &business_profile, ) .await? diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 69e445a6d156..d283eee40d09 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1898,120 +1898,86 @@ pub async fn retrieve_card_with_permanent_token( todo!() } -pub enum VaultFetchAction{ +pub enum VaultFetchAction { FetchCardDetailsFromLocker, FetchCardDetailsForNetworkTransactionFlowFromLocker, FetchNetworkTokenDataFromTokenizationService, - FetchNetworkTokenDetailsFromLocker, + FetchNetworkTokenDetailsFromLocker(api_models::payments::NetworkTokenWithNTIRef), + NoFetchAction, } pub fn decide_vault_fetch_action( - is_network_tokenization_enabled: bool, + is_network_tokenization_enabled: bool, mandate_id: Option, -) -> VaultFetchAction{ - //check for connectors as well if network tokenization is enabled - - let is_network_transaction_id_flow = mandate_id.as_ref() - .map(|mandate_ids| mandate_ids.is_network_transaction_id_flow()) - .unwrap_or(false); - let is_network_token_with_nti_flow = mandate_id - .map(|mandate_ids| mandate_ids.is_network_token_with_nti_flow()) - .unwrap_or(false); - - - if !is_network_tokenization_enabled{ - if is_network_transaction_id_flow{ - VaultFetchAction::FetchCardDetailsForNetworkTransactionFlowFromLocker - } - else{ - VaultFetchAction::FetchCardDetailsFromLocker - } - }else{ - if is_network_token_with_nti_flow{ - VaultFetchAction::FetchNetworkTokenDetailsFromLocker - }else if is_network_transaction_id_flow{ - VaultFetchAction::FetchCardDetailsForNetworkTransactionFlowFromLocker - }else{ - VaultFetchAction::FetchNetworkTokenDataFromTokenizationService - } - - } + connector: Option, + network_tokenization_supported_connectors: &std::collections::HashSet, + should_retry_with_pan: bool, +) -> VaultFetchAction { + let normal_flow = || { + determine_standard_vault_action( + is_network_tokenization_enabled, + mandate_id, + connector, + network_tokenization_supported_connectors, + ) + }; + let action = should_retry_with_pan + .then_some(VaultFetchAction::FetchCardDetailsFromLocker) + .unwrap_or_else(normal_flow); + action } -#[cfg(all( - any(feature = "v2", feature = "v1"), - not(feature = "payment_methods_v2") -))] -#[allow(clippy::too_many_arguments)] -pub async fn retrieve_payment_method_data_with_permanent_token( - state: &SessionState, - locker_id: &str, - _payment_method_id: &str, - payment_intent: &PaymentIntent, - card_token_data: Option<&domain::CardToken>, - _merchant_key_store: &domain::MerchantKeyStore, - _storage_scheme: enums::MerchantStorageScheme, +pub fn determine_standard_vault_action( + is_network_tokenization_enabled: bool, mandate_id: Option, - payment_method_info: Option, - business_profile: &domain::Profile, - should_retry_with_pan: bool, - vault_data: Option<&payments::VaultDataEnum>, -) -> RouterResult{ - let customer_id = payment_intent - .customer_id + connector: Option, + network_tokenization_supported_connectors: &std::collections::HashSet, +) -> VaultFetchAction { + let is_network_transaction_id_flow = mandate_id .as_ref() - .get_required_value("customer_id") - .change_context(errors::ApiErrorResponse::UnprocessableEntity { - message: "no customer id provided for the payment".to_string(), - })?; - - let vault_fetch_action = decide_vault_fetch_action(business_profile.is_network_tokenization_enabled, mandate_id); - - match vault_fetch_action{ - VaultFetchAction::FetchCardDetailsFromLocker => { - let card_result = vault_data.unwrap().get_card_vault_data().map(Ok).async_unwrap_or_else(|| async{ - fetch_card_details_from_locker( - state, - customer_id, - &payment_intent.merchant_id, - locker_id, - card_token_data, - ) - .await - }).await?; + .map(|mandate_ids| mandate_ids.is_network_transaction_id_flow()) + .unwrap_or(false); - Ok(domain::PaymentMethodData::Card(card_result)) - - }, - VaultFetchAction::FetchCardDetailsForNetworkTransactionFlowFromLocker => { - fetch_card_details_for_network_transaction_flow_from_locker( - state, - customer_id, - &payment_intent.merchant_id, - locker_id, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to fetch card information from the permanent locker") - - }, - VaultFetchAction::FetchNetworkTokenDataFromTokenizationService => { - todo!() - }, - VaultFetchAction::FetchNetworkTokenDetailsFromLocker => todo!(), + if !is_network_tokenization_enabled { + if is_network_transaction_id_flow { + VaultFetchAction::FetchCardDetailsForNetworkTransactionFlowFromLocker + } else { + VaultFetchAction::FetchCardDetailsFromLocker + } + } else { + match mandate_id { + Some(mandate_ids) => match mandate_ids.mandate_reference_id { + Some(api_models::payments::MandateReferenceId::NetworkTokenWithNTI(nt_data)) => { + VaultFetchAction::FetchNetworkTokenDetailsFromLocker(nt_data) + } + Some(api_models::payments::MandateReferenceId::NetworkMandateId(_)) => { + VaultFetchAction::FetchCardDetailsForNetworkTransactionFlowFromLocker + } + Some(api_models::payments::MandateReferenceId::ConnectorMandateId(_)) | None => { + VaultFetchAction::NoFetchAction + } + }, + None => { + if connector + .map(|conn| network_tokenization_supported_connectors.contains(&conn)) + .unwrap_or(false) + { + VaultFetchAction::FetchNetworkTokenDataFromTokenizationService + } else { + VaultFetchAction::FetchCardDetailsFromLocker + } + } + } } - - } - #[cfg(all( any(feature = "v2", feature = "v1"), not(feature = "payment_methods_v2") ))] #[allow(clippy::too_many_arguments)] -pub async fn retrieve_card_with_permanent_token( +pub async fn retrieve_payment_method_data_with_permanent_token( state: &SessionState, locker_id: &str, _payment_method_id: &str, @@ -2023,7 +1989,7 @@ pub async fn retrieve_card_with_permanent_token( payment_method_info: Option, business_profile: &domain::Profile, connector: Option, - should_retry_with_pan: bool, + should_retry_with_pan: bool, vault_data: Option<&payments::VaultDataEnum>, ) -> RouterResult { let customer_id = payment_intent @@ -2034,89 +2000,62 @@ pub async fn retrieve_card_with_permanent_token( message: "no customer id provided for the payment".to_string(), })?; - if !business_profile.is_network_tokenization_enabled { - let is_network_transaction_id_flow = mandate_id - .map(|mandate_ids| mandate_ids.is_network_transaction_id_flow()) - .unwrap_or(false); - - if is_network_transaction_id_flow { - fetch_card_details_for_network_transaction_flow_from_locker( - state, - customer_id, - &payment_intent.merchant_id, - locker_id, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to fetch card details from locker")?; + let network_tokenization_supported_connectors = &state + .conf + .network_tokenization_supported_connectors + .connector_list; - let card_network = card_details_from_locker - .card_brand - .map(|card_brand| enums::CardNetwork::from_str(&card_brand)) - .transpose() - .map_err(|e| { - logger::error!("Failed to parse card network {e:?}"); + let connector_variant = connector + .as_ref() + .map(|conn| { + api_enums::Connector::from_str(conn.as_str()) + .change_context(errors::ApiErrorResponse::InvalidDataValue { + field_name: "connector", }) - .ok() - .flatten(); - - let card_details_for_network_transaction_id = hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId { - card_number: card_details_from_locker.card_number, - card_exp_month: card_details_from_locker.card_exp_month, - card_exp_year: card_details_from_locker.card_exp_year, - card_issuer: None, - card_network, - card_type: None, - card_issuing_country: None, - bank_code: None, - nick_name: card_details_from_locker.nick_name.map(masking::Secret::new), - card_holder_name: card_details_from_locker.name_on_card.clone(), - }; + .attach_printable_lazy(|| format!("unable to parse connector name {connector:?}")) + }) + .transpose()?; - Ok( - domain::PaymentMethodData::CardDetailsForNetworkTransactionId( - card_details_for_network_transaction_id, - ), - ) - } else { - fetch_card_details_from_locker( - state, - customer_id, - &payment_intent.merchant_id, - locker_id, - card_token_data, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to fetch card information from the permanent locker") - } - } else { - match (payment_method_info, mandate_id) { - (None, _) => Err(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Payment method data is not present"), - (Some(ref pm_data), None) => { - // Regular (non-mandate) Payment flow - let network_tokenization_supported_connectors = &state - .conf - .network_tokenization_supported_connectors - .connector_list; - let connector_variant = connector - .as_ref() - .map(|conn| { - api_enums::Connector::from_str(conn.as_str()) - .change_context(errors::ApiErrorResponse::InvalidDataValue { - field_name: "connector", - }) - .attach_printable_lazy(|| { - format!("unable to parse connector name {connector:?}") - }) + let vault_fetch_action = decide_vault_fetch_action( + business_profile.is_network_tokenization_enabled, + mandate_id, + connector_variant, + network_tokenization_supported_connectors, + should_retry_with_pan, + ); + match payment_method_info { + Some(ref pm_data) => match vault_fetch_action { + VaultFetchAction::FetchCardDetailsFromLocker => { + let card_result = vault_data + .and_then(|vd| vd.get_card_vault_data()) + .map(Ok) + .async_unwrap_or_else(|| async { + fetch_card_details_from_locker( + state, + customer_id, + &payment_intent.merchant_id, + locker_id, + card_token_data, + ) + .await }) - .transpose()?; - if let (Some(_conn), Some(token_ref)) = ( - connector_variant - .filter(|conn| network_tokenization_supported_connectors.contains(conn)), - pm_data.network_token_requestor_reference_id.clone(), - ) { + .await?; + + Ok(domain::PaymentMethodData::Card(card_result)) + } + VaultFetchAction::FetchCardDetailsForNetworkTransactionFlowFromLocker => { + fetch_card_details_for_network_transaction_flow_from_locker( + state, + customer_id, + &payment_intent.merchant_id, + locker_id, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to fetch card information from the permanent locker") + } + VaultFetchAction::FetchNetworkTokenDataFromTokenizationService => { + if let Some(token_ref) = pm_data.network_token_requestor_reference_id.clone() { logger::info!("Fetching network token data from tokenization service"); match network_tokenization::get_token_from_tokenization_service( state, token_ref, pm_data, @@ -2132,7 +2071,31 @@ pub async fn retrieve_card_with_permanent_token( Err(err) => { logger::info!("Failed to fetch network token data from tokenization service {err:?}"); logger::info!("Falling back to fetch card details from locker"); - Ok(domain::PaymentMethodData::Card(fetch_card_details_from_locker( + Ok(domain::PaymentMethodData::Card(vault_data + .and_then(|vd| vd.get_card_vault_data()) + .map(Ok) + .async_unwrap_or_else(|| async { + fetch_card_details_from_locker( + state, + customer_id, + &payment_intent.merchant_id, + locker_id, + card_token_data, + ) + .await + }) + .await? + )) + } + } + } else { + logger::info!("Either the connector is not in the NT supported list or token requestor reference ID is absent"); + logger::info!("Falling back to fetch card details from locker"); + Ok(domain::PaymentMethodData::Card(vault_data + .and_then(|vd| vd.get_card_vault_data()) + .map(Ok) + .async_unwrap_or_else(|| async { + fetch_card_details_from_locker( state, customer_id, &payment_intent.merchant_id, @@ -2140,122 +2103,38 @@ pub async fn retrieve_card_with_permanent_token( card_token_data, ) .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable( - "failed to fetch card information from the permanent locker", - )?)) - } - } - } else { - logger::info!("Either the connector is not in the NT supported list or token requestor reference ID is absent"); - logger::info!("Falling back to fetch card details from locker"); - Ok(domain::PaymentMethodData::Card(fetch_card_details_from_locker( - state, - customer_id, - &payment_intent.merchant_id, - locker_id, - card_token_data, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to fetch card information from the permanent locker")?)) + }) + .await? + )) } } - (Some(ref pm_data), Some(mandate_ids)) => { - // Mandate Payment flow - match mandate_ids.mandate_reference_id { - Some(api_models::payments::MandateReferenceId::NetworkTokenWithNTI( - nt_data, - )) => { - { - if let Some(network_token_locker_id) = - pm_data.network_token_locker_id.as_ref() - { - let mut token_data = cards::get_card_from_locker( - state, - customer_id, - &payment_intent.merchant_id, - network_token_locker_id, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable( - "failed to fetch network token information from the permanent locker", - )?; - let expiry = nt_data.token_exp_month.zip(nt_data.token_exp_year); - if let Some((exp_month, exp_year)) = expiry { - token_data.card_exp_month = exp_month; - token_data.card_exp_year = exp_year; - } - let network_token_data = domain::NetworkTokenData { - token_number: token_data.card_number, - token_cryptogram: None, - token_exp_month: token_data.card_exp_month, - token_exp_year: token_data.card_exp_year, - nick_name: token_data.nick_name.map(masking::Secret::new), - card_issuer: None, - card_network: None, - card_type: None, - card_issuing_country: None, - bank_code: None, - eci: None, - }; - Ok(domain::PaymentMethodData::NetworkToken(network_token_data)) - } else { - // Mandate but network token locker id is not present - Err(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Network token locker id is not present") - } - } - } - - Some(api_models::payments::MandateReferenceId::NetworkMandateId(_)) => { - let card_details_from_locker = cards::get_card_from_locker( - state, - customer_id, - &payment_intent.merchant_id, - locker_id, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to fetch card details from locker")?; - - let card_network = card_details_from_locker - .card_brand - .map(|card_brand| enums::CardNetwork::from_str(&card_brand)) - .transpose() - .map_err(|e| { - logger::error!("Failed to parse card network {e:?}"); - }) - .ok() - .flatten(); - - let card_details_for_network_transaction_id = hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId { - card_number: card_details_from_locker.card_number, - card_exp_month: card_details_from_locker.card_exp_month, - card_exp_year: card_details_from_locker.card_exp_year, - card_issuer: None, - card_network, - card_type: None, - card_issuing_country: None, - bank_code: None, - nick_name: card_details_from_locker.nick_name.map(masking::Secret::new), - card_holder_name: card_details_from_locker.name_on_card, - }; - - Ok( - domain::PaymentMethodData::CardDetailsForNetworkTransactionId( - card_details_for_network_transaction_id, - ), - ) - } - - Some(api_models::payments::MandateReferenceId::ConnectorMandateId(_)) - | None => Err(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Payment method data is not present"), + VaultFetchAction::FetchNetworkTokenDetailsFromLocker(nt_data) => { + if let Some(network_token_locker_id) = pm_data.network_token_locker_id.as_ref() { + let network_token_data = vault_data + .and_then(|vd| vd.get_network_token_data()) + .map(Ok) + .async_unwrap_or_else(|| async { + fetch_network_token_details_from_locker( + state, + customer_id, + &payment_intent.merchant_id, + network_token_locker_id, + nt_data, + ) + .await + }) + .await?; + Ok(domain::PaymentMethodData::NetworkToken(network_token_data)) + } else { + Err(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Network token locker id is not present") } } - } + VaultFetchAction::NoFetchAction => Err(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Payment method data is not present"), + }, + None => Err(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Payment method data is not present"), } } @@ -2272,7 +2151,6 @@ pub async fn retrieve_card_with_permanent_token_for_external_authentication( _merchant_key_store: &domain::MerchantKeyStore, _storage_scheme: enums::MerchantStorageScheme, ) -> RouterResult { - let customer_id = payment_intent .customer_id .as_ref() @@ -2280,7 +2158,8 @@ pub async fn retrieve_card_with_permanent_token_for_external_authentication( .change_context(errors::ApiErrorResponse::UnprocessableEntity { message: "no customer id provided for the payment".to_string(), })?; - Ok(domain::PaymentMethodData::Card(fetch_card_details_from_locker( + Ok(domain::PaymentMethodData::Card( + fetch_card_details_from_locker( state, customer_id, &payment_intent.merchant_id, @@ -2289,8 +2168,8 @@ pub async fn retrieve_card_with_permanent_token_for_external_authentication( ) .await .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to fetch card information from the permanent locker")?)) - + .attach_printable("failed to fetch card information from the permanent locker")?, + )) } pub async fn fetch_card_details_from_locker( @@ -2347,6 +2226,40 @@ pub async fn fetch_card_details_from_locker( Ok(api_card.into()) } +pub async fn fetch_network_token_details_from_locker( + state: &SessionState, + customer_id: &id_type::CustomerId, + merchant_id: &id_type::MerchantId, + network_token_locker_id: &str, + nt_data: api_models::payments::NetworkTokenWithNTIRef, +) -> RouterResult { + let mut token_data = + cards::get_card_from_locker(state, customer_id, &merchant_id, network_token_locker_id) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "failed to fetch network token information from the permanent locker", + )?; + let expiry = nt_data.token_exp_month.zip(nt_data.token_exp_year); + if let Some((exp_month, exp_year)) = expiry { + token_data.card_exp_month = exp_month; + token_data.card_exp_year = exp_year; + } + let network_token_data = domain::NetworkTokenData { + token_number: token_data.card_number, + token_cryptogram: None, + token_exp_month: token_data.card_exp_month, + token_exp_year: token_data.card_exp_year, + nick_name: token_data.nick_name.map(masking::Secret::new), + card_issuer: None, + card_network: None, + card_type: None, + card_issuing_country: None, + bank_code: None, + eci: None, + }; + Ok(network_token_data) +} pub async fn fetch_card_details_for_network_transaction_flow_from_locker( state: &SessionState, @@ -2354,15 +2267,11 @@ pub async fn fetch_card_details_for_network_transaction_flow_from_locker( merchant_id: &id_type::MerchantId, locker_id: &str, ) -> RouterResult { - let card_details_from_locker = cards::get_card_from_locker( - state, - customer_id, - &merchant_id, - locker_id, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to fetch card details from locker")?; + let card_details_from_locker = + cards::get_card_from_locker(state, customer_id, &merchant_id, locker_id) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to fetch card details from locker")?; let card_network = card_details_from_locker .card_brand @@ -2374,17 +2283,19 @@ pub async fn fetch_card_details_for_network_transaction_flow_from_locker( .ok() .flatten(); - let card_details_for_network_transaction_id = hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId { - card_number: card_details_from_locker.card_number, - card_exp_month: card_details_from_locker.card_exp_month, - card_exp_year: card_details_from_locker.card_exp_year, - card_issuer: None, - card_network, - card_type: None, - card_issuing_country: None, - bank_code: None, - nick_name: card_details_from_locker.nick_name.map(masking::Secret::new), - }; + let card_details_for_network_transaction_id = + hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId { + card_number: card_details_from_locker.card_number, + card_exp_month: card_details_from_locker.card_exp_month, + card_exp_year: card_details_from_locker.card_exp_year, + card_issuer: None, + card_network, + card_type: None, + card_issuing_country: None, + bank_code: None, + nick_name: card_details_from_locker.nick_name.map(masking::Secret::new), + card_holder_name: card_details_from_locker.name_on_card.clone(), + }; Ok( domain::PaymentMethodData::CardDetailsForNetworkTransactionId( @@ -2533,7 +2444,7 @@ pub async fn make_pm_data<'a, F: Clone, R, D>( // } else { // get_card() // } - + // // pd.get_vault_operation().and_then(|data| match data { // // payments::PaymentMethodDataAction::SaveCard(_) => None, // // payments::PaymentMethodDataAction::VaultData(vd) => Some(vd), @@ -2615,16 +2526,11 @@ where let stalled_payment_method_data = payment_data.get_vault_operation(); // valut data : card data, token data(opt, opt) // vault data : Card(card), Networktoken(NT), CARD and Network (token) - - - let vd = stalled_payment_method_data - .and_then(|data| match data { - payments::PaymentMethodDataAction::SaveCard(_) => None, - payments::PaymentMethodDataAction::VaultDataVariant(vd) => Some(vd), - }); - - + let vd = stalled_payment_method_data.and_then(|data| match data { + payments::PaymentMethodDataAction::SaveCard(_) => None, + payments::PaymentMethodDataAction::VaultDataVariant(vd) => Some(vd), + }); let pm_data = Box::pin(payment_methods::retrieve_payment_method_with_token( state, @@ -2649,7 +2555,7 @@ where // match payment_method_data { // domain::PaymentMethodData::Card(card) => { // payment_data.set_vault_operation( - // payments::PaymentMethodDataAction::VaultData(payments::VaultData { + // payments::PaymentMethodDataAction::VaultDataVariant(payments::VaultData { // card_data: Some(card.clone()), // network_token_data: vd.network_token_data, // }), @@ -2666,6 +2572,55 @@ where // _ => {} // } // }; + + if let Some(ref payment_method_data) = payment_method_details.payment_method_data { + let updated_vault_operation = + match (stalled_payment_method_data, payment_method_data) { + (None, domain::PaymentMethodData::Card(card)) => { + Some(payments::PaymentMethodDataAction::VaultDataVariant( + payments::VaultDataEnum::CardVaultData(card.clone()), + )) + } + (None, domain::PaymentMethodData::NetworkToken(nt_data)) => { + Some(payments::PaymentMethodDataAction::VaultDataVariant( + payments::VaultDataEnum::NetworkTokenVaultData(nt_data.clone()), + )) + } + ( + Some(payments::PaymentMethodDataAction::VaultDataVariant(vault_enum)), + payment_method, + ) => match (vault_enum, payment_method) { + ( + payments::VaultDataEnum::CardVaultData(card), + domain::PaymentMethodData::NetworkToken(nt_data), + ) => Some(payments::PaymentMethodDataAction::VaultDataVariant( + payments::VaultDataEnum::CardAndNetworkToken(payments::VaultData { + card_data: card.clone(), + network_token_data: nt_data.clone(), + }), + )), + ( + payments::VaultDataEnum::NetworkTokenVaultData(nt_data), + domain::PaymentMethodData::Card(card), + ) => Some(payments::PaymentMethodDataAction::VaultDataVariant( + payments::VaultDataEnum::CardAndNetworkToken(payments::VaultData { + card_data: card.clone(), + network_token_data: nt_data.clone(), + }), + )), + (payments::VaultDataEnum::CardAndNetworkToken(_), _) => None, + _ => Some(payments::PaymentMethodDataAction::VaultDataVariant( + vault_enum.clone(), + )), + }, + _ => None, + }; + + if let Some(vault_operation) = updated_vault_operation { + payment_data.set_vault_operation(vault_operation); + } + }; + Ok::<_, error_stack::Report>( if let Some(payment_method_data) = payment_method_details.payment_method_data { payment_data.payment_attempt.payment_method = @@ -5972,7 +5927,6 @@ pub async fn get_payment_method_details_from_payment_token( payment_intent: &PaymentIntent, key_store: &domain::MerchantKeyStore, storage_scheme: enums::MerchantStorageScheme, - business_profile: &domain::Profile, ) -> RouterResult> { let hyperswitch_token = if let Some(token) = payment_attempt.payment_token.clone() { let redis_conn = state @@ -6047,29 +6001,31 @@ pub async fn get_payment_method_details_from_payment_token( .await } - storage::PaymentTokenData::Permanent(card_token) => retrieve_card_with_permanent_token_for_external_authentication( - state, - &card_token.token, - payment_intent, - None, - key_store, - storage_scheme, - payment_attempt.connector.clone(), - ) - .await - .map(|card| Some((card, enums::PaymentMethod::Card))), + storage::PaymentTokenData::Permanent(card_token) => { + retrieve_card_with_permanent_token_for_external_authentication( + state, + &card_token.token, + payment_intent, + None, + key_store, + storage_scheme, + ) + .await + .map(|card| Some((card, enums::PaymentMethod::Card))) + } - storage::PaymentTokenData::PermanentCard(card_token) => retrieve_card_with_permanent_token_for_external_authentication( - state, - &card_token.token, - payment_intent, - None, - key_store, - storage_scheme, - payment_attempt.connector.clone(), - ) - .await - .map(|card| Some((card, enums::PaymentMethod::Card))), + storage::PaymentTokenData::PermanentCard(card_token) => { + retrieve_card_with_permanent_token_for_external_authentication( + state, + &card_token.token, + payment_intent, + None, + key_store, + storage_scheme, + ) + .await + .map(|card| Some((card, enums::PaymentMethod::Card))) + } storage::PaymentTokenData::AuthBankDebit(auth_token) => { retrieve_payment_method_from_auth_service( From 32402d6e368dc01ece46ba4ca2332b15c58d4d3d Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:17:22 +0000 Subject: [PATCH 05/11] chore: run formatter --- crates/diesel_models/src/business_profile.rs | 3 +- .../src/business_profile.rs | 6 +- crates/router/src/core/payment_methods.rs | 68 +++++++++---------- crates/router/src/core/payments.rs | 45 ++++++------ crates/router/src/core/payments/helpers.rs | 61 +++++++++-------- .../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 +- .../core/payments/operations/payment_start.rs | 1 - .../payments/operations/payment_status.rs | 2 +- .../payments/operations/payment_update.rs | 2 +- .../payments_incremental_authorization.rs | 2 +- .../payments/operations/tax_calculation.rs | 2 +- crates/router/src/core/payments/retry.rs | 16 ++--- .../router/src/core/payments/transformers.rs | 3 +- 16 files changed, 113 insertions(+), 106 deletions(-) diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs index 749c8a59dc6d..54bb26b87baf 100644 --- a/crates/diesel_models/src/business_profile.rs +++ b/crates/diesel_models/src/business_profile.rs @@ -254,7 +254,8 @@ impl ProfileUpdateInternal { .unwrap_or(source.is_click_to_pay_enabled), authentication_product_ids: authentication_product_ids .or(source.authentication_product_ids), - is_clear_pan_retries_enabled: is_clear_pan_retries_enabled.or(source.is_clear_pan_retries_enabled), + is_clear_pan_retries_enabled: is_clear_pan_retries_enabled + .or(source.is_clear_pan_retries_enabled), } } } diff --git a/crates/hyperswitch_domain_models/src/business_profile.rs b/crates/hyperswitch_domain_models/src/business_profile.rs index 8b698cd14a37..090a7eb352e9 100644 --- a/crates/hyperswitch_domain_models/src/business_profile.rs +++ b/crates/hyperswitch_domain_models/src/business_profile.rs @@ -60,7 +60,7 @@ pub struct Profile { pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, - pub is_clear_pan_retries_enabled: bool, + pub is_clear_pan_retries_enabled: bool, } #[cfg(feature = "v1")] @@ -103,7 +103,7 @@ pub struct ProfileSetter { pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: bool, pub authentication_product_ids: Option, - pub is_clear_pan_retries_enabled: bool, + pub is_clear_pan_retries_enabled: bool, } #[cfg(feature = "v1")] @@ -205,7 +205,7 @@ pub struct ProfileGeneralUpdate { pub max_auto_retries_enabled: Option, pub is_click_to_pay_enabled: Option, pub authentication_product_ids: Option, - pub is_clear_pan_retries_enabled: Option, + pub is_clear_pan_retries_enabled: Option, } #[cfg(feature = "v1")] diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index b8b21f308562..468fb6a8f17b 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -580,40 +580,40 @@ pub async fn retrieve_payment_method_with_token( } storage::PaymentTokenData::Permanent(card_token) => { - payment_helpers::retrieve_payment_method_data_with_permanent_token( - state, - card_token.locker_id.as_ref().unwrap_or(&card_token.token), - card_token - .payment_method_id - .as_ref() - .unwrap_or(&card_token.token), - payment_intent, - card_token_data, - merchant_key_store, - storage_scheme, - mandate_id, - payment_method_info, - business_profile, - payment_attempt.connector.clone(), - should_retry_with_pan, - vault_data, - ) - .await - .map(|card| Some((card, enums::PaymentMethod::Card)))? - .map( - |(payment_method_data, payment_method)| storage::PaymentMethodDataWithId { - payment_method_data: Some(payment_method_data), - payment_method: Some(payment_method), - payment_method_id: Some( - card_token - .payment_method_id - .as_ref() - .unwrap_or(&card_token.token) - .to_string(), - ), - }, - ) - .unwrap_or_default() + payment_helpers::retrieve_payment_method_data_with_permanent_token( + state, + card_token.locker_id.as_ref().unwrap_or(&card_token.token), + card_token + .payment_method_id + .as_ref() + .unwrap_or(&card_token.token), + payment_intent, + card_token_data, + merchant_key_store, + storage_scheme, + mandate_id, + payment_method_info, + business_profile, + payment_attempt.connector.clone(), + should_retry_with_pan, + vault_data, + ) + .await + .map(|card| Some((card, enums::PaymentMethod::Card)))? + .map( + |(payment_method_data, payment_method)| storage::PaymentMethodDataWithId { + payment_method_data: Some(payment_method_data), + payment_method: Some(payment_method), + payment_method_id: Some( + card_token + .payment_method_id + .as_ref() + .unwrap_or(&card_token.token) + .to_string(), + ), + }, + ) + .unwrap_or_default() } storage::PaymentTokenData::PermanentCard(card_token) => { diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index fd336523c7c1..4822dbe34ed3 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -577,7 +577,7 @@ where None, &business_profile, false, - false, + false, ) .await?; @@ -2471,7 +2471,7 @@ where key_store, customer, business_profile, - should_retry_with_pan + should_retry_with_pan, ) .await?; *payment_data = pd; @@ -4123,7 +4123,7 @@ pub async fn get_connector_tokenization_action_when_confirm_true( merchant_key_store: &domain::MerchantKeyStore, customer: &Option, business_profile: &domain::Profile, - should_retry_with_pan: bool, + should_retry_with_pan: bool, ) -> RouterResult<(D, TokenizationAction)> where F: Send + Clone, @@ -4368,44 +4368,50 @@ where } #[derive(Clone, serde::Serialize, Debug)] -pub enum PaymentMethodDataAction{ +pub enum PaymentMethodDataAction { SaveCard(hyperswitch_domain_models::payment_method_data::Card), - VaultDataVariant(VaultDataEnum) + VaultDataVariant(VaultDataEnum), } #[derive(Clone, serde::Serialize, Debug)] -pub enum VaultDataEnum{ +pub enum VaultDataEnum { CardVaultData(hyperswitch_domain_models::payment_method_data::Card), NetworkTokenVaultData(hyperswitch_domain_models::payment_method_data::NetworkTokenData), - CardAndNetworkToken(VaultData) + CardAndNetworkToken(VaultData), } - #[derive(Default, 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, } -impl VaultDataEnum{ - pub fn get_card_vault_data(&self) -> Option{ - match self{ +impl VaultDataEnum { + pub fn get_card_vault_data( + &self, + ) -> Option { + match self { VaultDataEnum::CardVaultData(card_data) => Some(card_data.clone()), - VaultDataEnum::NetworkTokenVaultData(_network_token_data) => None, - VaultDataEnum::CardAndNetworkToken(vault_data) => Some(vault_data.card_data.clone()) + VaultDataEnum::NetworkTokenVaultData(_network_token_data) => None, + VaultDataEnum::CardAndNetworkToken(vault_data) => Some(vault_data.card_data.clone()), } } - pub fn get_network_token_data(&self) -> Option{ - match self{ + pub fn get_network_token_data( + &self, + ) -> Option { + match self { VaultDataEnum::CardVaultData(_card_data) => None, - VaultDataEnum::NetworkTokenVaultData(network_token_data) => Some(network_token_data.clone()), - VaultDataEnum::CardAndNetworkToken(vault_data) => Some(vault_data.network_token_data.clone()) + VaultDataEnum::NetworkTokenVaultData(network_token_data) => { + Some(network_token_data.clone()) + } + VaultDataEnum::CardAndNetworkToken(vault_data) => { + Some(vault_data.network_token_data.clone()) + } } } } - #[derive(Clone, serde::Serialize, Debug)] pub struct TaxData { pub shipping_details: hyperswitch_domain_models::address::Address, @@ -6513,7 +6519,6 @@ pub async fn payment_external_authentication( &payment_intent, &key_store, storage_scheme, - ) .await? .ok_or(errors::ApiErrorResponse::InternalServerError) @@ -7052,7 +7057,7 @@ impl OperationSessionGetters for PaymentData { self.payment_attempt.capture_method } - fn get_vault_operation(&self) -> Option<&PaymentMethodDataAction>{ + fn get_vault_operation(&self) -> Option<&PaymentMethodDataAction> { self.vault_operation.as_ref() } diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index d283eee40d09..d3aa01bad258 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -2071,40 +2071,42 @@ pub async fn retrieve_payment_method_data_with_permanent_token( Err(err) => { logger::info!("Failed to fetch network token data from tokenization service {err:?}"); logger::info!("Falling back to fetch card details from locker"); - Ok(domain::PaymentMethodData::Card(vault_data - .and_then(|vd| vd.get_card_vault_data()) - .map(Ok) - .async_unwrap_or_else(|| async { - fetch_card_details_from_locker( - state, - customer_id, - &payment_intent.merchant_id, - locker_id, - card_token_data, - ) - .await - }) - .await? + Ok(domain::PaymentMethodData::Card( + vault_data + .and_then(|vd| vd.get_card_vault_data()) + .map(Ok) + .async_unwrap_or_else(|| async { + fetch_card_details_from_locker( + state, + customer_id, + &payment_intent.merchant_id, + locker_id, + card_token_data, + ) + .await + }) + .await?, )) } } } else { logger::info!("Either the connector is not in the NT supported list or token requestor reference ID is absent"); logger::info!("Falling back to fetch card details from locker"); - Ok(domain::PaymentMethodData::Card(vault_data - .and_then(|vd| vd.get_card_vault_data()) - .map(Ok) - .async_unwrap_or_else(|| async { - fetch_card_details_from_locker( - state, - customer_id, - &payment_intent.merchant_id, - locker_id, - card_token_data, - ) - .await - }) - .await? + Ok(domain::PaymentMethodData::Card( + vault_data + .and_then(|vd| vd.get_card_vault_data()) + .map(Ok) + .async_unwrap_or_else(|| async { + fetch_card_details_from_locker( + state, + customer_id, + &payment_intent.merchant_id, + locker_id, + card_token_data, + ) + .await + }) + .await?, )) } } @@ -2472,9 +2474,8 @@ pub async fn make_pm_data<'a, F: Clone, R, D>( where F: Clone, { - use crate::core::payments::OperationSessionGetters; - use super::OperationSessionSetters; + use crate::core::payments::OperationSessionGetters; let request = payment_data.payment_method_data.clone(); diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs index ef1aca0894ed..82da4cead21b 100644 --- a/crates/router/src/core/payments/operations/payment_approve.rs +++ b/crates/router/src/core/payments/operations/payment_approve.rs @@ -195,7 +195,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 40527e66aa5b..2fa132ae9430 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -206,7 +206,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 631069b1f854..767325f225ae 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -255,7 +255,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 491b7ec6de92..64d7240c6764 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 @@ -166,7 +166,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_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index 681cef9b88db..921fa65febde 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -330,7 +330,6 @@ where storage_scheme, business_profile, should_retry_with_pan, - )) .await } else { diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index 9fc7d5d6415b..b68455b7ed96 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 4397791dc530..78b7bacad5dd 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -492,7 +492,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 cf50570d43bb..0aa52c3b7409 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -172,7 +172,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 f77eeb795f64..2955f506f1a1 100644 --- a/crates/router/src/core/payments/operations/tax_calculation.rs +++ b/crates/router/src/core/payments/operations/tax_calculation.rs @@ -180,7 +180,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/retry.rs b/crates/router/src/core/payments/retry.rs index dd01b6439e42..ebc4b41afd36 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -148,12 +148,12 @@ where .map(|gsm| gsm.clear_pan_possible) .unwrap_or(false); - let should_retry_with_pan = if clear_pan_possible && business_profile.is_clear_pan_retries_enabled{ - true - } else { - false - }; - + let should_retry_with_pan = + if clear_pan_possible && business_profile.is_clear_pan_retries_enabled { + true + } else { + false + }; router_data = do_retry( &state.clone(), @@ -171,7 +171,7 @@ where false, frm_suggestion, business_profile, - should_retry_with_pan + should_retry_with_pan, ) .await?; @@ -367,7 +367,7 @@ where frm_suggestion, business_profile, true, - should_retry_with_pan + should_retry_with_pan, ) .await?; diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 79a893d8a4ff..e13d4935b8a0 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -2578,7 +2578,8 @@ 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 { From fccb0ec0fcfaa01879f186ec20b24f6c39c4904d Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Thu, 19 Dec 2024 21:20:20 +0000 Subject: [PATCH 06/11] docs(openapi): re-generate OpenAPI specification --- api-reference-v2/openapi_spec.json | 19 ++++++++++++++++-- api-reference/openapi_spec.json | 31 +++++++++++++++++++++++++++--- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 58a81caeed3a..b9acb5577fca 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -9510,7 +9510,8 @@ "message", "status", "decision", - "step_up_possible" + "step_up_possible", + "clear_pan_possible" ], "properties": { "connector": { @@ -9565,6 +9566,10 @@ } ], "nullable": true + }, + "clear_pan_possible": { + "type": "boolean", + "description": "indicates if retry with pan is possible" } } }, @@ -9649,7 +9654,8 @@ "message", "status", "decision", - "step_up_possible" + "step_up_possible", + "clear_pan_possible" ], "properties": { "connector": { @@ -9706,6 +9712,10 @@ } ], "nullable": true + }, + "clear_pan_possible": { + "type": "boolean", + "description": "indicates if retry with pan is possible" } } }, @@ -9810,6 +9820,11 @@ } ], "nullable": true + }, + "clear_pan_possible": { + "type": "boolean", + "description": "indicates if retry with pan is possible", + "nullable": true } } }, diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 33dd5d87a473..ecc1201ff23d 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -12001,7 +12001,8 @@ "message", "status", "decision", - "step_up_possible" + "step_up_possible", + "clear_pan_possible" ], "properties": { "connector": { @@ -12056,6 +12057,10 @@ } ], "nullable": true + }, + "clear_pan_possible": { + "type": "boolean", + "description": "indicates if retry with pan is possible" } } }, @@ -12140,7 +12145,8 @@ "message", "status", "decision", - "step_up_possible" + "step_up_possible", + "clear_pan_possible" ], "properties": { "connector": { @@ -12197,6 +12203,10 @@ } ], "nullable": true + }, + "clear_pan_possible": { + "type": "boolean", + "description": "indicates if retry with pan is possible" } } }, @@ -12301,6 +12311,11 @@ } ], "nullable": true + }, + "clear_pan_possible": { + "type": "boolean", + "description": "indicates if retry with pan is possible", + "nullable": true } } }, @@ -22128,6 +22143,11 @@ "type": "object", "description": "Product authentication ids", "nullable": true + }, + "is_clear_pan_retries_enabled": { + "type": "boolean", + "description": "Indicates if clear pan retries is enabled or not.", + "nullable": true } }, "additionalProperties": false @@ -22161,7 +22181,8 @@ "is_tax_connector_enabled", "is_network_tokenization_enabled", "is_auto_retries_enabled", - "is_click_to_pay_enabled" + "is_click_to_pay_enabled", + "is_clear_pan_retries_enabled" ], "properties": { "merchant_id": { @@ -22369,6 +22390,10 @@ "type": "object", "description": "Product authentication ids", "nullable": true + }, + "is_clear_pan_retries_enabled": { + "type": "boolean", + "description": "Indicates if clear pan retries is enabled or not." } } }, From c6fd3207bd2dee767460f6d1f3bab345793ba8c9 Mon Sep 17 00:00:00 2001 From: Prasunna Soppa Date: Sat, 21 Dec 2024 22:10:46 +0530 Subject: [PATCH 07/11] code refactoring --- crates/router/src/core/payments/helpers.rs | 17 +++++++------- crates/router/src/core/payments/retry.rs | 26 +++++++++++----------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index d3aa01bad258..13e16c448c19 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1959,11 +1959,12 @@ pub fn determine_standard_vault_action( } }, None => { + //save card flow if connector .map(|conn| network_tokenization_supported_connectors.contains(&conn)) .unwrap_or(false) { - VaultFetchAction::FetchNetworkTokenDataFromTokenizationService + VaultFetchAction::FetchNetworkTokenDataFromTokenizationService //return nt ref } else { VaultFetchAction::FetchCardDetailsFromLocker } @@ -1986,7 +1987,7 @@ pub async fn retrieve_payment_method_data_with_permanent_token( _merchant_key_store: &domain::MerchantKeyStore, _storage_scheme: enums::MerchantStorageScheme, mandate_id: Option, - payment_method_info: Option, + payment_method_info: Option, //make it mandatory business_profile: &domain::Profile, connector: Option, should_retry_with_pan: bool, @@ -2016,7 +2017,7 @@ pub async fn retrieve_payment_method_data_with_permanent_token( }) .transpose()?; - let vault_fetch_action = decide_vault_fetch_action( + let vault_fetch_action = decide_vault_fetch_action( //change var name business_profile.is_network_tokenization_enabled, mandate_id, connector_variant, @@ -2090,8 +2091,7 @@ pub async fn retrieve_payment_method_data_with_permanent_token( } } } else { - logger::info!("Either the connector is not in the NT supported list or token requestor reference ID is absent"); - logger::info!("Falling back to fetch card details from locker"); + logger::info!("Falling back to fetch card details from locker"); //re write the error message Ok(domain::PaymentMethodData::Card( vault_data .and_then(|vd| vd.get_card_vault_data()) @@ -2524,9 +2524,7 @@ where // TODO: Handle case where payment method and token both are present in request properly. let (payment_method, pm_id) = match (&request, payment_data.token_data.as_ref()) { (_, Some(hyperswitch_token)) => { - let stalled_payment_method_data = payment_data.get_vault_operation(); - // valut data : card data, token data(opt, opt) - // vault data : Card(card), Networktoken(NT), CARD and Network (token) + let stalled_payment_method_data = payment_data.get_vault_operation(); //change the variable name let vd = stalled_payment_method_data.and_then(|data| match data { payments::PaymentMethodDataAction::SaveCard(_) => None, @@ -2609,7 +2607,8 @@ where network_token_data: nt_data.clone(), }), )), - (payments::VaultDataEnum::CardAndNetworkToken(_), _) => None, + (payments::VaultDataEnum::CardAndNetworkToken(_), _) => None, //change the set logic if none do not update + _ => Some(payments::PaymentMethodDataAction::VaultDataVariant( vault_enum.clone(), )), diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index ebc4b41afd36..4ae5e86d20b5 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -98,7 +98,7 @@ where router_data = do_retry( &state.clone(), req_state.clone(), - original_connector_data, + original_connector_data.clone(), operation, customer, merchant_account, @@ -116,6 +116,7 @@ where } // Step up is not applicable so proceed with auto retries flow else { + let original_connector_data = original_connector_data.clone(); loop { // Use initial_gsm for first time alone let gsm = match initial_gsm.as_ref() { @@ -141,19 +142,18 @@ where break; } - let connector = super::get_connector_data(&mut connectors)?; - - let clear_pan_possible = initial_gsm - .clone() + let is_network_token = matches!(payment_data.get_payment_method_data(), Some(domain::PaymentMethodData::NetworkToken(_))); + let should_retry_with_pan = is_network_token && initial_gsm + .as_ref() .map(|gsm| gsm.clear_pan_possible) - .unwrap_or(false); - - let should_retry_with_pan = - if clear_pan_possible && business_profile.is_clear_pan_retries_enabled { - true - } else { - false - }; + .unwrap_or(false) + && business_profile.is_clear_pan_retries_enabled; + + let connector = if should_retry_with_pan { + original_connector_data.clone() + } else { + super::get_connector_data(&mut connectors)? + }; router_data = do_retry( &state.clone(), From 7b879e82de6889c39987fbd6215a76d857c60c9b Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Sat, 21 Dec 2024 16:41:44 +0000 Subject: [PATCH 08/11] chore: run formatter --- crates/router/src/core/payments/helpers.rs | 8 +++++--- crates/router/src/core/payments/retry.rs | 14 +++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 13e16c448c19..1de56be7331b 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1964,7 +1964,8 @@ pub fn determine_standard_vault_action( .map(|conn| network_tokenization_supported_connectors.contains(&conn)) .unwrap_or(false) { - VaultFetchAction::FetchNetworkTokenDataFromTokenizationService //return nt ref + VaultFetchAction::FetchNetworkTokenDataFromTokenizationService + //return nt ref } else { VaultFetchAction::FetchCardDetailsFromLocker } @@ -2017,7 +2018,8 @@ pub async fn retrieve_payment_method_data_with_permanent_token( }) .transpose()?; - let vault_fetch_action = decide_vault_fetch_action( //change var name + let vault_fetch_action = decide_vault_fetch_action( + //change var name business_profile.is_network_tokenization_enabled, mandate_id, connector_variant, @@ -2608,7 +2610,7 @@ where }), )), (payments::VaultDataEnum::CardAndNetworkToken(_), _) => None, //change the set logic if none do not update - + _ => Some(payments::PaymentMethodDataAction::VaultDataVariant( vault_enum.clone(), )), diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index 4ae5e86d20b5..2d505ca10a49 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -142,11 +142,15 @@ where break; } - let is_network_token = matches!(payment_data.get_payment_method_data(), Some(domain::PaymentMethodData::NetworkToken(_))); - let should_retry_with_pan = is_network_token && initial_gsm - .as_ref() - .map(|gsm| gsm.clear_pan_possible) - .unwrap_or(false) + let is_network_token = matches!( + payment_data.get_payment_method_data(), + Some(domain::PaymentMethodData::NetworkToken(_)) + ); + let should_retry_with_pan = is_network_token + && initial_gsm + .as_ref() + .map(|gsm| gsm.clear_pan_possible) + .unwrap_or(false) && business_profile.is_clear_pan_retries_enabled; let connector = if should_retry_with_pan { From 628186d9b6b8906dd74ecd932df401d99bf52e3a Mon Sep 17 00:00:00 2001 From: Prasunna Soppa Date: Tue, 24 Dec 2024 00:21:39 +0530 Subject: [PATCH 09/11] code refactoring --- crates/api_models/src/payments.rs | 7 - crates/router/build.rs | 2 +- crates/router/src/core/payment_methods.rs | 8 +- crates/router/src/core/payments.rs | 24 +- crates/router/src/core/payments/helpers.rs | 311 +++++++++------------ 5 files changed, 146 insertions(+), 206 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 2ccb8aa35a80..0381e347f4f1 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -1470,13 +1470,6 @@ impl MandateIds { Some(MandateReferenceId::NetworkMandateId(_)) ) } - - pub fn is_network_token_with_nti_flow(&self) -> bool { - matches!( - self.mandate_reference_id, - Some(MandateReferenceId::NetworkTokenWithNTI(_)) - ) - } } #[derive(Eq, PartialEq, Debug, serde::Deserialize, serde::Serialize, Clone)] diff --git a/crates/router/build.rs b/crates/router/build.rs index b33c168833d2..3985a924fcaf 100644 --- a/crates/router/build.rs +++ b/crates/router/build.rs @@ -2,7 +2,7 @@ fn main() { // Set thread stack size to 8 MiB for debug builds // Reference: https://doc.rust-lang.org/std/thread/#stack-size #[cfg(debug_assertions)] - println!("cargo:rustc-env=RUST_MIN_STACK=8388608"); // 8 * 1024 * 1024 = 8 MiB + println!("cargo:rustc-env=RUST_MIN_STACK=10388608"); // 8 * 1024 * 1024 = 8 MiB #[cfg(feature = "vergen")] router_env::vergen::generate_cargo_instructions(); diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index 468fb6a8f17b..0b8812990d2c 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -24,7 +24,7 @@ use api_models::payment_methods; #[cfg(feature = "payouts")] pub use api_models::{enums::PayoutConnectors, payouts as payout_types}; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -use common_utils::ext_traits::Encode; +use common_utils::ext_traits::{Encode, OptionExt,}; use common_utils::{consts::DEFAULT_LOCALE, id_type}; #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] use common_utils::{ @@ -536,7 +536,7 @@ pub async fn retrieve_payment_method_with_token( payment_method_info: Option, business_profile: &domain::Profile, should_retry_with_pan: bool, - vault_data: Option<&payments::VaultDataEnum>, + vault_data: Option<&payments::VaultData>, ) -> RouterResult { let token = match token_data { storage::PaymentTokenData::TemporaryGeneric(generic_token) => { @@ -592,7 +592,7 @@ pub async fn retrieve_payment_method_with_token( merchant_key_store, storage_scheme, mandate_id, - payment_method_info, + payment_method_info.get_required_value("PaymentMethod").change_context(errors::ApiErrorResponse::InternalServerError).attach_printable("PaymentMethod not found")?, business_profile, payment_attempt.connector.clone(), should_retry_with_pan, @@ -629,7 +629,7 @@ pub async fn retrieve_payment_method_with_token( merchant_key_store, storage_scheme, mandate_id, - payment_method_info, + payment_method_info.get_required_value("PaymentMethod").change_context(errors::ApiErrorResponse::InternalServerError).attach_printable("PaymentMethod not found")?, business_profile, payment_attempt.connector.clone(), should_retry_with_pan, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 4822dbe34ed3..6fb544516c2b 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -202,7 +202,6 @@ where None, &profile, false, - false, ) .await?; @@ -4369,31 +4368,30 @@ where #[derive(Clone, serde::Serialize, Debug)] pub enum PaymentMethodDataAction { - SaveCard(hyperswitch_domain_models::payment_method_data::Card), - VaultDataVariant(VaultDataEnum), + ExistingVaultData(VaultData), } #[derive(Clone, serde::Serialize, Debug)] -pub enum VaultDataEnum { +pub enum VaultData { CardVaultData(hyperswitch_domain_models::payment_method_data::Card), NetworkTokenVaultData(hyperswitch_domain_models::payment_method_data::NetworkTokenData), - CardAndNetworkToken(VaultData), + CardAndNetworkToken(Box), } #[derive(Default, Clone, serde::Serialize, Debug)] -pub struct VaultData { +pub struct CardAndNetworkTokenData { pub card_data: hyperswitch_domain_models::payment_method_data::Card, pub network_token_data: hyperswitch_domain_models::payment_method_data::NetworkTokenData, } -impl VaultDataEnum { +impl VaultData { pub fn get_card_vault_data( &self, ) -> Option { match self { - VaultDataEnum::CardVaultData(card_data) => Some(card_data.clone()), - VaultDataEnum::NetworkTokenVaultData(_network_token_data) => None, - VaultDataEnum::CardAndNetworkToken(vault_data) => Some(vault_data.card_data.clone()), + Self::CardVaultData(card_data) => Some(card_data.clone()), + Self::NetworkTokenVaultData(_network_token_data) => None, + Self::CardAndNetworkToken(vault_data) => Some(vault_data.card_data.clone()), } } @@ -4401,11 +4399,11 @@ impl VaultDataEnum { &self, ) -> Option { match self { - VaultDataEnum::CardVaultData(_card_data) => None, - VaultDataEnum::NetworkTokenVaultData(network_token_data) => { + Self::CardVaultData(_card_data) => None, + Self::NetworkTokenVaultData(network_token_data) => { Some(network_token_data.clone()) } - VaultDataEnum::CardAndNetworkToken(vault_data) => { + Self::CardAndNetworkToken(vault_data) => { Some(vault_data.network_token_data.clone()) } } diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 13e16c448c19..660a5e6c06ae 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -1901,17 +1901,18 @@ pub async fn retrieve_card_with_permanent_token( pub enum VaultFetchAction { FetchCardDetailsFromLocker, FetchCardDetailsForNetworkTransactionFlowFromLocker, - FetchNetworkTokenDataFromTokenizationService, + FetchNetworkTokenDataFromTokenizationService(String), FetchNetworkTokenDetailsFromLocker(api_models::payments::NetworkTokenWithNTIRef), NoFetchAction, } -pub fn decide_vault_fetch_action( +pub fn decide_payment_method_retrieval_action( is_network_tokenization_enabled: bool, mandate_id: Option, connector: Option, network_tokenization_supported_connectors: &std::collections::HashSet, should_retry_with_pan: bool, + network_token_requestor_ref_id: Option, ) -> VaultFetchAction { let normal_flow = || { determine_standard_vault_action( @@ -1919,13 +1920,13 @@ pub fn decide_vault_fetch_action( mandate_id, connector, network_tokenization_supported_connectors, + network_token_requestor_ref_id, ) }; - let action = should_retry_with_pan + should_retry_with_pan .then_some(VaultFetchAction::FetchCardDetailsFromLocker) - .unwrap_or_else(normal_flow); - action + .unwrap_or_else(normal_flow) } pub fn determine_standard_vault_action( @@ -1933,6 +1934,7 @@ pub fn determine_standard_vault_action( mandate_id: Option, connector: Option, network_tokenization_supported_connectors: &std::collections::HashSet, + network_token_requestor_ref_id: Option, ) -> VaultFetchAction { let is_network_transaction_id_flow = mandate_id .as_ref() @@ -1960,13 +1962,17 @@ pub fn determine_standard_vault_action( }, None => { //save card flow - if connector + let is_supported_connector = connector .map(|conn| network_tokenization_supported_connectors.contains(&conn)) - .unwrap_or(false) - { - VaultFetchAction::FetchNetworkTokenDataFromTokenizationService //return nt ref - } else { - VaultFetchAction::FetchCardDetailsFromLocker + .unwrap_or(false); + + match (is_supported_connector, network_token_requestor_ref_id) { + (true, Some(ref_id)) => { + VaultFetchAction::FetchNetworkTokenDataFromTokenizationService(ref_id) + } + (false, Some(_)) | (true, None) | (false, None) => { + VaultFetchAction::FetchCardDetailsFromLocker + } } } } @@ -1987,11 +1993,11 @@ pub async fn retrieve_payment_method_data_with_permanent_token( _merchant_key_store: &domain::MerchantKeyStore, _storage_scheme: enums::MerchantStorageScheme, mandate_id: Option, - payment_method_info: Option, //make it mandatory + payment_method_info: domain::PaymentMethod, business_profile: &domain::Profile, connector: Option, should_retry_with_pan: bool, - vault_data: Option<&payments::VaultDataEnum>, + vault_data: Option<&payments::VaultData>, ) -> RouterResult { let customer_id = payment_intent .customer_id @@ -2017,81 +2023,67 @@ pub async fn retrieve_payment_method_data_with_permanent_token( }) .transpose()?; - let vault_fetch_action = decide_vault_fetch_action( //change var name + let vault_fetch_action = decide_payment_method_retrieval_action( business_profile.is_network_tokenization_enabled, mandate_id, connector_variant, network_tokenization_supported_connectors, should_retry_with_pan, + payment_method_info + .network_token_requestor_reference_id + .clone(), ); - match payment_method_info { - Some(ref pm_data) => match vault_fetch_action { - VaultFetchAction::FetchCardDetailsFromLocker => { - let card_result = vault_data - .and_then(|vd| vd.get_card_vault_data()) - .map(Ok) - .async_unwrap_or_else(|| async { - fetch_card_details_from_locker( - state, - customer_id, - &payment_intent.merchant_id, - locker_id, - card_token_data, - ) - .await - }) - .await?; - - Ok(domain::PaymentMethodData::Card(card_result)) - } - VaultFetchAction::FetchCardDetailsForNetworkTransactionFlowFromLocker => { - fetch_card_details_for_network_transaction_flow_from_locker( - state, - customer_id, - &payment_intent.merchant_id, - locker_id, - ) - .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("failed to fetch card information from the permanent locker") - } - VaultFetchAction::FetchNetworkTokenDataFromTokenizationService => { - if let Some(token_ref) = pm_data.network_token_requestor_reference_id.clone() { - logger::info!("Fetching network token data from tokenization service"); - match network_tokenization::get_token_from_tokenization_service( - state, token_ref, pm_data, + match vault_fetch_action { + VaultFetchAction::FetchCardDetailsFromLocker => { + let card_result = vault_data + .and_then(|vd| vd.get_card_vault_data()) + .map(Ok) + .async_unwrap_or_else(|| async { + fetch_card_details_from_locker( + state, + customer_id, + &payment_intent.merchant_id, + locker_id, + card_token_data, ) .await - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable( - "failed to fetch network token data from tokenization service", - ) { - Ok(network_token_data) => { - Ok(domain::PaymentMethodData::NetworkToken(network_token_data)) - } - Err(err) => { - logger::info!("Failed to fetch network token data from tokenization service {err:?}"); - logger::info!("Falling back to fetch card details from locker"); - Ok(domain::PaymentMethodData::Card( - vault_data - .and_then(|vd| vd.get_card_vault_data()) - .map(Ok) - .async_unwrap_or_else(|| async { - fetch_card_details_from_locker( - state, - customer_id, - &payment_intent.merchant_id, - locker_id, - card_token_data, - ) - .await - }) - .await?, - )) - } - } - } else { - logger::info!("Falling back to fetch card details from locker"); //re write the error message + }) + .await?; + + Ok(domain::PaymentMethodData::Card(card_result)) + } + VaultFetchAction::FetchCardDetailsForNetworkTransactionFlowFromLocker => { + fetch_card_details_for_network_transaction_flow_from_locker( + state, + customer_id, + &payment_intent.merchant_id, + locker_id, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to fetch card information from the permanent locker") + } + VaultFetchAction::FetchNetworkTokenDataFromTokenizationService( + network_token_requestor_ref_id, + ) => { + logger::info!("Fetching network token data from tokenization service"); + match network_tokenization::get_token_from_tokenization_service( + state, + network_token_requestor_ref_id, + &payment_method_info, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("failed to fetch network token data from tokenization service") + { + Ok(network_token_data) => { + Ok(domain::PaymentMethodData::NetworkToken(network_token_data)) + } + Err(err) => { + logger::info!( + "Failed to fetch network token data from tokenization service {err:?}" + ); + logger::info!("Falling back to fetch card details from locker"); Ok(domain::PaymentMethodData::Card( vault_data .and_then(|vd| vd.get_card_vault_data()) @@ -2110,32 +2102,32 @@ pub async fn retrieve_payment_method_data_with_permanent_token( )) } } - VaultFetchAction::FetchNetworkTokenDetailsFromLocker(nt_data) => { - if let Some(network_token_locker_id) = pm_data.network_token_locker_id.as_ref() { - let network_token_data = vault_data - .and_then(|vd| vd.get_network_token_data()) - .map(Ok) - .async_unwrap_or_else(|| async { - fetch_network_token_details_from_locker( - state, - customer_id, - &payment_intent.merchant_id, - network_token_locker_id, - nt_data, - ) - .await - }) - .await?; - Ok(domain::PaymentMethodData::NetworkToken(network_token_data)) - } else { - Err(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Network token locker id is not present") - } + } + VaultFetchAction::FetchNetworkTokenDetailsFromLocker(nt_data) => { + if let Some(network_token_locker_id) = + payment_method_info.network_token_locker_id.as_ref() + { + let network_token_data = vault_data + .and_then(|vd| vd.get_network_token_data()) + .map(Ok) + .async_unwrap_or_else(|| async { + fetch_network_token_details_from_locker( + state, + customer_id, + &payment_intent.merchant_id, + network_token_locker_id, + nt_data, + ) + .await + }) + .await?; + Ok(domain::PaymentMethodData::NetworkToken(network_token_data)) + } else { + Err(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Network token locker id is not present") } - VaultFetchAction::NoFetchAction => Err(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Payment method data is not present"), - }, - None => Err(errors::ApiErrorResponse::InternalServerError) + } + VaultFetchAction::NoFetchAction => Err(errors::ApiErrorResponse::InternalServerError) .attach_printable("Payment method data is not present"), } } @@ -2236,7 +2228,7 @@ pub async fn fetch_network_token_details_from_locker( nt_data: api_models::payments::NetworkTokenWithNTIRef, ) -> RouterResult { let mut token_data = - cards::get_card_from_locker(state, customer_id, &merchant_id, network_token_locker_id) + cards::get_card_from_locker(state, customer_id, merchant_id, network_token_locker_id) .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable( @@ -2270,7 +2262,7 @@ pub async fn fetch_card_details_for_network_transaction_flow_from_locker( locker_id: &str, ) -> RouterResult { let card_details_from_locker = - cards::get_card_from_locker(state, customer_id, &merchant_id, locker_id) + cards::get_card_from_locker(state, customer_id, merchant_id, locker_id) .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("failed to fetch card details from locker")?; @@ -2433,30 +2425,11 @@ pub async fn make_pm_data<'a, F: Clone, R, D>( todo!() } -// fn my_function(pd: PaymentData, profile: &domain::Profile) { -// let is_network_tokenization_enabled = profile.is_network_tokenization_enabled; -// let is_network_transaction_id_flow = pd -// .mandate_id -// .as_ref() -// .map(|mandate_ids| mandate_ids.is_network_transaction_id_flow()) -// .unwrap_or(false); - -// if is_network_tokenization_enabled && is_network_transaction_id_flow { -// get_network() -// } else { -// get_card() -// } - -// // pd.get_vault_operation().and_then(|data| match data { -// // payments::PaymentMethodDataAction::SaveCard(_) => None, -// // payments::PaymentMethodDataAction::VaultData(vd) => Some(vd), -// // }).or(get_card_from_locker); -// } - #[cfg(all( any(feature = "v1", feature = "v2"), not(feature = "payment_methods_v2") ))] +#[allow(clippy::too_many_arguments)] pub async fn make_pm_data<'a, F: Clone, R, D>( operation: BoxedOperation<'a, F, R, D>, state: &'a SessionState, @@ -2470,10 +2443,7 @@ pub async fn make_pm_data<'a, F: Clone, R, D>( BoxedOperation<'a, F, R, D>, Option, Option, -)> -where - F: Clone, -{ +)>{ use super::OperationSessionSetters; use crate::core::payments::OperationSessionGetters; @@ -2524,11 +2494,10 @@ where // TODO: Handle case where payment method and token both are present in request properly. let (payment_method, pm_id) = match (&request, payment_data.token_data.as_ref()) { (_, Some(hyperswitch_token)) => { - let stalled_payment_method_data = payment_data.get_vault_operation(); //change the variable name + let current_payment_method_data = payment_data.get_vault_operation(); - let vd = stalled_payment_method_data.and_then(|data| match data { - payments::PaymentMethodDataAction::SaveCard(_) => None, - payments::PaymentMethodDataAction::VaultDataVariant(vd) => Some(vd), + let vd = current_payment_method_data.map(|data| match data { + payments::PaymentMethodDataAction::ExistingVaultData(vd) => vd, }); let pm_data = Box::pin(payment_methods::retrieve_payment_method_with_token( @@ -2550,68 +2519,48 @@ where let payment_method_details = pm_data.attach_printable("in 'make_pm_data'")?; - // if let Some(ref payment_method_data) = payment_method_details.payment_method_data { - // match payment_method_data { - // domain::PaymentMethodData::Card(card) => { - // payment_data.set_vault_operation( - // payments::PaymentMethodDataAction::VaultDataVariant(payments::VaultData { - // card_data: Some(card.clone()), - // network_token_data: vd.network_token_data, - // }), - // ); - // } - // domain::PaymentMethodData::NetworkToken(nt_data) => { - // payment_data.set_vault_operation( - // payments::PaymentMethodDataAction::VaultData(payments::VaultData { - // card_data: vd.card_data, - // network_token_data: Some(nt_data.clone()), - // }), - // ); - // } - // _ => {} - // } - // }; - if let Some(ref payment_method_data) = payment_method_details.payment_method_data { let updated_vault_operation = - match (stalled_payment_method_data, payment_method_data) { + match (current_payment_method_data, payment_method_data) { (None, domain::PaymentMethodData::Card(card)) => { - Some(payments::PaymentMethodDataAction::VaultDataVariant( - payments::VaultDataEnum::CardVaultData(card.clone()), + Some(payments::PaymentMethodDataAction::ExistingVaultData( + payments::VaultData::CardVaultData(card.clone()), )) } (None, domain::PaymentMethodData::NetworkToken(nt_data)) => { - Some(payments::PaymentMethodDataAction::VaultDataVariant( - payments::VaultDataEnum::NetworkTokenVaultData(nt_data.clone()), + Some(payments::PaymentMethodDataAction::ExistingVaultData( + payments::VaultData::NetworkTokenVaultData(nt_data.clone()), )) } ( - Some(payments::PaymentMethodDataAction::VaultDataVariant(vault_enum)), + Some(payments::PaymentMethodDataAction::ExistingVaultData(vault_data)), payment_method, - ) => match (vault_enum, payment_method) { + ) => match (vault_data, payment_method) { ( - payments::VaultDataEnum::CardVaultData(card), + payments::VaultData::CardVaultData(card), domain::PaymentMethodData::NetworkToken(nt_data), - ) => Some(payments::PaymentMethodDataAction::VaultDataVariant( - payments::VaultDataEnum::CardAndNetworkToken(payments::VaultData { - card_data: card.clone(), - network_token_data: nt_data.clone(), - }), + ) => Some(payments::PaymentMethodDataAction::ExistingVaultData( + payments::VaultData::CardAndNetworkToken( + Box::new(payments::CardAndNetworkTokenData { + card_data: card.clone(), + network_token_data: nt_data.clone(), + }) + ), )), ( - payments::VaultDataEnum::NetworkTokenVaultData(nt_data), + payments::VaultData::NetworkTokenVaultData(nt_data), domain::PaymentMethodData::Card(card), - ) => Some(payments::PaymentMethodDataAction::VaultDataVariant( - payments::VaultDataEnum::CardAndNetworkToken(payments::VaultData { - card_data: card.clone(), - network_token_data: nt_data.clone(), - }), - )), - (payments::VaultDataEnum::CardAndNetworkToken(_), _) => None, //change the set logic if none do not update - - _ => Some(payments::PaymentMethodDataAction::VaultDataVariant( - vault_enum.clone(), + ) => Some(payments::PaymentMethodDataAction::ExistingVaultData( + payments::VaultData::CardAndNetworkToken( + Box::new(payments::CardAndNetworkTokenData { + card_data: card.clone(), + network_token_data: nt_data.clone(), + }) + ), )), + _ => Some(payments::PaymentMethodDataAction::ExistingVaultData( + vault_data.clone(), + )) }, _ => None, }; From 9c1f7a597e42627000009fe1dcb5db115b2f8e01 Mon Sep 17 00:00:00 2001 From: Prasunna Soppa Date: Tue, 24 Dec 2024 00:26:25 +0530 Subject: [PATCH 10/11] update schema.rs --- crates/diesel_models/src/schema.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 5ecc97107e3c..927eea21c75c 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -220,22 +220,6 @@ diesel::table! { } } -diesel::table! { - use diesel::sql_types::*; - use crate::enums::diesel_exports::*; - - callback_mapper (id, type_) { - #[max_length = 128] - id -> Varchar, - #[sql_name = "type"] - #[max_length = 64] - type_ -> Varchar, - data -> Jsonb, - created_at -> Timestamp, - last_modified_at -> Timestamp, - } -} - diesel::table! { use diesel::sql_types::*; use crate::enums::diesel_exports::*; @@ -1468,7 +1452,6 @@ diesel::allow_tables_to_appear_in_same_query!( blocklist_fingerprint, blocklist_lookup, business_profile, - callback_mapper, captures, cards_info, configs, From d9e1e33b03ae67dd8f112b7c3cabef085351b06f Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Mon, 23 Dec 2024 18:59:09 +0000 Subject: [PATCH 11/11] chore: run formatter --- crates/router/src/core/payment_methods.rs | 12 +++++++++--- crates/router/src/core/payments.rs | 8 ++------ crates/router/src/core/payments/helpers.rs | 20 ++++++++++---------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs index ce0d511e7f6f..7f817e25004b 100644 --- a/crates/router/src/core/payment_methods.rs +++ b/crates/router/src/core/payment_methods.rs @@ -24,7 +24,7 @@ use api_models::payment_methods; #[cfg(feature = "payouts")] pub use api_models::{enums::PayoutConnectors, payouts as payout_types}; #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))] -use common_utils::ext_traits::{Encode, OptionExt,}; +use common_utils::ext_traits::{Encode, OptionExt}; use common_utils::{consts::DEFAULT_LOCALE, id_type}; #[cfg(all(feature = "v2", feature = "payment_methods_v2"))] use common_utils::{ @@ -592,7 +592,10 @@ pub async fn retrieve_payment_method_with_token( merchant_key_store, storage_scheme, mandate_id, - payment_method_info.get_required_value("PaymentMethod").change_context(errors::ApiErrorResponse::InternalServerError).attach_printable("PaymentMethod not found")?, + payment_method_info + .get_required_value("PaymentMethod") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("PaymentMethod not found")?, business_profile, payment_attempt.connector.clone(), should_retry_with_pan, @@ -629,7 +632,10 @@ pub async fn retrieve_payment_method_with_token( merchant_key_store, storage_scheme, mandate_id, - payment_method_info.get_required_value("PaymentMethod").change_context(errors::ApiErrorResponse::InternalServerError).attach_printable("PaymentMethod not found")?, + payment_method_info + .get_required_value("PaymentMethod") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("PaymentMethod not found")?, business_profile, payment_attempt.connector.clone(), should_retry_with_pan, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index c871be7c1115..e2606e26e9a3 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -4478,12 +4478,8 @@ impl VaultData { ) -> Option { match self { Self::CardVaultData(_card_data) => None, - Self::NetworkTokenVaultData(network_token_data) => { - Some(network_token_data.clone()) - } - Self::CardAndNetworkToken(vault_data) => { - Some(vault_data.network_token_data.clone()) - } + Self::NetworkTokenVaultData(network_token_data) => Some(network_token_data.clone()), + Self::CardAndNetworkToken(vault_data) => Some(vault_data.network_token_data.clone()), } } } diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 4b3ba2d53c98..72599ce2eed4 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -2449,7 +2449,7 @@ pub async fn make_pm_data<'a, F: Clone, R, D>( BoxedOperation<'a, F, R, D>, Option, Option, -)>{ +)> { use super::OperationSessionSetters; use crate::core::payments::OperationSessionGetters; @@ -2546,27 +2546,27 @@ pub async fn make_pm_data<'a, F: Clone, R, D>( payments::VaultData::CardVaultData(card), domain::PaymentMethodData::NetworkToken(nt_data), ) => Some(payments::PaymentMethodDataAction::ExistingVaultData( - payments::VaultData::CardAndNetworkToken( - Box::new(payments::CardAndNetworkTokenData { + payments::VaultData::CardAndNetworkToken(Box::new( + payments::CardAndNetworkTokenData { card_data: card.clone(), network_token_data: nt_data.clone(), - }) - ), + }, + )), )), ( payments::VaultData::NetworkTokenVaultData(nt_data), domain::PaymentMethodData::Card(card), ) => Some(payments::PaymentMethodDataAction::ExistingVaultData( - payments::VaultData::CardAndNetworkToken( - Box::new(payments::CardAndNetworkTokenData { + payments::VaultData::CardAndNetworkToken(Box::new( + payments::CardAndNetworkTokenData { card_data: card.clone(), network_token_data: nt_data.clone(), - }) - ), + }, + )), )), _ => Some(payments::PaymentMethodDataAction::ExistingVaultData( vault_data.clone(), - )) + )), }, _ => None, };