From 3d1a3cdc8f942a3dca2e6a200bf9200366bd62f1 Mon Sep 17 00:00:00 2001 From: Kashif Date: Tue, 22 Oct 2024 18:08:36 +0530 Subject: [PATCH] refactor(connector): [WorldPay] propagate refusal codes as error code and messages (#6392) --- crates/router/src/connector/worldpay.rs | 62 ++++++++++++++++++- .../router/src/connector/worldpay/response.rs | 4 +- .../src/connector/worldpay/transformers.rs | 55 +++++++++------- 3 files changed, 94 insertions(+), 27 deletions(-) diff --git a/crates/router/src/connector/worldpay.rs b/crates/router/src/connector/worldpay.rs index 97da36f39b35..777594a4534e 100644 --- a/crates/router/src/connector/worldpay.rs +++ b/crates/router/src/connector/worldpay.rs @@ -123,7 +123,7 @@ impl ConnectorCommon for Worldpay { code: response.error_name, message: response.message, reason: response.validation_errors.map(|e| e.to_string()), - attempt_status: None, + attempt_status: Some(enums::AttemptStatus::Failure), connector_transaction_id: None, }) } @@ -344,7 +344,25 @@ impl ConnectorIntegration, ) -> CustomResult { - self.build_error_response(res, event_builder) + let response = if !res.response.is_empty() { + res.response + .parse_struct("WorldpayErrorResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)? + } else { + WorldpayErrorResponse::default(res.status_code) + }; + + event_builder.map(|i| i.set_error_response_body(&response)); + router_env::logger::info!(connector_response=?response); + + Ok(ErrorResponse { + status_code: res.status_code, + code: response.error_name, + message: response.message, + reason: response.validation_errors.map(|e| e.to_string()), + attempt_status: None, + connector_transaction_id: None, + }) } fn handle_response( @@ -510,6 +528,14 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res, event_builder) } + + fn get_5xx_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } } impl api::PaymentSession for Worldpay {} @@ -622,6 +648,14 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res, event_builder) } + + fn get_5xx_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } } impl api::PaymentsCompleteAuthorize for Worldpay {} @@ -729,6 +763,14 @@ impl ) -> CustomResult { self.build_error_response(res, event_builder) } + + fn get_5xx_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } } impl api::Refund for Worldpay {} @@ -839,6 +881,14 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res, event_builder) } + + fn get_5xx_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } } impl ConnectorIntegration for Worldpay { @@ -909,6 +959,14 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res, event_builder) } + + fn get_5xx_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } } #[async_trait::async_trait] diff --git a/crates/router/src/connector/worldpay/response.rs b/crates/router/src/connector/worldpay/response.rs index edc3c26948fa..c62310867f0b 100644 --- a/crates/router/src/connector/worldpay/response.rs +++ b/crates/router/src/connector/worldpay/response.rs @@ -53,8 +53,8 @@ pub struct FraudHighRiskResponse { pub struct RefusedResponse { pub refusal_description: String, pub refusal_code: String, - pub risk_factors: Vec, - pub fraud: Fraud, + pub risk_factors: Option>, + pub fraud: Option, #[serde(rename = "threeDS")] pub three_ds: Option, } diff --git a/crates/router/src/connector/worldpay/transformers.rs b/crates/router/src/connector/worldpay/transformers.rs index a28d3bff7ed4..be8b7737b16f 100644 --- a/crates/router/src/connector/worldpay/transformers.rs +++ b/crates/router/src/connector/worldpay/transformers.rs @@ -419,13 +419,13 @@ impl ), ) -> Result { let (router_data, optional_correlation_id) = item; - let (description, redirection_data) = router_data + let (description, redirection_data, error) = router_data .response .other_fields .as_ref() .map(|other_fields| match other_fields { WorldpayPaymentResponseFields::AuthorizedResponse(res) => { - (res.description.clone(), None) + (res.description.clone(), None, None) } WorldpayPaymentResponseFields::DDCResponse(res) => ( None, @@ -444,6 +444,7 @@ impl ), ]), }), + None, ), WorldpayPaymentResponseFields::ThreeDsChallenged(res) => ( None, @@ -455,28 +456,30 @@ impl res.challenge.jwt.clone().expose(), )]), }), + None, + ), + WorldpayPaymentResponseFields::RefusedResponse(res) => ( + None, + None, + Some((res.refusal_code.clone(), res.refusal_description.clone())), ), - WorldpayPaymentResponseFields::FraudHighRisk(_) - | WorldpayPaymentResponseFields::RefusedResponse(_) => (None, None), + WorldpayPaymentResponseFields::FraudHighRisk(_) => (None, None, None), }) - .unwrap_or((None, None)); + .unwrap_or((None, None, None)); let worldpay_status = router_data.response.outcome.clone(); - let optional_reason = match worldpay_status { + let optional_error_message = match worldpay_status { PaymentOutcome::ThreeDsAuthenticationFailed => { Some("3DS authentication failed from issuer".to_string()) } PaymentOutcome::ThreeDsUnavailable => { Some("3DS authentication unavailable from issuer".to_string()) } - PaymentOutcome::FraudHighRisk => { - Some("Transaction marked as high risk by Worldpay".to_string()) - } - PaymentOutcome::Refused => Some("Transaction refused by issuer".to_string()), + PaymentOutcome::FraudHighRisk => Some("Transaction marked as high risk".to_string()), _ => None, }; let status = enums::AttemptStatus::from(worldpay_status.clone()); - let response = optional_reason.map_or( - Ok(PaymentsResponseData::TransactionResponse { + let response = match (optional_error_message, error) { + (None, None) => Ok(PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::foreign_try_from(( router_data.response, optional_correlation_id.clone(), @@ -489,17 +492,23 @@ impl incremental_authorization_allowed: None, charge_id: None, }), - |reason| { - Err(types::ErrorResponse { - code: worldpay_status.to_string(), - message: reason.clone(), - reason: Some(reason), - status_code: router_data.http_code, - attempt_status: Some(status), - connector_transaction_id: optional_correlation_id, - }) - }, - ); + (Some(reason), _) => Err(types::ErrorResponse { + code: worldpay_status.to_string(), + message: reason.clone(), + reason: Some(reason), + status_code: router_data.http_code, + attempt_status: Some(status), + connector_transaction_id: optional_correlation_id, + }), + (_, Some((code, message))) => Err(types::ErrorResponse { + code, + message: message.clone(), + reason: Some(message), + status_code: router_data.http_code, + attempt_status: Some(status), + connector_transaction_id: optional_correlation_id, + }), + }; Ok(Self { status, description,