fix(connector): handle unexpected error response from bluesnap connector (#7120)

Co-authored-by: Anurag Singh <anurag.singh.001@Anurag-Singh-WPMHJ5619X.local>
Co-authored-by: Gnanasundari24 <118818938+Gnanasundari24@users.noreply.github.com>
This commit is contained in:
Anurag
2025-02-06 19:16:11 +05:30
committed by GitHub
parent 60ddddf24a
commit 8ae5267b91

View File

@ -11,7 +11,7 @@ use common_utils::{
request::{Method, Request, RequestBuilder, RequestContent}, request::{Method, Request, RequestBuilder, RequestContent},
types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector}, types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector},
}; };
use error_stack::{report, ResultExt}; use error_stack::{report, Report, ResultExt};
use hyperswitch_domain_models::{ use hyperswitch_domain_models::{
router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData}, router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
router_flow_types::{ router_flow_types::{
@ -55,9 +55,9 @@ use crate::{
utils::{ utils::{
construct_not_supported_error_report, convert_amount, construct_not_supported_error_report, convert_amount,
get_error_code_error_message_based_on_priority, get_header_key_value, get_http_header, get_error_code_error_message_based_on_priority, get_header_key_value, get_http_header,
to_connector_meta_from_secret, to_currency_lower_unit, ConnectorErrorType, handle_json_response_deserialization_failure, to_connector_meta_from_secret,
ConnectorErrorTypeMapping, ForeignTryFrom, PaymentsAuthorizeRequestData, to_currency_lower_unit, ConnectorErrorType, ConnectorErrorTypeMapping, ForeignTryFrom,
RefundsRequestData, RouterData as _, PaymentsAuthorizeRequestData, RefundsRequestData, RouterData as _,
}, },
}; };
@ -132,74 +132,84 @@ impl ConnectorCommon for Bluesnap {
event_builder: Option<&mut ConnectorEvent>, event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> { ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
logger::debug!(bluesnap_error_response=?res); logger::debug!(bluesnap_error_response=?res);
let response: bluesnap::BluesnapErrors = res let response_data: Result<
.response bluesnap::BluesnapErrors,
.parse_struct("BluesnapErrorResponse") Report<common_utils::errors::ParsingError>,
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?; > = res.response.parse_struct("BluesnapErrors");
event_builder.map(|i| i.set_error_response_body(&response)); match response_data {
router_env::logger::info!(connector_response=?response); Ok(response) => {
event_builder.map(|i| i.set_error_response_body(&response));
router_env::logger::info!(connector_response=?response);
let response_error_message = match response { let response_error_message = match response {
bluesnap::BluesnapErrors::Payment(error_response) => { bluesnap::BluesnapErrors::Payment(error_response) => {
let error_list = error_response.message.clone(); let error_list = error_response.message.clone();
let option_error_code_message = get_error_code_error_message_based_on_priority( let option_error_code_message =
self.clone(), get_error_code_error_message_based_on_priority(
error_list.into_iter().map(|errors| errors.into()).collect(), self.clone(),
); error_list.into_iter().map(|errors| errors.into()).collect(),
let reason = error_response );
.message let reason = error_response
.iter() .message
.map(|error| error.description.clone()) .iter()
.collect::<Vec<String>>() .map(|error| error.description.clone())
.join(" & "); .collect::<Vec<String>>()
ErrorResponse { .join(" & ");
status_code: res.status_code, ErrorResponse {
code: option_error_code_message status_code: res.status_code,
.clone() code: option_error_code_message
.map(|error_code_message| error_code_message.error_code) .clone()
.unwrap_or(NO_ERROR_CODE.to_string()), .map(|error_code_message| error_code_message.error_code)
message: option_error_code_message .unwrap_or(NO_ERROR_CODE.to_string()),
.map(|error_code_message| error_code_message.error_message) message: option_error_code_message
.unwrap_or(NO_ERROR_MESSAGE.to_string()), .map(|error_code_message| error_code_message.error_message)
reason: Some(reason), .unwrap_or(NO_ERROR_MESSAGE.to_string()),
attempt_status: None, reason: Some(reason),
connector_transaction_id: None, attempt_status: None,
} connector_transaction_id: None,
} }
bluesnap::BluesnapErrors::Auth(error_res) => ErrorResponse { }
status_code: res.status_code, bluesnap::BluesnapErrors::Auth(error_res) => ErrorResponse {
code: error_res.error_code.clone(), status_code: res.status_code,
message: error_res.error_name.clone().unwrap_or(error_res.error_code), code: error_res.error_code.clone(),
reason: Some(error_res.error_description), message: error_res.error_name.clone().unwrap_or(error_res.error_code),
attempt_status: None, reason: Some(error_res.error_description),
connector_transaction_id: None, attempt_status: None,
}, connector_transaction_id: None,
bluesnap::BluesnapErrors::General(error_response) => { },
let (error_res, attempt_status) = if res.status_code == 403 bluesnap::BluesnapErrors::General(error_response) => {
&& error_response.contains(BLUESNAP_TRANSACTION_NOT_FOUND) let (error_res, attempt_status) = if res.status_code == 403
{ && error_response.contains(BLUESNAP_TRANSACTION_NOT_FOUND)
( {
format!( (
"{} in bluesnap dashboard", format!(
REQUEST_TIMEOUT_PAYMENT_NOT_FOUND "{} in bluesnap dashboard",
), REQUEST_TIMEOUT_PAYMENT_NOT_FOUND
Some(enums::AttemptStatus::Failure), // when bluesnap throws 403 for payment not found, we update the payment status to failure. ),
) Some(enums::AttemptStatus::Failure), // when bluesnap throws 403 for payment not found, we update the payment status to failure.
} else { )
(error_response.clone(), None) } else {
(error_response.clone(), None)
};
ErrorResponse {
status_code: res.status_code,
code: NO_ERROR_CODE.to_string(),
message: error_response,
reason: Some(error_res),
attempt_status,
connector_transaction_id: None,
}
}
}; };
ErrorResponse { Ok(response_error_message)
status_code: res.status_code,
code: NO_ERROR_CODE.to_string(),
message: error_response,
reason: Some(error_res),
attempt_status,
connector_transaction_id: None,
}
} }
}; Err(error_msg) => {
Ok(response_error_message) event_builder.map(|event| event.set_error(serde_json::json!({"error": res.response.escape_ascii().to_string(), "status_code": res.status_code})));
router_env::logger::error!(deserialization_error =? error_msg);
handle_json_response_deserialization_failure(res, "bluesnap")
}
}
} }
} }