From 18a779f94d418587c10c8ac8766d22ff41d25f6a Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Tue, 1 Jul 2025 18:46:15 +0530 Subject: [PATCH] refactor(authentication): flattened paymentData in authentication trait functions (#8365) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- crates/api_models/src/authentication.rs | 1 - crates/router/src/core/payments.rs | 4 +- .../payments/operations/payment_confirm.rs | 40 +++-- .../core/unified_authentication_service.rs | 157 +++++++++--------- .../unified_authentication_service/types.rs | 39 +++-- .../unified_authentication_service/utils.rs | 6 +- .../down.sql | 2 +- 7 files changed, 142 insertions(+), 107 deletions(-) diff --git a/crates/api_models/src/authentication.rs b/crates/api_models/src/authentication.rs index d1c98b25ec..af7b59925b 100644 --- a/crates/api_models/src/authentication.rs +++ b/crates/api_models/src/authentication.rs @@ -135,7 +135,6 @@ impl ApiEventMetric for AuthenticationCreateRequest { }) } } - impl ApiEventMetric for AuthenticationResponse { fn get_api_event_type(&self) -> Option { Some(ApiEventsType::Authentication { diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 93c4b55230..83176881ea 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -8508,7 +8508,7 @@ pub async fn payment_external_authentication( .await? { let auth_response = - >::authentication( + ::authentication( &state, &business_profile, payment_method_details.1, @@ -8534,7 +8534,7 @@ pub async fn payment_external_authentication( authentication_details.three_ds_requestor_url.clone(), &merchant_connector_account, &authentication_connector, - payment_intent.payment_id, + Some(payment_intent.payment_id), ) .await?; let authentication = external_authentication_update_trackers( diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index 4dbefe6c9d..8d850c064a 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -1270,26 +1270,30 @@ impl Domain> for )?; ClickToPay::pre_authentication( state, - key_store, - business_profile, - payment_data, + &payment_data.payment_attempt.merchant_id, + Some(&payment_data.payment_intent.payment_id), + payment_data.payment_method_data.as_ref(), &helpers::MerchantConnectorAccountType::DbVal(Box::new(connector_mca.clone())), &connector_mca.connector_name, &authentication_id, payment_method, + payment_data.payment_intent.amount, + payment_data.payment_intent.currency, + payment_data.service_details.clone(), ) .await?; payment_data.payment_attempt.authentication_id = Some(authentication_id.clone()); let response = ClickToPay::post_authentication( state, - key_store, business_profile, - payment_data, + Some(&payment_data.payment_intent.payment_id), &helpers::MerchantConnectorAccountType::DbVal(Box::new(connector_mca.clone())), &connector_mca.connector_name, + &authentication_id, payment_method, - None, + &payment_data.payment_intent.merchant_id, + None ) .await?; let (network_token, authentication_status) = match response.response.clone() { @@ -1399,10 +1403,16 @@ impl Domain> for state, key_store, business_profile, - payment_data, + payment_data.payment_attempt.authentication_id.as_ref(), + payment_data.payment_intent.currency, + payment_data.payment_attempt.status, + payment_data.service_details.clone(), &helpers::MerchantConnectorAccountType::DbVal(Box::new(connector_mca.clone())), &connector_mca.connector_name, payment_method, + payment_data.payment_attempt.net_amount.get_order_amount(), + Some(&payment_data.payment_intent.payment_id), + merchant_id, ) .await? }, @@ -1433,15 +1443,18 @@ impl Domain> for let pre_auth_response = uas_utils::types::ExternalAuthentication::pre_authentication( state, - key_store, - business_profile, - payment_data, + &payment_data.payment_attempt.merchant_id, + Some(&payment_data.payment_intent.payment_id), + payment_data.payment_method_data.as_ref(), &three_ds_connector_account, &authentication_connector_name, &authentication.authentication_id, payment_data.payment_attempt.payment_method.ok_or( errors::ApiErrorResponse::InternalServerError ).attach_printable("payment_method not found in payment_attempt")?, + payment_data.payment_intent.amount, + payment_data.payment_intent.currency, + payment_data.service_details.clone() ).await?; let updated_authentication = uas_utils::utils::external_authentication_update_trackers( state, @@ -1511,15 +1524,16 @@ impl Domain> for let updated_authentication = if !authentication.authentication_status.is_terminal_status() && is_pull_mechanism_enabled { let post_auth_response = uas_utils::types::ExternalAuthentication::post_authentication( state, - key_store, business_profile, - payment_data, + Some(&payment_data.payment_intent.payment_id), &three_ds_connector_account, &authentication_connector.to_string(), + &authentication.authentication_id, payment_data.payment_attempt.payment_method.ok_or( errors::ApiErrorResponse::InternalServerError ).attach_printable("payment_method not found in payment_attempt")?, - Some(authentication.clone()), + &payment_data.payment_intent.merchant_id, + Some(&authentication), ).await?; uas_utils::utils::external_authentication_update_trackers( state, diff --git a/crates/router/src/core/unified_authentication_service.rs b/crates/router/src/core/unified_authentication_service.rs index becb1c173d..caba69331b 100644 --- a/crates/router/src/core/unified_authentication_service.rs +++ b/crates/router/src/core/unified_authentication_service.rs @@ -33,7 +33,6 @@ use crate::{ consts, core::{ errors::utils::StorageErrorExt, - payments::PaymentData, unified_authentication_service::types::{ ClickToPay, ExternalAuthentication, UnifiedAuthenticationService, UNIFIED_AUTHENTICATION_SERVICE, @@ -47,32 +46,31 @@ use crate::{ #[cfg(feature = "v1")] #[async_trait::async_trait] -impl UnifiedAuthenticationService for ClickToPay { +impl UnifiedAuthenticationService for ClickToPay { fn get_pre_authentication_request_data( - payment_data: &PaymentData, + _payment_method_data: Option<&domain::PaymentMethodData>, + service_details: Option, + amount: common_utils::types::MinorUnit, + currency: Option, ) -> RouterResult { - let service_details = hyperswitch_domain_models::router_request_types::unified_authentication_service::CtpServiceDetails { + let domain_service_details = hyperswitch_domain_models::router_request_types::unified_authentication_service::CtpServiceDetails { service_session_ids: Some(ServiceSessionIds { - merchant_transaction_id: payment_data - .service_details + merchant_transaction_id: service_details .as_ref() .and_then(|details| details.merchant_transaction_id.clone()), - correlation_id: payment_data - .service_details + correlation_id: service_details .as_ref() .and_then(|details| details.correlation_id.clone()), - x_src_flow_id: payment_data - .service_details + x_src_flow_id: service_details .as_ref() .and_then(|details| details.x_src_flow_id.clone()), }), payment_details: None, }; - let amount = payment_data.payment_attempt.net_amount.get_order_amount(); let transaction_details = TransactionDetails { amount: Some(amount), - currency: payment_data.payment_attempt.currency, + currency, device_channel: None, message_category: None, }; @@ -84,13 +82,12 @@ impl UnifiedAuthenticationService for ClickToPay { is_authenticated: false, // This is not relevant in this flow so keeping it as false locale: None, supported_card_brands: None, - encrypted_payload: payment_data - .service_details + encrypted_payload: service_details .as_ref() .and_then(|details| details.encrypted_payload.clone()), }); Ok(UasPreAuthenticationRequestData { - service_details: Some(service_details), + service_details: Some(domain_service_details), transaction_details: Some(transaction_details), payment_details: None, authentication_info, @@ -99,27 +96,35 @@ impl UnifiedAuthenticationService for ClickToPay { async fn pre_authentication( state: &SessionState, - _key_store: &domain::MerchantKeyStore, - _business_profile: &domain::Profile, - payment_data: &PaymentData, + merchant_id: &common_utils::id_type::MerchantId, + payment_id: Option<&common_utils::id_type::PaymentId>, + payment_method_data: Option<&domain::PaymentMethodData>, merchant_connector_account: &MerchantConnectorAccountType, connector_name: &str, authentication_id: &common_utils::id_type::AuthenticationId, payment_method: common_enums::PaymentMethod, + amount: common_utils::types::MinorUnit, + currency: Option, + service_details: Option, ) -> RouterResult { - let pre_authentication_data = Self::get_pre_authentication_request_data(payment_data)?; + let pre_authentication_data = Self::get_pre_authentication_request_data( + payment_method_data, + service_details, + amount, + currency, + )?; let pre_auth_router_data: UasPreAuthenticationRouterData = utils::construct_uas_router_data( state, connector_name.to_string(), payment_method, - payment_data.payment_attempt.merchant_id.clone(), + merchant_id.clone(), None, pre_authentication_data, merchant_connector_account, Some(authentication_id.to_owned()), - payment_data.payment_intent.payment_id.clone(), + payment_id.cloned(), )?; utils::do_auth_connector_call( @@ -132,21 +137,15 @@ impl UnifiedAuthenticationService for ClickToPay { async fn post_authentication( state: &SessionState, - _key_store: &domain::MerchantKeyStore, _business_profile: &domain::Profile, - payment_data: &PaymentData, + payment_id: Option<&common_utils::id_type::PaymentId>, merchant_connector_account: &MerchantConnectorAccountType, connector_name: &str, + authentication_id: &common_utils::id_type::AuthenticationId, payment_method: common_enums::PaymentMethod, - _authentication: Option, + merchant_id: &common_utils::id_type::MerchantId, + _authentication: Option<&Authentication>, ) -> RouterResult { - let authentication_id = payment_data - .payment_attempt - .authentication_id - .clone() - .ok_or(ApiErrorResponse::InternalServerError) - .attach_printable("Missing authentication id in payment attempt")?; - let post_authentication_data = UasPostAuthenticationRequestData { threeds_server_transaction_id: None, }; @@ -156,12 +155,12 @@ impl UnifiedAuthenticationService for ClickToPay { state, connector_name.to_string(), payment_method, - payment_data.payment_attempt.merchant_id.clone(), + merchant_id.clone(), None, post_authentication_data, merchant_connector_account, - Some(authentication_id.clone()), - payment_data.payment_intent.payment_id.clone(), + Some(authentication_id.to_owned()), + payment_id.cloned(), )?; utils::do_auth_connector_call( @@ -176,39 +175,39 @@ impl UnifiedAuthenticationService for ClickToPay { state: &SessionState, _key_store: &domain::MerchantKeyStore, _business_profile: &domain::Profile, - payment_data: &PaymentData, + authentication_id: Option<&common_utils::id_type::AuthenticationId>, + currency: Option, + status: common_enums::AttemptStatus, + service_details: Option, merchant_connector_account: &MerchantConnectorAccountType, connector_name: &str, payment_method: common_enums::PaymentMethod, + net_amount: common_utils::types::MinorUnit, + payment_id: Option<&common_utils::id_type::PaymentId>, + merchant_id: &common_utils::id_type::MerchantId, ) -> RouterResult<()> { - let authentication_id = payment_data - .payment_attempt - .authentication_id - .clone() + let authentication_id = authentication_id .ok_or(ApiErrorResponse::InternalServerError) - .attach_printable("Missing authentication id in payment attempt")?; + .attach_printable("Missing authentication id in tracker")?; - let currency = payment_data.payment_attempt.currency.ok_or( - ApiErrorResponse::MissingRequiredField { - field_name: "currency", - }, - )?; + let currency = currency.ok_or(ApiErrorResponse::MissingRequiredField { + field_name: "currency", + })?; let current_time = common_utils::date_time::now(); - let payment_attempt_status = payment_data.payment_attempt.status; + let payment_attempt_status = status; let (checkout_event_status, confirmation_reason) = utils::get_checkout_event_status_and_reason(payment_attempt_status); - let click_to_pay_details = payment_data.service_details.clone(); + let click_to_pay_details = service_details.clone(); let authentication_confirmation_data = UasConfirmationRequestData { - x_src_flow_id: payment_data - .service_details + x_src_flow_id: click_to_pay_details .as_ref() .and_then(|details| details.x_src_flow_id.clone()), - transaction_amount: payment_data.payment_attempt.net_amount.get_order_amount(), + transaction_amount: net_amount, transaction_currency: currency, checkout_event_type: Some("01".to_string()), // hardcoded to '01' since only authorise flow is implemented checkout_event_status: checkout_event_status.clone(), @@ -228,12 +227,12 @@ impl UnifiedAuthenticationService for ClickToPay { state, connector_name.to_string(), payment_method, - payment_data.payment_attempt.merchant_id.clone(), + merchant_id.clone(), None, authentication_confirmation_data, merchant_connector_account, - Some(authentication_id.clone()), - payment_data.payment_intent.payment_id.clone() + Some(authentication_id.to_owned()), + payment_id.cloned(), )?; utils::do_auth_connector_call( @@ -250,15 +249,16 @@ impl UnifiedAuthenticationService for ClickToPay { #[cfg(feature = "v1")] #[async_trait::async_trait] -impl UnifiedAuthenticationService for ExternalAuthentication { +impl UnifiedAuthenticationService for ExternalAuthentication { fn get_pre_authentication_request_data( - payment_data: &PaymentData, + payment_method_data: Option<&domain::PaymentMethodData>, + _service_details: Option, + _amount: common_utils::types::MinorUnit, + _currency: Option, ) -> RouterResult { - let payment_method_data = payment_data - .payment_method_data - .as_ref() + let payment_method_data = payment_method_data .ok_or(ApiErrorResponse::InternalServerError) - .attach_printable("payment_data.payment_method_data is missing")?; + .attach_printable("payment_method_data is missing")?; let payment_details = if let payment_method_data::PaymentMethodData::Card(card) = payment_method_data { Some(PaymentDetails { @@ -285,27 +285,35 @@ impl UnifiedAuthenticationService for ExternalAuthentication #[allow(clippy::too_many_arguments)] async fn pre_authentication( state: &SessionState, - _key_store: &domain::MerchantKeyStore, - _business_profile: &domain::Profile, - payment_data: &PaymentData, + merchant_id: &common_utils::id_type::MerchantId, + payment_id: Option<&common_utils::id_type::PaymentId>, + payment_method_data: Option<&domain::PaymentMethodData>, merchant_connector_account: &MerchantConnectorAccountType, connector_name: &str, authentication_id: &common_utils::id_type::AuthenticationId, payment_method: common_enums::PaymentMethod, + amount: common_utils::types::MinorUnit, + currency: Option, + service_details: Option, ) -> RouterResult { - let pre_authentication_data = Self::get_pre_authentication_request_data(payment_data)?; + let pre_authentication_data = Self::get_pre_authentication_request_data( + payment_method_data, + service_details, + amount, + currency, + )?; let pre_auth_router_data: UasPreAuthenticationRouterData = utils::construct_uas_router_data( state, connector_name.to_string(), payment_method, - payment_data.payment_attempt.merchant_id.clone(), + merchant_id.clone(), None, pre_authentication_data, merchant_connector_account, Some(authentication_id.to_owned()), - payment_data.payment_intent.payment_id.clone(), + payment_id.cloned(), )?; utils::do_auth_connector_call( @@ -391,10 +399,10 @@ impl UnifiedAuthenticationService for ExternalAuthentication three_ds_requestor_url: String, merchant_connector_account: &MerchantConnectorAccountType, connector_name: &str, - payment_id: common_utils::id_type::PaymentId, + payment_id: Option, ) -> RouterResult { let authentication_data = - >::get_authentication_request_data( + ::get_authentication_request_data( payment_method_data, billing_address, shipping_address, @@ -448,17 +456,18 @@ impl UnifiedAuthenticationService for ExternalAuthentication async fn post_authentication( state: &SessionState, - _key_store: &domain::MerchantKeyStore, business_profile: &domain::Profile, - payment_data: &PaymentData, + payment_id: Option<&common_utils::id_type::PaymentId>, merchant_connector_account: &MerchantConnectorAccountType, connector_name: &str, + _authentication_id: &common_utils::id_type::AuthenticationId, payment_method: common_enums::PaymentMethod, - authentication: Option, + _merchant_id: &common_utils::id_type::MerchantId, + authentication: Option<&Authentication>, ) -> RouterResult { let authentication_data = - >::get_post_authentication_request_data( - authentication.clone(), + ::get_post_authentication_request_data( + authentication.cloned(), )?; let auth_router_data: UasPostAuthenticationRouterData = utils::construct_uas_router_data( state, @@ -468,8 +477,8 @@ impl UnifiedAuthenticationService for ExternalAuthentication None, authentication_data, merchant_connector_account, - authentication.map(|auth| auth.authentication_id), - payment_data.payment_intent.payment_id.clone(), + authentication.map(|auth| auth.authentication_id.clone()), + payment_id.cloned(), )?; utils::do_auth_connector_call( diff --git a/crates/router/src/core/unified_authentication_service/types.rs b/crates/router/src/core/unified_authentication_service/types.rs index 54e903edd6..12b385327c 100644 --- a/crates/router/src/core/unified_authentication_service/types.rs +++ b/crates/router/src/core/unified_authentication_service/types.rs @@ -12,10 +12,7 @@ use hyperswitch_domain_models::{ }; use crate::{ - core::{ - errors::RouterResult, - payments::{helpers::MerchantConnectorAccountType, PaymentData}, - }, + core::{errors::RouterResult, payments::helpers::MerchantConnectorAccountType}, db::domain, routes::SessionState, }; @@ -35,9 +32,12 @@ pub struct ClickToPay; pub struct ExternalAuthentication; #[async_trait::async_trait] -pub trait UnifiedAuthenticationService { +pub trait UnifiedAuthenticationService { fn get_pre_authentication_request_data( - _payment_data: &PaymentData, + _payment_method_data: Option<&domain::PaymentMethodData>, + _service_details: Option, + _amount: common_utils::types::MinorUnit, + _currency: Option, ) -> RouterResult { Err(errors::ApiErrorResponse::NotImplemented { message: NotImplementedMessage::Reason( @@ -50,13 +50,16 @@ pub trait UnifiedAuthenticationService { #[allow(clippy::too_many_arguments)] async fn pre_authentication( _state: &SessionState, - _key_store: &domain::MerchantKeyStore, - _business_profile: &domain::Profile, - _payment_data: &PaymentData, + _merchant_id: &common_utils::id_type::MerchantId, + _payment_id: Option<&common_utils::id_type::PaymentId>, + _payment_method_data: Option<&domain::PaymentMethodData>, _merchant_connector_account: &MerchantConnectorAccountType, _connector_name: &str, _authentication_id: &common_utils::id_type::AuthenticationId, _payment_method: common_enums::PaymentMethod, + _amount: common_utils::types::MinorUnit, + _currency: Option, + _service_details: Option, ) -> RouterResult { Err(errors::ApiErrorResponse::NotImplemented { message: NotImplementedMessage::Reason("pre_authentication".to_string()), @@ -112,7 +115,7 @@ pub trait UnifiedAuthenticationService { _three_ds_requestor_url: String, _merchant_connector_account: &MerchantConnectorAccountType, _connector_name: &str, - _payment_id: common_utils::id_type::PaymentId, + _payment_id: Option, ) -> RouterResult { Err(errors::ApiErrorResponse::NotImplemented { message: NotImplementedMessage::Reason("authentication".to_string()), @@ -132,13 +135,14 @@ pub trait UnifiedAuthenticationService { #[allow(clippy::too_many_arguments)] async fn post_authentication( _state: &SessionState, - _key_store: &domain::MerchantKeyStore, _business_profile: &domain::Profile, - _payment_data: &PaymentData, + _payment_id: Option<&common_utils::id_type::PaymentId>, _merchant_connector_account: &MerchantConnectorAccountType, _connector_name: &str, + _authentication_id: &common_utils::id_type::AuthenticationId, _payment_method: common_enums::PaymentMethod, - _authentication: Option, + _merchant_id: &common_utils::id_type::MerchantId, + _authentication: Option<&diesel_models::authentication::Authentication>, ) -> RouterResult { Err(errors::ApiErrorResponse::NotImplemented { message: NotImplementedMessage::Reason("post_authentication".to_string()), @@ -146,14 +150,21 @@ pub trait UnifiedAuthenticationService { .into()) } + #[allow(clippy::too_many_arguments)] async fn confirmation( _state: &SessionState, _key_store: &domain::MerchantKeyStore, _business_profile: &domain::Profile, - _payment_data: &PaymentData, + _authentication_id: Option<&common_utils::id_type::AuthenticationId>, + _currency: Option, + _status: common_enums::AttemptStatus, + _service_details: Option, _merchant_connector_account: &MerchantConnectorAccountType, _connector_name: &str, _payment_method: common_enums::PaymentMethod, + _net_amount: common_utils::types::MinorUnit, + _payment_id: Option<&common_utils::id_type::PaymentId>, + _merchant_id: &common_utils::id_type::MerchantId, ) -> RouterResult<()> { Err(errors::ApiErrorResponse::NotImplemented { message: NotImplementedMessage::Reason("confirmation".to_string()), diff --git a/crates/router/src/core/unified_authentication_service/utils.rs b/crates/router/src/core/unified_authentication_service/utils.rs index 5e199968fe..6c841a02d3 100644 --- a/crates/router/src/core/unified_authentication_service/utils.rs +++ b/crates/router/src/core/unified_authentication_service/utils.rs @@ -65,7 +65,7 @@ pub fn construct_uas_router_data( request_data: Req, merchant_connector_account: &payments::helpers::MerchantConnectorAccountType, authentication_id: Option, - payment_id: common_utils::id_type::PaymentId, + payment_id: Option, ) -> RouterResult> { let auth_type: ConnectorAuthType = merchant_connector_account .get_connector_account_details() @@ -78,7 +78,9 @@ pub fn construct_uas_router_data( customer_id: None, connector_customer: None, connector: authentication_connector_name, - payment_id: payment_id.get_string_repr().to_owned(), + payment_id: payment_id + .map(|id| id.get_string_repr().to_owned()) + .unwrap_or_default(), tenant_id: state.tenant.tenant_id.clone(), attempt_id: IRRELEVANT_ATTEMPT_ID_IN_AUTHENTICATION_FLOW.to_owned(), status: common_enums::AttemptStatus::default(), diff --git a/migrations/2025-05-19-130655_authentication_table_refactor/down.sql b/migrations/2025-05-19-130655_authentication_table_refactor/down.sql index e486cb79a5..a61357c5f5 100644 --- a/migrations/2025-05-19-130655_authentication_table_refactor/down.sql +++ b/migrations/2025-05-19-130655_authentication_table_refactor/down.sql @@ -3,7 +3,7 @@ ALTER TABLE authentication ALTER COLUMN authentication_connector SET NOT NULL, ALTER COLUMN merchant_connector_id SET NOT NULL, - ADD COLUMN IF NOT EXISTS authentication_client_secret VARCHAR(128) NULL, + DROP COLUMN IF EXISTS authentication_client_secret, DROP COLUMN IF EXISTS force_3ds_challenge, DROP COLUMN IF EXISTS psd2_sca_exemption_type, DROP COLUMN IF EXISTS return_url,