diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 0c8924f0d2d1..442e383f2d57 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -2825,6 +2825,8 @@ pub struct ThreeDsData { pub three_ds_authorize_url: String, /// ThreeDS method details pub three_ds_method_details: ThreeDsMethodData, + /// Poll config for a connector + pub poll_config: PollConfigResponse, } #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, ToSchema)] @@ -2841,6 +2843,16 @@ pub enum ThreeDsMethodData { }, } +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, ToSchema)] +pub struct PollConfigResponse { + /// Poll Id + pub poll_id: String, + /// Interval of the poll + pub delay_in_secs: i8, + /// Frequency of the poll + pub frequency: i8, +} + #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "snake_case")] #[serde(untagged)] diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index 6e9ad5848c59..bb9ef7319927 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -405,6 +405,7 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::PaymentCreatePaymentLinkConfig, api_models::payments::ThreeDsData, api_models::payments::ThreeDsMethodData, + api_models::payments::PollConfigResponse, api_models::payments::ExternalAuthenticationDetailsResponse, api_models::payment_methods::RequiredFieldInfo, api_models::payment_methods::DefaultPaymentMethod, diff --git a/crates/router/src/core/authentication.rs b/crates/router/src/core/authentication.rs index dd17ae19ddec..ebf1477f788d 100644 --- a/crates/router/src/core/authentication.rs +++ b/crates/router/src/core/authentication.rs @@ -5,7 +5,10 @@ pub mod types; use api_models::payments; use common_enums::Currency; -use common_utils::{errors::CustomResult, ext_traits::ValueExt}; +use common_utils::{ + errors::CustomResult, + ext_traits::{Encode, StringExt, ValueExt}, +}; use error_stack::{report, ResultExt}; use masking::{ExposeInterface, PeekInterface}; @@ -234,9 +237,12 @@ pub async fn perform_pre_authentication( &three_ds_connector_account, business_profile.merchant_id.clone(), )?; - let router_data = - utils::do_auth_connector_call(state, authentication_connector_name, router_data) - .await?; + let router_data = utils::do_auth_connector_call( + state, + authentication_connector_name.clone(), + router_data, + ) + .await?; let acquirer_details: types::AcquirerDetails = payment_connector_account .get_metadata() .get_required_value("merchant_connector_account.metadata")? @@ -257,6 +263,27 @@ pub async fn perform_pre_authentication( || authentication.authentication_status.is_failed() { *should_continue_confirm_transaction = false; + // If flow is going through external authentication, set the poll_config in payment_data which can be fetched while sending next_action block in confirm response + let default_poll_config = core_types::PollConfig::default(); + let default_config_str = default_poll_config + .encode_to_string_of_json() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Error while stringifying default poll config")?; + let poll_config = state + .store + .find_config_by_key_unwrap_or( + &core_types::PollConfig::get_poll_config_key(authentication_connector_name), + Some(default_config_str), + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("The poll config was not found in the DB")?; + let poll_config: core_types::PollConfig = poll_config + .config + .parse_struct("PollConfig") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Error while parsing PollConfig")?; + payment_data.poll_config = Some(poll_config) } payment_data.authentication = Some(authentication); } diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index c255c0debbb2..6e5ee0b6c7f5 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -22,7 +22,11 @@ use api_models::{ mandates::RecurringDetails, payments::{self as payments_api, HeaderPayload}, }; -use common_utils::{ext_traits::AsyncExt, pii, types::Surcharge}; +use common_utils::{ + ext_traits::{AsyncExt, StringExt}, + pii, + types::Surcharge, +}; use data_models::mandates::{CustomerAcceptance, MandateData}; use diesel_models::{ephemeral_key, fraud_check::FraudCheck}; use error_stack::{report, ResultExt}; @@ -1145,17 +1149,17 @@ impl PaymentRedirectFlow for PaymentAuthenticat let poll_config = state .store .find_config_by_key_unwrap_or( - &format!("poll_config_external_three_ds_{connector}"), + &router_types::PollConfig::get_poll_config_key(connector), Some(default_config_str), ) .await .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("The poll config was not found in the DB")?; - let poll_config = - serde_json::from_str::>(&poll_config.config) - .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable("Error while parsing PollConfig")? - .unwrap_or(default_poll_config); + let poll_config: router_types::PollConfig = poll_config + .config + .parse_struct("PollConfig") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Error while parsing PollConfig")?; let profile_id = payments_response .profile_id .as_ref() @@ -2377,6 +2381,7 @@ where pub authentication: Option, pub frm_metadata: Option, pub recurring_details: Option, + pub poll_config: Option, } #[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 be73d0836dde..d9744cff772c 100644 --- a/crates/router/src/core/payments/operations/payment_approve.rs +++ b/crates/router/src/core/payments/operations/payment_approve.rs @@ -178,6 +178,7 @@ impl frm_metadata: None, authentication: None, recurring_details: None, + poll_config: 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 cb1b2fbd6742..3e531280831a 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -188,6 +188,7 @@ impl frm_metadata: None, authentication: None, recurring_details: None, + poll_config: 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 a20358cb95b1..d4c3f0acad7a 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -231,6 +231,7 @@ impl frm_metadata: None, authentication: None, recurring_details: None, + poll_config: 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 89bdd0b84cc8..d4dc52ce27cb 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -307,6 +307,7 @@ impl authentication: None, frm_metadata: None, recurring_details, + poll_config: 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 de0e6604098b..e73bf33f64a7 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -634,6 +634,7 @@ impl frm_metadata: request.frm_metadata.clone(), authentication, recurring_details, + poll_config: 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 5d510f2afd44..7560257ab268 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -447,6 +447,7 @@ impl authentication: None, frm_metadata: request.frm_metadata.clone(), recurring_details, + poll_config: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/operations/payment_reject.rs b/crates/router/src/core/payments/operations/payment_reject.rs index 413a6fb4f0f5..8845fe836e27 100644 --- a/crates/router/src/core/payments/operations/payment_reject.rs +++ b/crates/router/src/core/payments/operations/payment_reject.rs @@ -174,6 +174,7 @@ impl authentication: None, frm_metadata: None, recurring_details: None, + poll_config: 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 d963c6864b7a..808eb20eb125 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -199,6 +199,7 @@ impl authentication: None, frm_metadata: None, recurring_details: None, + poll_config: 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 70fb33851d92..c7042908b631 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -186,6 +186,7 @@ impl authentication: None, frm_metadata: None, recurring_details: None, + poll_config: 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 c079f93caaea..4c0359c28f06 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -490,6 +490,7 @@ async fn get_tracker_for_sync< authentication, frm_metadata: None, recurring_details: None, + poll_config: 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 b201453068b9..ecf1fe998bb1 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -453,6 +453,7 @@ impl authentication: None, frm_metadata: request.frm_metadata.clone(), recurring_details, + poll_config: 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 7f2311eb88a6..ddba82fc04d1 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -155,6 +155,7 @@ impl authentication: None, frm_metadata: None, recurring_details: None, + poll_config: None, }; let get_trackers_response = operations::GetTrackerResponse { diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 23b3f1f6931f..640c87ca977b 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -570,6 +570,8 @@ where Some(authentication) => { if payment_intent.status == common_enums::IntentStatus::RequiresCustomerAction && authentication.cavv.is_none() && authentication.is_separate_authn_required(){ // if preAuthn and separate authentication needed. + let poll_config = payment_data.poll_config.unwrap_or_default(); + let request_poll_id = core_utils::get_external_authentication_request_poll_id(&payment_intent.payment_id); let payment_connector_name = payment_attempt.connector .as_ref() .get_required_value("connector")?; @@ -592,6 +594,7 @@ where three_ds_method_data: None, three_ds_method_url: None, }), + poll_config: api_models::payments::PollConfigResponse {poll_id: request_poll_id, delay_in_secs: poll_config.delay_in_secs, frequency: poll_config.frequency}, }, }) }else{ diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 6004131be40c..ce31e9bf5471 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -1153,6 +1153,12 @@ pub struct PollConfig { pub frequency: i8, } +impl PollConfig { + pub fn get_poll_config_key(connector: String) -> String { + format!("poll_config_external_three_ds_{connector}") + } +} + impl Default for PollConfig { fn default() -> Self { Self { diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index b736475858f7..9d15bd70923c 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -16316,6 +16316,30 @@ } } }, + "PollConfigResponse": { + "type": "object", + "required": [ + "poll_id", + "delay_in_secs", + "frequency" + ], + "properties": { + "poll_id": { + "type": "string", + "description": "Poll Id" + }, + "delay_in_secs": { + "type": "integer", + "format": "int32", + "description": "Interval of the poll" + }, + "frequency": { + "type": "integer", + "format": "int32", + "description": "Frequency of the poll" + } + } + }, "PollResponse": { "type": "object", "required": [ @@ -17879,7 +17903,8 @@ "required": [ "three_ds_authentication_url", "three_ds_authorize_url", - "three_ds_method_details" + "three_ds_method_details", + "poll_config" ], "properties": { "three_ds_authentication_url": { @@ -17892,6 +17917,9 @@ }, "three_ds_method_details": { "$ref": "#/components/schemas/ThreeDsMethodData" + }, + "poll_config": { + "$ref": "#/components/schemas/PollConfigResponse" } } },