refactor(authentication): flattened paymentData in authentication trait functions (#8365)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Sahkal Poddar
2025-07-01 18:46:15 +05:30
committed by GitHub
parent ad522513b9
commit 18a779f94d
7 changed files with 142 additions and 107 deletions

View File

@ -135,7 +135,6 @@ impl ApiEventMetric for AuthenticationCreateRequest {
})
}
}
impl ApiEventMetric for AuthenticationResponse {
fn get_api_event_type(&self) -> Option<ApiEventsType> {
Some(ApiEventsType::Authentication {

View File

@ -8508,7 +8508,7 @@ pub async fn payment_external_authentication<F: Clone + Sync>(
.await?
{
let auth_response =
<ExternalAuthentication as UnifiedAuthenticationService<F>>::authentication(
<ExternalAuthentication as UnifiedAuthenticationService>::authentication(
&state,
&business_profile,
payment_method_details.1,
@ -8534,7 +8534,7 @@ pub async fn payment_external_authentication<F: Clone + Sync>(
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(

View File

@ -1270,26 +1270,30 @@ impl<F: Clone + Send + Sync> Domain<F, api::PaymentsRequest, PaymentData<F>> 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<F: Clone + Send + Sync> Domain<F, api::PaymentsRequest, PaymentData<F>> 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<F: Clone + Send + Sync> Domain<F, api::PaymentsRequest, PaymentData<F>> 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<F: Clone + Send + Sync> Domain<F, api::PaymentsRequest, PaymentData<F>> 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,

View File

@ -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<F: Clone + Sync> UnifiedAuthenticationService<F> for ClickToPay {
impl UnifiedAuthenticationService for ClickToPay {
fn get_pre_authentication_request_data(
payment_data: &PaymentData<F>,
_payment_method_data: Option<&domain::PaymentMethodData>,
service_details: Option<payments::CtpServiceDetails>,
amount: common_utils::types::MinorUnit,
currency: Option<common_enums::Currency>,
) -> RouterResult<UasPreAuthenticationRequestData> {
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<F: Clone + Sync> UnifiedAuthenticationService<F> 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<F: Clone + Sync> UnifiedAuthenticationService<F> for ClickToPay {
async fn pre_authentication(
state: &SessionState,
_key_store: &domain::MerchantKeyStore,
_business_profile: &domain::Profile,
payment_data: &PaymentData<F>,
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<common_enums::Currency>,
service_details: Option<payments::CtpServiceDetails>,
) -> RouterResult<UasPreAuthenticationRouterData> {
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<F: Clone + Sync> UnifiedAuthenticationService<F> for ClickToPay {
async fn post_authentication(
state: &SessionState,
_key_store: &domain::MerchantKeyStore,
_business_profile: &domain::Profile,
payment_data: &PaymentData<F>,
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<Authentication>,
merchant_id: &common_utils::id_type::MerchantId,
_authentication: Option<&Authentication>,
) -> RouterResult<UasPostAuthenticationRouterData> {
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<F: Clone + Sync> UnifiedAuthenticationService<F> 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<F: Clone + Sync> UnifiedAuthenticationService<F> for ClickToPay {
state: &SessionState,
_key_store: &domain::MerchantKeyStore,
_business_profile: &domain::Profile,
payment_data: &PaymentData<F>,
authentication_id: Option<&common_utils::id_type::AuthenticationId>,
currency: Option<common_enums::Currency>,
status: common_enums::AttemptStatus,
service_details: Option<payments::CtpServiceDetails>,
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<F: Clone + Sync> UnifiedAuthenticationService<F> 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<F: Clone + Sync> UnifiedAuthenticationService<F> for ClickToPay {
#[cfg(feature = "v1")]
#[async_trait::async_trait]
impl<F: Clone + Sync> UnifiedAuthenticationService<F> for ExternalAuthentication {
impl UnifiedAuthenticationService for ExternalAuthentication {
fn get_pre_authentication_request_data(
payment_data: &PaymentData<F>,
payment_method_data: Option<&domain::PaymentMethodData>,
_service_details: Option<payments::CtpServiceDetails>,
_amount: common_utils::types::MinorUnit,
_currency: Option<common_enums::Currency>,
) -> RouterResult<UasPreAuthenticationRequestData> {
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<F: Clone + Sync> UnifiedAuthenticationService<F> for ExternalAuthentication
#[allow(clippy::too_many_arguments)]
async fn pre_authentication(
state: &SessionState,
_key_store: &domain::MerchantKeyStore,
_business_profile: &domain::Profile,
payment_data: &PaymentData<F>,
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<common_enums::Currency>,
service_details: Option<payments::CtpServiceDetails>,
) -> RouterResult<UasPreAuthenticationRouterData> {
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<F: Clone + Sync> UnifiedAuthenticationService<F> for ExternalAuthentication
three_ds_requestor_url: String,
merchant_connector_account: &MerchantConnectorAccountType,
connector_name: &str,
payment_id: common_utils::id_type::PaymentId,
payment_id: Option<common_utils::id_type::PaymentId>,
) -> RouterResult<UasAuthenticationRouterData> {
let authentication_data =
<Self as UnifiedAuthenticationService<F>>::get_authentication_request_data(
<Self as UnifiedAuthenticationService>::get_authentication_request_data(
payment_method_data,
billing_address,
shipping_address,
@ -448,17 +456,18 @@ impl<F: Clone + Sync> UnifiedAuthenticationService<F> for ExternalAuthentication
async fn post_authentication(
state: &SessionState,
_key_store: &domain::MerchantKeyStore,
business_profile: &domain::Profile,
payment_data: &PaymentData<F>,
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<Authentication>,
_merchant_id: &common_utils::id_type::MerchantId,
authentication: Option<&Authentication>,
) -> RouterResult<UasPostAuthenticationRouterData> {
let authentication_data =
<Self as UnifiedAuthenticationService<F>>::get_post_authentication_request_data(
authentication.clone(),
<Self as UnifiedAuthenticationService>::get_post_authentication_request_data(
authentication.cloned(),
)?;
let auth_router_data: UasPostAuthenticationRouterData = utils::construct_uas_router_data(
state,
@ -468,8 +477,8 @@ impl<F: Clone + Sync> UnifiedAuthenticationService<F> 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(

View File

@ -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<F: Clone + Sync> {
pub trait UnifiedAuthenticationService {
fn get_pre_authentication_request_data(
_payment_data: &PaymentData<F>,
_payment_method_data: Option<&domain::PaymentMethodData>,
_service_details: Option<payments::CtpServiceDetails>,
_amount: common_utils::types::MinorUnit,
_currency: Option<common_enums::Currency>,
) -> RouterResult<UasPreAuthenticationRequestData> {
Err(errors::ApiErrorResponse::NotImplemented {
message: NotImplementedMessage::Reason(
@ -50,13 +50,16 @@ pub trait UnifiedAuthenticationService<F: Clone + Sync> {
#[allow(clippy::too_many_arguments)]
async fn pre_authentication(
_state: &SessionState,
_key_store: &domain::MerchantKeyStore,
_business_profile: &domain::Profile,
_payment_data: &PaymentData<F>,
_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<common_enums::Currency>,
_service_details: Option<payments::CtpServiceDetails>,
) -> RouterResult<hyperswitch_domain_models::types::UasPreAuthenticationRouterData> {
Err(errors::ApiErrorResponse::NotImplemented {
message: NotImplementedMessage::Reason("pre_authentication".to_string()),
@ -112,7 +115,7 @@ pub trait UnifiedAuthenticationService<F: Clone + Sync> {
_three_ds_requestor_url: String,
_merchant_connector_account: &MerchantConnectorAccountType,
_connector_name: &str,
_payment_id: common_utils::id_type::PaymentId,
_payment_id: Option<common_utils::id_type::PaymentId>,
) -> RouterResult<hyperswitch_domain_models::types::UasAuthenticationRouterData> {
Err(errors::ApiErrorResponse::NotImplemented {
message: NotImplementedMessage::Reason("authentication".to_string()),
@ -132,13 +135,14 @@ pub trait UnifiedAuthenticationService<F: Clone + Sync> {
#[allow(clippy::too_many_arguments)]
async fn post_authentication(
_state: &SessionState,
_key_store: &domain::MerchantKeyStore,
_business_profile: &domain::Profile,
_payment_data: &PaymentData<F>,
_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<diesel_models::authentication::Authentication>,
_merchant_id: &common_utils::id_type::MerchantId,
_authentication: Option<&diesel_models::authentication::Authentication>,
) -> RouterResult<hyperswitch_domain_models::types::UasPostAuthenticationRouterData> {
Err(errors::ApiErrorResponse::NotImplemented {
message: NotImplementedMessage::Reason("post_authentication".to_string()),
@ -146,14 +150,21 @@ pub trait UnifiedAuthenticationService<F: Clone + Sync> {
.into())
}
#[allow(clippy::too_many_arguments)]
async fn confirmation(
_state: &SessionState,
_key_store: &domain::MerchantKeyStore,
_business_profile: &domain::Profile,
_payment_data: &PaymentData<F>,
_authentication_id: Option<&common_utils::id_type::AuthenticationId>,
_currency: Option<common_enums::Currency>,
_status: common_enums::AttemptStatus,
_service_details: Option<payments::CtpServiceDetails>,
_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()),

View File

@ -65,7 +65,7 @@ pub fn construct_uas_router_data<F: Clone, Req, Res>(
request_data: Req,
merchant_connector_account: &payments::helpers::MerchantConnectorAccountType,
authentication_id: Option<common_utils::id_type::AuthenticationId>,
payment_id: common_utils::id_type::PaymentId,
payment_id: Option<common_utils::id_type::PaymentId>,
) -> RouterResult<RouterData<F, Req, Res>> {
let auth_type: ConnectorAuthType = merchant_connector_account
.get_connector_account_details()
@ -78,7 +78,9 @@ pub fn construct_uas_router_data<F: Clone, Req, Res>(
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(),