chore: code refinement

This commit is contained in:
Amitsingh Tanwar
2025-10-28 15:32:31 +05:30
parent fdd4154a8c
commit 184fea4d04
8 changed files with 168 additions and 127 deletions

View File

@ -934,15 +934,13 @@ async fn call_unified_connector_service_authorize(
let payment_authorize_response = response.into_inner(); let payment_authorize_response = response.into_inner();
let (router_data_response, status_code) = let ucs_data = handle_unified_connector_service_response_for_payment_authorize(
handle_unified_connector_service_response_for_payment_authorize(
&mut router_data,
payment_authorize_response.clone(), payment_authorize_response.clone(),
) )
.change_context(ApiErrorResponse::InternalServerError) .change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to deserialize UCS response")?; .attach_printable("Failed to deserialize UCS response")?;
let router_data_response = router_data_response.map(|(response, status)| { let router_data_response = ucs_data.router_data_response.map(|(response, status)| {
router_data.status = status; router_data.status = status;
response response
}); });
@ -951,7 +949,16 @@ async fn call_unified_connector_service_authorize(
.raw_connector_response .raw_connector_response
.clone() .clone()
.map(|raw_connector_response| raw_connector_response.expose().into()); .map(|raw_connector_response| raw_connector_response.expose().into());
router_data.connector_http_status_code = Some(status_code); router_data.connector_http_status_code = Some(ucs_data.status_code);
// Populate connector_customer_id if present
ucs_data.connector_customer_id.map(|connector_customer_id| {
router_data.connector_customer = Some(connector_customer_id);
});
ucs_data.connector_response.map(|customer_response| {
router_data.connector_response = Some(customer_response);
});
Ok((router_data, payment_authorize_response)) Ok((router_data, payment_authorize_response))
}, },
@ -1028,15 +1035,13 @@ async fn call_unified_connector_service_repeat_payment(
let payment_repeat_response = response.into_inner(); let payment_repeat_response = response.into_inner();
let (router_data_response, status_code) = let ucs_data = handle_unified_connector_service_response_for_payment_repeat(
handle_unified_connector_service_response_for_payment_repeat(
&mut router_data,
payment_repeat_response.clone(), payment_repeat_response.clone(),
) )
.change_context(ApiErrorResponse::InternalServerError) .change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to deserialize UCS response")?; .attach_printable("Failed to deserialize UCS response")?;
let router_data_response = router_data_response.map(|(response, status)| { let router_data_response = ucs_data.router_data_response.map(|(response, status)| {
router_data.status = status; router_data.status = status;
response response
}); });
@ -1045,7 +1050,17 @@ async fn call_unified_connector_service_repeat_payment(
.raw_connector_response .raw_connector_response
.clone() .clone()
.map(|raw_connector_response| raw_connector_response.expose().into()); .map(|raw_connector_response| raw_connector_response.expose().into());
router_data.connector_http_status_code = Some(status_code); router_data.connector_http_status_code = Some(ucs_data.status_code);
// Populate connector_customer_id if present
ucs_data.connector_customer_id.map(|connector_customer_id| {
router_data.connector_customer = Some(connector_customer_id);
});
// Populate connector_response if present
ucs_data.connector_response.map(|connector_response| {
router_data.connector_response = Some(connector_response);
});
Ok((router_data, payment_repeat_response)) Ok((router_data, payment_repeat_response))
}, },

View File

@ -229,19 +229,19 @@ impl Feature<api::Void, types::PaymentsCancelData>
let payment_void_response = response.into_inner(); let payment_void_response = response.into_inner();
let (router_data_response, status_code) = let ucs_data = handle_unified_connector_service_response_for_payment_cancel(
handle_unified_connector_service_response_for_payment_cancel(
payment_void_response.clone(), payment_void_response.clone(),
) )
.change_context(ApiErrorResponse::InternalServerError) .change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to deserialize UCS response")?; .attach_printable("Failed to deserialize UCS response")?;
let router_data_response = router_data_response.map(|(response, status)| { let router_data_response =
ucs_data.router_data_response.map(|(response, status)| {
router_data.status = status; router_data.status = status;
response response
}); });
router_data.response = router_data_response; router_data.response = router_data_response;
router_data.connector_http_status_code = Some(status_code); router_data.connector_http_status_code = Some(ucs_data.status_code);
Ok((router_data, payment_void_response)) Ok((router_data, payment_void_response))
}, },

