diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index 5df0d22f1a..cbfdd05362 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -35,8 +35,9 @@ use crate::{ errors::{self, CustomResult, RouterResult, StorageErrorExt}, mandate::helpers as m_helpers, payments::{ - self, helpers, operations, populate_surcharge_details, CustomerDetails, PaymentAddress, - PaymentData, + self, helpers, operations, + operations::payment_confirm::unified_authentication_service::ThreeDsMetaData, + populate_surcharge_details, CustomerDetails, PaymentAddress, PaymentData, }, three_ds_decision_rule, unified_authentication_service::{ @@ -1387,48 +1388,111 @@ impl Domain> for }, helpers::UnifiedAuthenticationServiceFlow::ExternalAuthenticationInitiate { acquirer_details, - token, .. } => { let (authentication_connector, three_ds_connector_account) = authentication::utils::get_authentication_connector_data(state, key_store, business_profile, None).await?; let authentication_connector_name = authentication_connector.to_string(); - let authentication = authentication::utils::create_new_authentication( + let authentication_id = + common_utils::id_type::AuthenticationId::generate_authentication_id(consts::AUTHENTICATION_ID_PREFIX); + let (acquirer_bin, acquirer_merchant_id, acquirer_country_code) = if let Some(details) = &acquirer_details { + ( + Some(details.acquirer_bin.clone()), + Some(details.acquirer_merchant_id.clone()), + details.acquirer_country_code.clone(), + ) + } else { + (None, None, None) + }; + let authentication = uas_utils::create_new_authentication( state, business_profile.merchant_id.clone(), - authentication_connector_name.clone(), - token, + Some(authentication_connector_name.clone()), business_profile.get_id().to_owned(), - payment_data.payment_intent.payment_id.clone(), - three_ds_connector_account + Some(payment_data.payment_intent.payment_id.clone()), + Some(three_ds_connector_account .get_mca_id() .ok_or(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Error while finding mca_id from merchant_connector_account")?, + .attach_printable("Error while finding mca_id from merchant_connector_account")?), + &authentication_id, + payment_data.service_details.clone(), + common_enums::AuthenticationStatus::Started, + None, payment_data.payment_attempt.organization_id.clone(), payment_data.payment_intent.force_3ds_challenge, payment_data.payment_intent.psd2_sca_exemption_type, + acquirer_bin, + acquirer_merchant_id, + acquirer_country_code, + None, + None, + None, + None, ) .await?; + let acquirer_configs = authentication + .profile_acquirer_id + .clone() + .and_then(|acquirer_id| { + business_profile + .acquirer_config_map.as_ref() + .and_then(|acquirer_config_map| acquirer_config_map.0.get(&acquirer_id).cloned()) + }); + let metadata: Option = three_ds_connector_account + .get_metadata() + .map(|metadata| { + metadata + .expose() + .parse_value("ThreeDsMetaData") + .attach_printable("Error while parsing ThreeDsMetaData") + }) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError)?; + let merchant_country_code = authentication.acquirer_country_code.clone(); + let return_url = helpers::create_authorize_url( + &state.base_url, + &payment_data.payment_attempt.clone(), + payment_data.payment_attempt.connector.as_ref().get_required_value("connector")?, + ); - let pre_auth_response = uas_utils::types::ExternalAuthentication::pre_authentication( - state, - &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(), - None, - None, - None, - None - ).await?; + let notification_url = Some(url::Url::parse(&return_url)) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed to parse webhook url")?; + + let merchant_details = Some(unified_authentication_service::MerchantDetails { + merchant_id: Some(authentication.merchant_id.get_string_repr().to_string()), + merchant_name: acquirer_configs.clone().map(|detail| detail.merchant_name.clone()).or(metadata.clone().and_then(|metadata| metadata.merchant_name)), + merchant_category_code: business_profile.merchant_category_code.or(metadata.clone().and_then(|metadata| metadata.merchant_category_code)), + endpoint_prefix: metadata.clone().map(|metadata| metadata.endpoint_prefix), + three_ds_requestor_url: business_profile.authentication_connector_details.clone().map(|details| details.three_ds_requestor_url), + three_ds_requestor_id: metadata.clone().and_then(|metadata| metadata.three_ds_requestor_id), + three_ds_requestor_name: metadata.clone().and_then(|metadata| metadata.three_ds_requestor_name), + merchant_country_code: merchant_country_code.map(common_types::payments::MerchantCountryCode::new), + notification_url, + }); + let domain_address = payment_data.address.get_payment_method_billing(); + + let pre_auth_response = uas_utils::types::ExternalAuthentication::pre_authentication( + state, + &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(), + merchant_details.as_ref(), + domain_address, + authentication.acquirer_bin.clone(), + authentication.acquirer_merchant_id.clone(), + ) + .await?; let updated_authentication = uas_utils::utils::external_authentication_update_trackers( state, pre_auth_response, @@ -1442,7 +1506,7 @@ impl Domain> for ).await?; let authentication_store = hyperswitch_domain_models::router_request_types::authentication::AuthenticationStore { cavv: None, // since in case of pre_authentication cavv is not present - authentication + authentication: updated_authentication.clone(), }; payment_data.authentication = Some(authentication_store.clone()); diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 8572f3cfa3..a96f288ea1 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -889,7 +889,9 @@ impl Payments { web::resource("/{payment_id}/incremental_authorization").route(web::post().to(payments::payments_incremental_authorization)), ) .service( - web::resource("/{payment_id}/{merchant_id}/authorize/{connector}").route(web::post().to(payments::post_3ds_payments_authorize)), + web::resource("/{payment_id}/{merchant_id}/authorize/{connector}") + .route(web::post().to(payments::post_3ds_payments_authorize)) + .route(web::get().to(payments::post_3ds_payments_authorize)) ) .service( web::resource("/{payment_id}/3ds/authentication").route(web::post().to(payments::payments_external_authentication)),