From 1d80949bef1228bf432dc445eaba15afccb030bd Mon Sep 17 00:00:00 2001 From: DEEPANSHU BANSAL <41580413+deepanshu-iiitu@users.noreply.github.com> Date: Wed, 20 Dec 2023 18:17:28 +0530 Subject: [PATCH] feat(connector): [BOA] Handle BOA 5XX errors (#3178) --- crates/router/src/connector/bankofamerica.rs | 69 +++++++++++++++++++ .../connector/bankofamerica/transformers.rs | 17 +++++ .../payments/operations/payment_response.rs | 30 ++++---- 3 files changed, 104 insertions(+), 12 deletions(-) diff --git a/crates/router/src/connector/bankofamerica.rs b/crates/router/src/connector/bankofamerica.rs index 8bee764b1f..18af4bda92 100644 --- a/crates/router/src/connector/bankofamerica.rs +++ b/crates/router/src/connector/bankofamerica.rs @@ -385,6 +385,33 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res) } + + fn get_5xx_error_response( + &self, + res: Response, + ) -> CustomResult { + let response: bankofamerica::BankOfAmericaServerErrorResponse = res + .response + .parse_struct("BankOfAmericaServerErrorResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + let attempt_status = match response.reason { + Some(reason) => match reason { + transformers::Reason::SystemError => Some(enums::AttemptStatus::Failure), + transformers::Reason::ServerTimeout | transformers::Reason::ServiceTimeout => None, + }, + None => None, + }; + Ok(ErrorResponse { + status_code: res.status_code, + reason: response.status.clone(), + code: response.status.unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: response + .message + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + attempt_status, + connector_transaction_id: None, + }) + } } impl ConnectorIntegration @@ -546,6 +573,27 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res) } + + fn get_5xx_error_response( + &self, + res: Response, + ) -> CustomResult { + let response: bankofamerica::BankOfAmericaServerErrorResponse = res + .response + .parse_struct("BankOfAmericaServerErrorResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + + Ok(ErrorResponse { + status_code: res.status_code, + reason: response.status.clone(), + code: response.status.unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: response + .message + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + attempt_status: None, + connector_transaction_id: None, + }) + } } impl ConnectorIntegration @@ -640,6 +688,27 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res) } + + fn get_5xx_error_response( + &self, + res: Response, + ) -> CustomResult { + let response: bankofamerica::BankOfAmericaServerErrorResponse = res + .response + .parse_struct("BankOfAmericaServerErrorResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + + Ok(ErrorResponse { + status_code: res.status_code, + reason: response.status.clone(), + code: response.status.unwrap_or(consts::NO_ERROR_CODE.to_string()), + message: response + .message + .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()), + attempt_status: None, + connector_transaction_id: None, + }) + } } impl ConnectorIntegration diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs index e7c0c7a579..deca1dc674 100644 --- a/crates/router/src/connector/bankofamerica/transformers.rs +++ b/crates/router/src/connector/bankofamerica/transformers.rs @@ -626,6 +626,7 @@ impl attempt_status: None, connector_transaction_id: None, }), + status: enums::AttemptStatus::Failure, ..item.data }), } @@ -1024,6 +1025,22 @@ pub struct BankOfAmericaStandardErrorResponse { pub details: Option>, } +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct BankOfAmericaServerErrorResponse { + pub status: Option, + pub message: Option, + pub reason: Option, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum Reason { + SystemError, + ServerTimeout, + ServiceTimeout, +} + #[derive(Debug, Deserialize)] pub struct BankOfAmericaAuthenticationErrorResponse { pub response: AuthenticationErrorInformation, diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 8b301c525f..adecf1b78e 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -471,20 +471,26 @@ async fn payment_response_update_tracker( flow_name.clone(), ) .await; - let status = + let status = match err.attempt_status { + // Use the status sent by connector in error_response if it's present + Some(status) => status, + None => // mark previous attempt status for technical failures in PSync flow - if flow_name == "PSync" { - match err.status_code { - // marking failure for 2xx because this is genuine payment failure - 200..=299 => storage::enums::AttemptStatus::Failure, - _ => router_data.status, + { + if flow_name == "PSync" { + match err.status_code { + // marking failure for 2xx because this is genuine payment failure + 200..=299 => storage::enums::AttemptStatus::Failure, + _ => router_data.status, + } + } else { + match err.status_code { + 500..=511 => storage::enums::AttemptStatus::Pending, + _ => storage::enums::AttemptStatus::Failure, + } } - } else { - match err.status_code { - 500..=511 => storage::enums::AttemptStatus::Pending, - _ => storage::enums::AttemptStatus::Failure, - } - }; + } + }; ( None, Some(storage::PaymentAttemptUpdate::ErrorUpdate {