View File

@ -239,14 +239,14 @@ impl Feature<api::Capture, types::PaymentsCaptureData>
let payment_capture_response = response.into_inner(); let payment_capture_response = response.into_inner();
let (router_data_response, status_code) = let ucs_data = handle_unified_connector_service_response_for_payment_capture(
handle_unified_connector_service_response_for_payment_capture(
payment_capture_response.clone(), payment_capture_response.clone(),
) )
.change_context(ApiErrorResponse::InternalServerError) .change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to deserialize UCS response")?; .attach_printable("Failed to deserialize UCS response")?;
let router_data_response = router_data_response.map(|(response, status)| { let router_data_response =
ucs_data.router_data_response.map(|(response, status)| {
router_data.status = status; router_data.status = status;
response response
}); });
@ -255,7 +255,7 @@ impl Feature<api::Capture, types::PaymentsCaptureData>
router_data.minor_amount_captured = payment_capture_response router_data.minor_amount_captured = payment_capture_response
.minor_captured_amount .minor_captured_amount
.map(MinorUnit::new); .map(MinorUnit::new);
router_data.connector_http_status_code = Some(status_code); router_data.connector_http_status_code = Some(ucs_data.status_code);
Ok((router_data, payment_capture_response)) Ok((router_data, payment_capture_response))
}, },

View File

@ -436,15 +436,14 @@ impl Feature<api::ExternalVaultProxy, types::ExternalVaultProxyPaymentsData>
let payment_authorize_response = response.into_inner(); let payment_authorize_response = response.into_inner();
let (router_data_response, status_code) = let ucs_data =
unified_connector_service::handle_unified_connector_service_response_for_payment_authorize( unified_connector_service::handle_unified_connector_service_response_for_payment_authorize(
&mut router_data,
payment_authorize_response.clone(), payment_authorize_response.clone(),
) )
.change_context(ApiErrorResponse::InternalServerError) .change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to deserialize UCS response")?; .attach_printable("Failed to deserialize UCS response")?;
let router_data_response = router_data_response.map(|(response, status)|{ let router_data_response = ucs_data.router_data_response.map(|(response, status)|{
router_data.status = status; router_data.status = status;
response response
}); });
@ -453,7 +452,7 @@ impl Feature<api::ExternalVaultProxy, types::ExternalVaultProxyPaymentsData>
.raw_connector_response .raw_connector_response
.clone() .clone()
.map(|raw_connector_response| raw_connector_response.expose().into()); .map(|raw_connector_response| raw_connector_response.expose().into());
router_data.connector_http_status_code = Some(status_code); router_data.connector_http_status_code = Some(ucs_data.status_code);
Ok((router_data, payment_authorize_response)) Ok((router_data, payment_authorize_response))
} }

View File

@ -342,20 +342,26 @@ impl Feature<api::SetupMandate, types::SetupMandateRequestData> for types::Setup
let payment_register_response = response.into_inner(); let payment_register_response = response.into_inner();
let (router_data_response, status_code) = let ucs_data = handle_unified_connector_service_response_for_payment_register(
handle_unified_connector_service_response_for_payment_register(
&mut router_data,
payment_register_response.clone(), payment_register_response.clone(),
) )
.change_context(ApiErrorResponse::InternalServerError) .change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to deserialize UCS response")?; .attach_printable("Failed to deserialize UCS response")?;
let router_data_response = router_data_response.map(|(response, status)| { let router_data_response =
ucs_data.router_data_response.map(|(response, status)| {
router_data.status = status; router_data.status = status;
response response
}); });
router_data.response = router_data_response; router_data.response = router_data_response;
router_data.connector_http_status_code = Some(status_code); router_data.connector_http_status_code = Some(ucs_data.status_code);
// Populate connector_customer_id if present
ucs_data.connector_customer_id.map(|connector_customer_id| {
router_data.connector_customer = Some(connector_customer_id);
});
// Note: Register flow doesn't populate connector_response
Ok((router_data, payment_register_response)) Ok((router_data, payment_register_response))
}, },

