fix: Map attempt_status_unspecified to None instead of Unresolved for HS<>UCS ErrorResponse (#9445)

Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
Saptak Dutta
2025-09-24 19:04:51 +05:30
committed by GitHub
parent ecb27b07c6
commit e0fa7e9b6c
7 changed files with 122 additions and 107 deletions

View File

@ -888,14 +888,17 @@ async fn call_unified_connector_service_authorize(
let payment_authorize_response = response.into_inner(); let payment_authorize_response = response.into_inner();
let (status, router_data_response, status_code) = let (router_data_response, status_code) =
handle_unified_connector_service_response_for_payment_authorize( handle_unified_connector_service_response_for_payment_authorize(
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)| {
router_data.status = status; router_data.status = status;
response
});
router_data.response = router_data_response; router_data.response = router_data_response;
router_data.raw_connector_response = payment_authorize_response router_data.raw_connector_response = payment_authorize_response
.raw_connector_response .raw_connector_response
@ -972,14 +975,17 @@ async fn call_unified_connector_service_repeat_payment(
let payment_repeat_response = response.into_inner(); let payment_repeat_response = response.into_inner();
let (status, router_data_response, status_code) = let (router_data_response, status_code) =
handle_unified_connector_service_response_for_payment_repeat( handle_unified_connector_service_response_for_payment_repeat(
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)| {
router_data.status = status; router_data.status = status;
response
});
router_data.response = router_data_response; router_data.response = router_data_response;
router_data.raw_connector_response = payment_repeat_response router_data.raw_connector_response = payment_repeat_response
.raw_connector_response .raw_connector_response

View File

@ -428,14 +428,17 @@ impl Feature<api::ExternalVaultProxy, types::ExternalVaultProxyPaymentsData>
let payment_authorize_response = response.into_inner(); let payment_authorize_response = response.into_inner();
let (status, router_data_response, status_code) = let (router_data_response, status_code) =
unified_connector_service::handle_unified_connector_service_response_for_payment_authorize( unified_connector_service::handle_unified_connector_service_response_for_payment_authorize(
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)|{
router_data.status = status; router_data.status = status;
response
});
router_data.response = router_data_response; router_data.response = router_data_response;
router_data.raw_connector_response = payment_authorize_response router_data.raw_connector_response = payment_authorize_response
.raw_connector_response .raw_connector_response

View File

@ -295,14 +295,17 @@ impl Feature<api::PSync, types::PaymentsSyncData>
let payment_get_response = response.into_inner(); let payment_get_response = response.into_inner();
let (status, router_data_response, status_code) = let (router_data_response, status_code) =
handle_unified_connector_service_response_for_payment_get( handle_unified_connector_service_response_for_payment_get(
payment_get_response.clone(), payment_get_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)| {
router_data.status = status; router_data.status = status;
response
});
router_data.response = router_data_response; router_data.response = router_data_response;
router_data.raw_connector_response = payment_get_response router_data.raw_connector_response = payment_get_response
.raw_connector_response .raw_connector_response

View File

@ -317,14 +317,17 @@ impl Feature<api::SetupMandate, types::SetupMandateRequestData> for types::Setup
let payment_register_response = response.into_inner(); let payment_register_response = response.into_inner();
let (status, router_data_response, status_code) = let (router_data_response, status_code) =
handle_unified_connector_service_response_for_payment_register( handle_unified_connector_service_response_for_payment_register(
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)| {
router_data.status = status; router_data.status = status;
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(status_code);

View File

@ -55,6 +55,15 @@ pub mod transformers;
// Re-export webhook transformer types for easier access // Re-export webhook transformer types for easier access
pub use transformers::WebhookTransformData; pub use transformers::WebhookTransformData;
/// Type alias for return type used by unified connector service response handlers
type UnifiedConnectorServiceResult = CustomResult<
(
Result<(PaymentsResponseData, AttemptStatus), ErrorResponse>,
u16,
),
UnifiedConnectorServiceError,
>;
/// Generic version of should_call_unified_connector_service that works with any type /// Generic version of should_call_unified_connector_service that works with any type
/// implementing OperationSessionGetters trait /// implementing OperationSessionGetters trait
pub async fn should_call_unified_connector_service<F: Clone, T, D>( pub async fn should_call_unified_connector_service<F: Clone, T, D>(
@ -570,82 +579,46 @@ pub fn build_unified_connector_service_external_vault_proxy_metadata(
pub fn handle_unified_connector_service_response_for_payment_authorize( pub fn handle_unified_connector_service_response_for_payment_authorize(
response: PaymentServiceAuthorizeResponse, response: PaymentServiceAuthorizeResponse,
) -> CustomResult< ) -> UnifiedConnectorServiceResult {
(
AttemptStatus,
Result<PaymentsResponseData, ErrorResponse>,
u16,
),
UnifiedConnectorServiceError,
> {
let status = AttemptStatus::foreign_try_from(response.status())?;
let status_code = transformers::convert_connector_service_status_code(response.status_code)?; let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
let router_data_response = let router_data_response =
Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?; Result::<(PaymentsResponseData, AttemptStatus), ErrorResponse>::foreign_try_from(response)?;
Ok((status, router_data_response, status_code)) Ok((router_data_response, status_code))
} }
pub fn handle_unified_connector_service_response_for_payment_get( pub fn handle_unified_connector_service_response_for_payment_get(
response: payments_grpc::PaymentServiceGetResponse, response: payments_grpc::PaymentServiceGetResponse,
) -> CustomResult< ) -> UnifiedConnectorServiceResult {
(
AttemptStatus,
Result<PaymentsResponseData, ErrorResponse>,
u16,
),
UnifiedConnectorServiceError,
> {
let status = AttemptStatus::foreign_try_from(response.status())?;
let status_code = transformers::convert_connector_service_status_code(response.status_code)?; let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
let router_data_response = let router_data_response =
Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?; Result::<(PaymentsResponseData, AttemptStatus), ErrorResponse>::foreign_try_from(response)?;
Ok((status, router_data_response, status_code)) Ok((router_data_response, status_code))
} }
pub fn handle_unified_connector_service_response_for_payment_register( pub fn handle_unified_connector_service_response_for_payment_register(
response: payments_grpc::PaymentServiceRegisterResponse, response: payments_grpc::PaymentServiceRegisterResponse,
) -> CustomResult< ) -> UnifiedConnectorServiceResult {
(
AttemptStatus,
Result<PaymentsResponseData, ErrorResponse>,
u16,
),
UnifiedConnectorServiceError,
> {
let status = AttemptStatus::foreign_try_from(response.status())?;
let status_code = transformers::convert_connector_service_status_code(response.status_code)?; let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
let router_data_response = let router_data_response =
Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?; Result::<(PaymentsResponseData, AttemptStatus), ErrorResponse>::foreign_try_from(response)?;
Ok((status, router_data_response, status_code)) Ok((router_data_response, status_code))
} }
pub fn handle_unified_connector_service_response_for_payment_repeat( pub fn handle_unified_connector_service_response_for_payment_repeat(
response: payments_grpc::PaymentServiceRepeatEverythingResponse, response: payments_grpc::PaymentServiceRepeatEverythingResponse,
) -> CustomResult< ) -> UnifiedConnectorServiceResult {
(
AttemptStatus,
Result<PaymentsResponseData, ErrorResponse>,
u16,
),
UnifiedConnectorServiceError,
> {
let status = AttemptStatus::foreign_try_from(response.status())?;
let status_code = transformers::convert_connector_service_status_code(response.status_code)?; let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
let router_data_response = let router_data_response =
Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?; Result::<(PaymentsResponseData, AttemptStatus), ErrorResponse>::foreign_try_from(response)?;
Ok((status, router_data_response, status_code)) Ok((router_data_response, status_code))
} }
pub fn build_webhook_secrets_from_merchant_connector_account( pub fn build_webhook_secrets_from_merchant_connector_account(

View File

@ -512,15 +512,13 @@ impl ForeignTryFrom<&RouterData<Authorize, PaymentsAuthorizeData, PaymentsRespon
} }
impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse> impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
for Result<PaymentsResponseData, ErrorResponse> for Result<(PaymentsResponseData, AttemptStatus), ErrorResponse>
{ {
type Error = error_stack::Report<UnifiedConnectorServiceError>; type Error = error_stack::Report<UnifiedConnectorServiceError>;
fn foreign_try_from( fn foreign_try_from(
response: payments_grpc::PaymentServiceAuthorizeResponse, response: payments_grpc::PaymentServiceAuthorizeResponse,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
let status = AttemptStatus::foreign_try_from(response.status())?;
let connector_response_reference_id = let connector_response_reference_id =
response.response_ref_id.as_ref().and_then(|identifier| { response.response_ref_id.as_ref().and_then(|identifier| {
identifier identifier
@ -573,12 +571,17 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
let status_code = convert_connector_service_status_code(response.status_code)?; let status_code = convert_connector_service_status_code(response.status_code)?;
let response = if response.error_code.is_some() { let response = if response.error_code.is_some() {
let attempt_status = match response.status() {
payments_grpc::PaymentStatus::AttemptStatusUnspecified => None,
_ => Some(AttemptStatus::foreign_try_from(response.status())?),
};
Err(ErrorResponse { Err(ErrorResponse {
code: response.error_code().to_owned(), code: response.error_code().to_owned(),
message: response.error_message().to_owned(), message: response.error_message().to_owned(),
reason: Some(response.error_message().to_owned()), reason: Some(response.error_message().to_owned()),
status_code, status_code,
attempt_status: Some(status), attempt_status,
connector_transaction_id: connector_response_reference_id, connector_transaction_id: connector_response_reference_id,
network_decline_code: None, network_decline_code: None,
network_advice_code: None, network_advice_code: None,
@ -586,7 +589,10 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
connector_metadata: None, connector_metadata: None,
}) })
} else { } else {
Ok(PaymentsResponseData::TransactionResponse { let status = AttemptStatus::foreign_try_from(response.status())?;
Ok((
PaymentsResponseData::TransactionResponse {
resource_id, resource_id,
redirection_data: Box::new(redirection_data), redirection_data: Box::new(redirection_data),
mandate_reference: Box::new(None), mandate_reference: Box::new(None),
@ -595,7 +601,9 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
connector_response_reference_id, connector_response_reference_id,
incremental_authorization_allowed: response.incremental_authorization_allowed, incremental_authorization_allowed: response.incremental_authorization_allowed,
charges: None, charges: None,
}) },
status,
))
}; };
Ok(response) Ok(response)
@ -603,15 +611,13 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
} }
impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse> impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
for Result<PaymentsResponseData, ErrorResponse> for Result<(PaymentsResponseData, AttemptStatus), ErrorResponse>
{ {
type Error = error_stack::Report<UnifiedConnectorServiceError>; type Error = error_stack::Report<UnifiedConnectorServiceError>;
fn foreign_try_from( fn foreign_try_from(
response: payments_grpc::PaymentServiceGetResponse, response: payments_grpc::PaymentServiceGetResponse,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
let status = AttemptStatus::foreign_try_from(response.status())?;
let connector_response_reference_id = let connector_response_reference_id =
response.response_ref_id.as_ref().and_then(|identifier| { response.response_ref_id.as_ref().and_then(|identifier| {
identifier identifier
@ -635,12 +641,17 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
}; };
let response = if response.error_code.is_some() { let response = if response.error_code.is_some() {
let attempt_status = match response.status() {
payments_grpc::PaymentStatus::AttemptStatusUnspecified => None,
_ => Some(AttemptStatus::foreign_try_from(response.status())?),
};
Err(ErrorResponse { Err(ErrorResponse {
code: response.error_code().to_owned(), code: response.error_code().to_owned(),
message: response.error_message().to_owned(), message: response.error_message().to_owned(),
reason: Some(response.error_message().to_owned()), reason: Some(response.error_message().to_owned()),
status_code, status_code,
attempt_status: Some(status), attempt_status,
connector_transaction_id: connector_response_reference_id, connector_transaction_id: connector_response_reference_id,
network_decline_code: None, network_decline_code: None,
network_advice_code: None, network_advice_code: None,
@ -648,7 +659,10 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
connector_metadata: None, connector_metadata: None,
}) })
} else { } else {
Ok(PaymentsResponseData::TransactionResponse { let status = AttemptStatus::foreign_try_from(response.status())?;
Ok((
PaymentsResponseData::TransactionResponse {
resource_id, resource_id,
redirection_data: Box::new(None), redirection_data: Box::new(None),
mandate_reference: Box::new(response.mandate_reference.map(|grpc_mandate| { mandate_reference: Box::new(response.mandate_reference.map(|grpc_mandate| {
@ -664,7 +678,9 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
connector_response_reference_id, connector_response_reference_id,
incremental_authorization_allowed: None, incremental_authorization_allowed: None,
charges: None, charges: None,
}) },
status,
))
}; };
Ok(response) Ok(response)
@ -672,15 +688,13 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
} }
impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse> impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
for Result<PaymentsResponseData, ErrorResponse> for Result<(PaymentsResponseData, AttemptStatus), ErrorResponse>
{ {
type Error = error_stack::Report<UnifiedConnectorServiceError>; type Error = error_stack::Report<UnifiedConnectorServiceError>;
fn foreign_try_from( fn foreign_try_from(
response: payments_grpc::PaymentServiceRegisterResponse, response: payments_grpc::PaymentServiceRegisterResponse,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
let status = AttemptStatus::foreign_try_from(response.status())?;
let connector_response_reference_id = let connector_response_reference_id =
response.response_ref_id.as_ref().and_then(|identifier| { response.response_ref_id.as_ref().and_then(|identifier| {
identifier identifier
@ -698,12 +712,16 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
let status_code = convert_connector_service_status_code(response.status_code)?; let status_code = convert_connector_service_status_code(response.status_code)?;
let response = if response.error_code.is_some() { let response = if response.error_code.is_some() {
let attempt_status = match response.status() {
payments_grpc::PaymentStatus::AttemptStatusUnspecified => None,
_ => Some(AttemptStatus::foreign_try_from(response.status())?),
};
Err(ErrorResponse { Err(ErrorResponse {
code: response.error_code().to_owned(), code: response.error_code().to_owned(),
message: response.error_message().to_owned(), message: response.error_message().to_owned(),
reason: Some(response.error_message().to_owned()), reason: Some(response.error_message().to_owned()),
status_code, status_code,
attempt_status: Some(status), attempt_status,
connector_transaction_id: connector_response_reference_id, connector_transaction_id: connector_response_reference_id,
network_decline_code: None, network_decline_code: None,
network_advice_code: None, network_advice_code: None,
@ -711,7 +729,9 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
connector_metadata: None, connector_metadata: None,
}) })
} else { } else {
Ok(PaymentsResponseData::TransactionResponse { let status = AttemptStatus::foreign_try_from(response.status())?;
Ok((PaymentsResponseData::TransactionResponse {
resource_id: response.registration_id.as_ref().and_then(|identifier| { resource_id: response.registration_id.as_ref().and_then(|identifier| {
identifier identifier
.id_type .id_type
@ -748,7 +768,7 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
connector_response_reference_id, connector_response_reference_id,
incremental_authorization_allowed: response.incremental_authorization_allowed, incremental_authorization_allowed: response.incremental_authorization_allowed,
charges: None, charges: None,
}) }, status))
}; };
Ok(response) Ok(response)
@ -756,15 +776,13 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
} }
impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse> impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
for Result<PaymentsResponseData, ErrorResponse> for Result<(PaymentsResponseData, AttemptStatus), ErrorResponse>
{ {
type Error = error_stack::Report<UnifiedConnectorServiceError>; type Error = error_stack::Report<UnifiedConnectorServiceError>;
fn foreign_try_from( fn foreign_try_from(
response: payments_grpc::PaymentServiceRepeatEverythingResponse, response: payments_grpc::PaymentServiceRepeatEverythingResponse,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
let status = AttemptStatus::foreign_try_from(response.status())?;
let connector_response_reference_id = let connector_response_reference_id =
response.response_ref_id.as_ref().and_then(|identifier| { response.response_ref_id.as_ref().and_then(|identifier| {
identifier identifier
@ -790,12 +808,16 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
let status_code = convert_connector_service_status_code(response.status_code)?; let status_code = convert_connector_service_status_code(response.status_code)?;
let response = if response.error_code.is_some() { let response = if response.error_code.is_some() {
let attempt_status = match response.status() {
payments_grpc::PaymentStatus::AttemptStatusUnspecified => None,
_ => Some(AttemptStatus::foreign_try_from(response.status())?),
};
Err(ErrorResponse { Err(ErrorResponse {
code: response.error_code().to_owned(), code: response.error_code().to_owned(),
message: response.error_message().to_owned(), message: response.error_message().to_owned(),
reason: Some(response.error_message().to_owned()), reason: Some(response.error_message().to_owned()),
status_code, status_code,
attempt_status: Some(status), attempt_status,
connector_transaction_id: transaction_id, connector_transaction_id: transaction_id,
network_decline_code: None, network_decline_code: None,
network_advice_code: None, network_advice_code: None,
@ -803,7 +825,9 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
connector_metadata: None, connector_metadata: None,
}) })
} else { } else {
Ok(PaymentsResponseData::TransactionResponse { let status = AttemptStatus::foreign_try_from(response.status())?;
Ok((PaymentsResponseData::TransactionResponse {
resource_id: match transaction_id.as_ref() { resource_id: match transaction_id.as_ref() {
Some(transaction_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(transaction_id.clone()), Some(transaction_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(transaction_id.clone()),
None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId, None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId,
@ -815,7 +839,7 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
connector_response_reference_id, connector_response_reference_id,
incremental_authorization_allowed: None, incremental_authorization_allowed: None,
charges: None, charges: None,
}) }, status))
}; };
Ok(response) Ok(response)

View File

@ -170,7 +170,7 @@ where
} }
}?; }?;
let (status, router_data_response, status_code) = let (router_data_response, status_code) =
unified_connector_service::handle_unified_connector_service_response_for_payment_get( unified_connector_service::handle_unified_connector_service_response_for_payment_get(
payment_get_response.clone(), payment_get_response.clone(),
) )
@ -178,7 +178,10 @@ where
.attach_printable("Failed to process UCS webhook response using PSync handler")?; .attach_printable("Failed to process UCS webhook response using PSync handler")?;
let mut updated_router_data = router_data; let mut updated_router_data = router_data;
let router_data_response = router_data_response.map(|(response, status)| {
updated_router_data.status = status; updated_router_data.status = status;
response
});
let _ = router_data_response.map_err(|error_response| { let _ = router_data_response.map_err(|error_response| {
updated_router_data.response = Err(error_response); updated_router_data.response = Err(error_response);