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 (status, router_data_response, status_code) =
let (router_data_response, status_code) =
handle_unified_connector_service_response_for_payment_authorize(
payment_authorize_response.clone(),
)
.change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to deserialize UCS response")?;
router_data.status = status;
let router_data_response = router_data_response.map(|(response, status)| {
router_data.status = status;
response
});
router_data.response = router_data_response;
router_data.raw_connector_response = payment_authorize_response
.raw_connector_response
@ -972,14 +975,17 @@ async fn call_unified_connector_service_repeat_payment(
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(
payment_repeat_response.clone(),
)
.change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to deserialize UCS response")?;
router_data.status = status;
let router_data_response = router_data_response.map(|(response, status)| {
router_data.status = status;
response
});
router_data.response = router_data_response;
router_data.raw_connector_response = payment_repeat_response
.raw_connector_response

View File

@ -428,14 +428,17 @@ impl Feature<api::ExternalVaultProxy, types::ExternalVaultProxyPaymentsData>
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(
payment_authorize_response.clone(),
)
.change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to deserialize UCS response")?;
router_data.status = status;
let router_data_response = router_data_response.map(|(response, status)|{
router_data.status = status;
response
});
router_data.response = router_data_response;
router_data.raw_connector_response = payment_authorize_response
.raw_connector_response

View File

@ -295,14 +295,17 @@ impl Feature<api::PSync, types::PaymentsSyncData>
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(
payment_get_response.clone(),
)
.change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to deserialize UCS response")?;
router_data.status = status;
let router_data_response = router_data_response.map(|(response, status)| {
router_data.status = status;
response
});
router_data.response = router_data_response;
router_data.raw_connector_response = payment_get_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 (status, router_data_response, status_code) =
let (router_data_response, status_code) =
handle_unified_connector_service_response_for_payment_register(
payment_register_response.clone(),
)
.change_context(ApiErrorResponse::InternalServerError)
.attach_printable("Failed to deserialize UCS response")?;
router_data.status = status;
let router_data_response = router_data_response.map(|(response, status)| {
router_data.status = status;
response
});
router_data.response = router_data_response;
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
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
/// implementing OperationSessionGetters trait
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(
response: PaymentServiceAuthorizeResponse,
) -> CustomResult<
(
AttemptStatus,
Result<PaymentsResponseData, ErrorResponse>,
u16,
),
UnifiedConnectorServiceError,
> {
let status = AttemptStatus::foreign_try_from(response.status())?;
) -> UnifiedConnectorServiceResult {
let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
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(
response: payments_grpc::PaymentServiceGetResponse,
) -> CustomResult<
(
AttemptStatus,
Result<PaymentsResponseData, ErrorResponse>,
u16,
),
UnifiedConnectorServiceError,
> {
let status = AttemptStatus::foreign_try_from(response.status())?;
) -> UnifiedConnectorServiceResult {
let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
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(
response: payments_grpc::PaymentServiceRegisterResponse,
) -> CustomResult<
(
AttemptStatus,
Result<PaymentsResponseData, ErrorResponse>,
u16,
),
UnifiedConnectorServiceError,
> {
let status = AttemptStatus::foreign_try_from(response.status())?;
) -> UnifiedConnectorServiceResult {
let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
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(
response: payments_grpc::PaymentServiceRepeatEverythingResponse,
) -> CustomResult<
(
AttemptStatus,
Result<PaymentsResponseData, ErrorResponse>,
u16,
),
UnifiedConnectorServiceError,
> {
let status = AttemptStatus::foreign_try_from(response.status())?;
) -> UnifiedConnectorServiceResult {
let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
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(

View File

@ -512,15 +512,13 @@ impl ForeignTryFrom<&RouterData<Authorize, PaymentsAuthorizeData, PaymentsRespon
}
impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
for Result<PaymentsResponseData, ErrorResponse>
for Result<(PaymentsResponseData, AttemptStatus), ErrorResponse>
{
type Error = error_stack::Report<UnifiedConnectorServiceError>;
fn foreign_try_from(
response: payments_grpc::PaymentServiceAuthorizeResponse,
) -> Result<Self, Self::Error> {
let status = AttemptStatus::foreign_try_from(response.status())?;
let connector_response_reference_id =
response.response_ref_id.as_ref().and_then(|identifier| {
identifier
@ -573,12 +571,17 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
let status_code = convert_connector_service_status_code(response.status_code)?;
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 {
code: response.error_code().to_owned(),
message: response.error_message().to_owned(),
reason: Some(response.error_message().to_owned()),
status_code,
attempt_status: Some(status),
attempt_status,
connector_transaction_id: connector_response_reference_id,
network_decline_code: None,
network_advice_code: None,
@ -586,16 +589,21 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
connector_metadata: None,
})
} else {
Ok(PaymentsResponseData::TransactionResponse {
resource_id,
redirection_data: Box::new(redirection_data),
mandate_reference: Box::new(None),
connector_metadata,
network_txn_id: response.network_txn_id.clone(),
connector_response_reference_id,
incremental_authorization_allowed: response.incremental_authorization_allowed,
charges: None,
})
let status = AttemptStatus::foreign_try_from(response.status())?;
Ok((
PaymentsResponseData::TransactionResponse {
resource_id,
redirection_data: Box::new(redirection_data),
mandate_reference: Box::new(None),
connector_metadata,
network_txn_id: response.network_txn_id.clone(),
connector_response_reference_id,
incremental_authorization_allowed: response.incremental_authorization_allowed,
charges: None,
},
status,
))
};
Ok(response)
@ -603,15 +611,13 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
}
impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
for Result<PaymentsResponseData, ErrorResponse>
for Result<(PaymentsResponseData, AttemptStatus), ErrorResponse>
{
type Error = error_stack::Report<UnifiedConnectorServiceError>;
fn foreign_try_from(
response: payments_grpc::PaymentServiceGetResponse,
) -> Result<Self, Self::Error> {
let status = AttemptStatus::foreign_try_from(response.status())?;
let connector_response_reference_id =
response.response_ref_id.as_ref().and_then(|identifier| {
identifier
@ -635,12 +641,17 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
};
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 {
code: response.error_code().to_owned(),
message: response.error_message().to_owned(),
reason: Some(response.error_message().to_owned()),
status_code,
attempt_status: Some(status),
attempt_status,
connector_transaction_id: connector_response_reference_id,
network_decline_code: None,
network_advice_code: None,
@ -648,23 +659,28 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
connector_metadata: None,
})
} else {
Ok(PaymentsResponseData::TransactionResponse {
resource_id,
redirection_data: Box::new(None),
mandate_reference: Box::new(response.mandate_reference.map(|grpc_mandate| {
hyperswitch_domain_models::router_response_types::MandateReference {
connector_mandate_id: grpc_mandate.mandate_id,
payment_method_id: None,
mandate_metadata: None,
connector_mandate_request_reference_id: None,
}
})),
connector_metadata: None,
network_txn_id: response.network_txn_id.clone(),
connector_response_reference_id,
incremental_authorization_allowed: None,
charges: None,
})
let status = AttemptStatus::foreign_try_from(response.status())?;
Ok((
PaymentsResponseData::TransactionResponse {
resource_id,
redirection_data: Box::new(None),
mandate_reference: Box::new(response.mandate_reference.map(|grpc_mandate| {
hyperswitch_domain_models::router_response_types::MandateReference {
connector_mandate_id: grpc_mandate.mandate_id,
payment_method_id: None,
mandate_metadata: None,
connector_mandate_request_reference_id: None,
}
})),
connector_metadata: None,
network_txn_id: response.network_txn_id.clone(),
connector_response_reference_id,
incremental_authorization_allowed: None,
charges: None,
},
status,
))
};
Ok(response)
@ -672,15 +688,13 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
}
impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
for Result<PaymentsResponseData, ErrorResponse>
for Result<(PaymentsResponseData, AttemptStatus), ErrorResponse>
{
type Error = error_stack::Report<UnifiedConnectorServiceError>;
fn foreign_try_from(
response: payments_grpc::PaymentServiceRegisterResponse,
) -> Result<Self, Self::Error> {
let status = AttemptStatus::foreign_try_from(response.status())?;
let connector_response_reference_id =
response.response_ref_id.as_ref().and_then(|identifier| {
identifier
@ -698,12 +712,16 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
let status_code = convert_connector_service_status_code(response.status_code)?;
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 {
code: response.error_code().to_owned(),
message: response.error_message().to_owned(),
reason: Some(response.error_message().to_owned()),
status_code,
attempt_status: Some(status),
attempt_status,
connector_transaction_id: connector_response_reference_id,
network_decline_code: None,
network_advice_code: None,
@ -711,7 +729,9 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
connector_metadata: None,
})
} 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| {
identifier
.id_type
@ -748,7 +768,7 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
connector_response_reference_id,
incremental_authorization_allowed: response.incremental_authorization_allowed,
charges: None,
})
}, status))
};
Ok(response)
@ -756,15 +776,13 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
}
impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
for Result<PaymentsResponseData, ErrorResponse>
for Result<(PaymentsResponseData, AttemptStatus), ErrorResponse>
{
type Error = error_stack::Report<UnifiedConnectorServiceError>;
fn foreign_try_from(
response: payments_grpc::PaymentServiceRepeatEverythingResponse,
) -> Result<Self, Self::Error> {
let status = AttemptStatus::foreign_try_from(response.status())?;
let connector_response_reference_id =
response.response_ref_id.as_ref().and_then(|identifier| {
identifier
@ -790,12 +808,16 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
let status_code = convert_connector_service_status_code(response.status_code)?;
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 {
code: response.error_code().to_owned(),
message: response.error_message().to_owned(),
reason: Some(response.error_message().to_owned()),
status_code,
attempt_status: Some(status),
attempt_status,
connector_transaction_id: transaction_id,
network_decline_code: None,
network_advice_code: None,
@ -803,7 +825,9 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
connector_metadata: None,
})
} else {
Ok(PaymentsResponseData::TransactionResponse {
let status = AttemptStatus::foreign_try_from(response.status())?;
Ok((PaymentsResponseData::TransactionResponse {
resource_id: match transaction_id.as_ref() {
Some(transaction_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(transaction_id.clone()),
None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId,
@ -815,7 +839,7 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
connector_response_reference_id,
incremental_authorization_allowed: None,
charges: None,
})
}, status))
};
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(
payment_get_response.clone(),
)
@ -178,7 +178,10 @@ where
.attach_printable("Failed to process UCS webhook response using PSync handler")?;
let mut updated_router_data = router_data;
updated_router_data.status = status;
let router_data_response = router_data_response.map(|(response, status)| {
updated_router_data.status = status;
response
});
let _ = router_data_response.map_err(|error_response| {
updated_router_data.response = Err(error_response);