View File

@ -7905,18 +7905,17 @@ where
/// Helper function to populate connector_customer_id from database before calling UCS /// Helper function to populate connector_customer_id from database before calling UCS
/// This checks if a connector_customer_id already exists in the database and populates it into router_data /// This checks if a connector_customer_id already exists in the database and populates it into router_data
/// Returns true if connector_customer_id was found and populated from DB, false otherwise /// Returns true if connector_customer_id was found and populated from DB, false otherwise
async fn populate_connector_customer_from_db_before_ucs<F, Req, D>( async fn populate_connector_customer_from_db_before_ucs<D, F>(
state: &SessionState, state: &SessionState,
router_data: &mut RouterData<F, Req, PaymentsResponseData>,
connector_label: Option<&str>, connector_label: Option<&str>,
payment_data: &D, payment_data: &D,
customer: &Option<domain::Customer>, customer: &Option<domain::Customer>,
merchant_connector_account: &MerchantConnectorAccountType, merchant_connector_account: &MerchantConnectorAccountType,
) -> RouterResult<bool> ) -> RouterResult<Option<String>>
where where
D: OperationSessionGetters<F>, D: OperationSessionGetters<F>,
{ {
let mut connector_customer_id_was_populated = false; let mut connector_customer_id_was_populated = None;
if let (Some(connector_label), Some(connector_name)) = ( if let (Some(connector_label), Some(connector_name)) = (
connector_label, connector_label,
@ -7955,8 +7954,7 @@ where
payment_data.get_payment_intent().payment_id.get_string_repr(), payment_data.get_payment_intent().payment_id.get_string_repr(),
connector_label connector_label
); );
router_data.connector_customer = Some(connector_customer_id.to_string()); connector_customer_id_was_populated = Some(connector_customer_id.to_string());
connector_customer_id_was_populated = true;
} }
None => { None => {
router_env::logger::info!( router_env::logger::info!(
@ -7978,14 +7976,14 @@ where
async fn save_connector_customer_id_after_ucs<F, Req>( async fn save_connector_customer_id_after_ucs<F, Req>(
state: &SessionState, state: &SessionState,
router_data: &RouterData<F, Req, PaymentsResponseData>, router_data: &RouterData<F, Req, PaymentsResponseData>,
connector_customer_id_was_populated_from_db: bool, connector_customer_id_was_populated_from_db: Option<String>,
connector_label: &Option<String>, connector_label: &Option<String>,
customer: &Option<domain::Customer>, customer: &Option<domain::Customer>,
merchant_context: &domain::MerchantContext, merchant_context: &domain::MerchantContext,
payment_id: String, payment_id: String,
) -> RouterResult<()> { ) -> RouterResult<()> {
// Process only if connector_customer_id was NOT already in DB // Process only if connector_customer_id was NOT already in DB
if !connector_customer_id_was_populated_from_db { if !connector_customer_id_was_populated_from_db.is_some() {
// Extract necessary fields and save if both are present // Extract necessary fields and save if both are present
match (&router_data.connector_customer, connector_label.as_ref()) { match (&router_data.connector_customer, connector_label.as_ref()) {
(Some(connector_customer_id), Some(connector_label_str)) => { (Some(connector_customer_id), Some(connector_label_str)) => {
@ -8019,7 +8017,6 @@ async fn save_connector_customer_id_after_ucs<F, Req>(
payment_id payment_id
); );
} }
Ok(()) Ok(())
} }
@ -8188,7 +8185,6 @@ where
let connector_customer_id_was_populated_from_db = let connector_customer_id_was_populated_from_db =
populate_connector_customer_from_db_before_ucs( populate_connector_customer_from_db_before_ucs(
state, state,
&mut router_data,
connector_label.as_deref(), connector_label.as_deref(),
payment_data, payment_data,
customer, customer,
@ -8196,6 +8192,12 @@ where
) )
.await?; .await?;
connector_customer_id_was_populated_from_db
.as_ref()
.map(|id| {
router_data.connector_customer = Some(id.clone());
});
// Based on the preprocessing response, decide whether to continue with UCS call // Based on the preprocessing response, decide whether to continue with UCS call
if should_continue { if should_continue {
router_data router_data
@ -8380,17 +8382,20 @@ where
// Populate connector_customer_id from database for shadow UCS call // Populate connector_customer_id from database for shadow UCS call
// Use the pre-calculated connector_label // Use the pre-calculated connector_label
// Track whether ID was found in DB to avoid redundant save later // Track whether ID was found in DB to avoid redundant save later
let _connector_customer_id_was_populated_from_db = let connector_customer_id_was_populated_from_db =
populate_connector_customer_from_db_before_ucs( populate_connector_customer_from_db_before_ucs(
state, state,
&mut unified_connector_service_router_data,
unified_connector_service_connector_label.as_deref(), unified_connector_service_connector_label.as_deref(),
payment_data, payment_data,
customer, customer,
&merchant_connector_account, &merchant_connector_account,
) )
.await .await
.unwrap_or(false); // Don't fail the main flow if shadow UCS populate fails .unwrap_or_default(); // Don't fail the main flow if shadow UCS populate fails
connector_customer_id_was_populated_from_db.map(|id| {
unified_connector_service_router_data.connector_customer = Some(id);
});
let lineage_ids = grpc_client::LineageIds::new( let lineage_ids = grpc_client::LineageIds::new(
business_profile.merchant_id.clone(), business_profile.merchant_id.clone(),

View File

@ -60,7 +60,7 @@ use crate::{
events::connector_api_logs::ConnectorEvent, events::connector_api_logs::ConnectorEvent,
headers::{CONTENT_TYPE, X_REQUEST_ID}, headers::{CONTENT_TYPE, X_REQUEST_ID},
routes::SessionState, routes::SessionState,
types::transformers::ForeignTryFrom, types::{transformers::ForeignTryFrom, UcsResponseData},
}; };
pub mod transformers; pub mod transformers;
@ -69,13 +69,7 @@ pub mod transformers;
pub use transformers::{WebhookTransformData, WebhookTransformationStatus}; pub use transformers::{WebhookTransformData, WebhookTransformationStatus};
/// Type alias for return type used by unified connector service response handlers /// Type alias for return type used by unified connector service response handlers
type UnifiedConnectorServiceResult = CustomResult< type UnifiedConnectorServiceResult = CustomResult<UcsResponseData, UnifiedConnectorServiceError>;
(
Result<(PaymentsResponseData, AttemptStatus), ErrorResponse>,
u16,
),
UnifiedConnectorServiceError,
>;
/// Checks if the Unified Connector Service (UCS) is available for use /// Checks if the Unified Connector Service (UCS) is available for use
async fn check_ucs_availability(state: &SessionState) -> UcsAvailability { async fn check_ucs_availability(state: &SessionState) -> UcsAvailability {
@ -759,8 +753,7 @@ pub fn build_unified_connector_service_external_vault_proxy_metadata(
} }
} }
pub fn handle_unified_connector_service_response_for_payment_authorize<F, Req>( pub fn handle_unified_connector_service_response_for_payment_authorize(
router_data: &mut RouterData<F, Req, PaymentsResponseData>,
response: PaymentServiceAuthorizeResponse, response: PaymentServiceAuthorizeResponse,
) -> UnifiedConnectorServiceResult { ) -> UnifiedConnectorServiceResult {
let status_code = transformers::convert_connector_service_status_code(response.status_code)?; let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
@ -770,17 +763,17 @@ pub fn handle_unified_connector_service_response_for_payment_authorize<F, Req>(
response.clone(), response.clone(),
)?; )?;
// Populate connector_customer_id from UCS state let connector_customer_id =
populate_connector_customer_id_from_ucs_state(router_data, response.state.as_ref()); extract_connector_customer_id_from_ucs_state(response.state.as_ref());
let connector_response =
extract_connector_response_from_ucs(response.connector_response.as_ref());
// Populate connector_response from UCS response (log errors, don't fail) Ok(UcsResponseData {
populate_connector_response_from_ucs(router_data, response.connector_response.as_ref()) router_data_response,
.inspect_err(|err| { status_code,
router_env::logger::warn!("Failed to populate connector_response from UCS: {:?}", err); connector_customer_id,
connector_response,
}) })
.ok();
Ok((router_data_response, status_code))
} }
pub fn handle_unified_connector_service_response_for_payment_capture( pub fn handle_unified_connector_service_response_for_payment_capture(
@ -791,11 +784,15 @@ pub fn handle_unified_connector_service_response_for_payment_capture(
let router_data_response = let router_data_response =
Result::<(PaymentsResponseData, AttemptStatus), ErrorResponse>::foreign_try_from(response)?; Result::<(PaymentsResponseData, AttemptStatus), ErrorResponse>::foreign_try_from(response)?;
Ok((router_data_response, status_code)) Ok(UcsResponseData {
router_data_response,
status_code,
connector_customer_id: None,
connector_response: None,
})
} }
pub fn handle_unified_connector_service_response_for_payment_register<F, Req>( pub fn handle_unified_connector_service_response_for_payment_register(
router_data: &mut RouterData<F, Req, PaymentsResponseData>,
response: payments_grpc::PaymentServiceRegisterResponse, response: payments_grpc::PaymentServiceRegisterResponse,
) -> UnifiedConnectorServiceResult { ) -> UnifiedConnectorServiceResult {
let status_code = transformers::convert_connector_service_status_code(response.status_code)?; let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
@ -805,14 +802,18 @@ pub fn handle_unified_connector_service_response_for_payment_register<F, Req>(
response.clone(), response.clone(),
)?; )?;
// Populate connector_customer_id from UCS state let connector_customer_id =
populate_connector_customer_id_from_ucs_state(router_data, response.state.as_ref()); extract_connector_customer_id_from_ucs_state(response.state.as_ref());
Ok((router_data_response, status_code)) Ok(UcsResponseData {
router_data_response,
status_code,
connector_customer_id,
connector_response: None, // Register doesn't need connector_response
})
} }
pub fn handle_unified_connector_service_response_for_payment_repeat<F, Req>( pub fn handle_unified_connector_service_response_for_payment_repeat(
router_data: &mut RouterData<F, Req, PaymentsResponseData>,
response: payments_grpc::PaymentServiceRepeatEverythingResponse, response: payments_grpc::PaymentServiceRepeatEverythingResponse,
) -> UnifiedConnectorServiceResult { ) -> UnifiedConnectorServiceResult {
let status_code = transformers::convert_connector_service_status_code(response.status_code)?; let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
@ -822,45 +823,46 @@ pub fn handle_unified_connector_service_response_for_payment_repeat<F, Req>(
response.clone(), response.clone(),
)?; )?;
// Populate connector_customer_id from UCS state let connector_customer_id =
populate_connector_customer_id_from_ucs_state(router_data, response.state.as_ref()); extract_connector_customer_id_from_ucs_state(response.state.as_ref());
let connector_response =
extract_connector_response_from_ucs(response.connector_response.as_ref());
// Populate connector_response from UCS response (log errors, don't fail) Ok(UcsResponseData {
populate_connector_response_from_ucs(router_data, response.connector_response.as_ref()) router_data_response,
.inspect_err(|err| { status_code,
router_env::logger::warn!("Failed to populate connector_response from UCS: {:?}", err); connector_customer_id,
connector_response,
}) })
.ok();
Ok((router_data_response, status_code))
} }
/// Extracts and populates connector_customer_id from UCS state into router_data /// Extracts connector_customer_id from UCS state
pub fn populate_connector_customer_id_from_ucs_state<F, Req, Resp>( pub fn extract_connector_customer_id_from_ucs_state(
router_data: &mut RouterData<F, Req, Resp>,
ucs_state: Option<&payments_grpc::ConnectorState>, ucs_state: Option<&payments_grpc::ConnectorState>,
) { ) -> Option<String> {
ucs_state.map(|state| { ucs_state.and_then(|state| {
state state
.connector_customer_id .connector_customer_id
.as_ref() .as_ref()
.map(|id| router_data.connector_customer = Some(id.to_string())); .map(|id| id.to_string())
}); })
} }
/// Extracts and populates connector_response from UCS response into router_data /// Extracts connector_response from UCS response
pub fn populate_connector_response_from_ucs<F, Req, Resp>( pub fn extract_connector_response_from_ucs(
router_data: &mut RouterData<F, Req, Resp>,
connector_response: Option<&payments_grpc::ConnectorResponseData>, connector_response: Option<&payments_grpc::ConnectorResponseData>,
) -> RouterResult<()> { ) -> Option<hyperswitch_domain_models::router_data::ConnectorResponseData> {
router_data.connector_response = connector_response connector_response.and_then(|data| {
.map(|data| {
<hyperswitch_domain_models::router_data::ConnectorResponseData as hyperswitch_interfaces::helpers::ForeignTryFrom<payments_grpc::ConnectorResponseData>>::foreign_try_from(data.clone()) <hyperswitch_domain_models::router_data::ConnectorResponseData as hyperswitch_interfaces::helpers::ForeignTryFrom<payments_grpc::ConnectorResponseData>>::foreign_try_from(data.clone())
.map_err(|e| {
logger::warn!(
error=?e,
"Failed to deserialize connector_response from UCS"
);
e
})
.ok()
}) })
.transpose()
.change_context(errors::ApiErrorResponse::InternalServerError)
.attach_printable("Failed to deserialize connector_response from UCS")?;
Ok(())
} }
pub fn handle_unified_connector_service_response_for_payment_cancel( pub fn handle_unified_connector_service_response_for_payment_cancel(
@ -871,7 +873,12 @@ pub fn handle_unified_connector_service_response_for_payment_cancel(
let router_data_response = let router_data_response =
Result::<(PaymentsResponseData, AttemptStatus), ErrorResponse>::foreign_try_from(response)?; Result::<(PaymentsResponseData, AttemptStatus), ErrorResponse>::foreign_try_from(response)?;
Ok((router_data_response, status_code)) Ok(UcsResponseData {
router_data_response,
status_code,
connector_customer_id: None,
connector_response: None,
})
} }
pub fn build_webhook_secrets_from_merchant_connector_account( pub fn build_webhook_secrets_from_merchant_connector_account(

View File

@ -721,6 +721,15 @@ pub struct PspTokenResult {
pub token: Result<String, ErrorResponse>, pub token: Result<String, ErrorResponse>,
} }
/// Data extracted from UCS response
pub struct UcsResponseData {
pub router_data_response:
Result<(PaymentsResponseData, common_enums::AttemptStatus), ErrorResponse>,
pub status_code: u16,
pub connector_customer_id: Option<String>,
pub connector_response: Option<ConnectorResponseData>,
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Redirection { pub enum Redirection {
Redirect, Redirect,