Skip to content

Commit

Permalink
refactor(connector): [WorldPay] propagate refusal codes as error code…
Browse files Browse the repository at this point in the history
… and messages (#6392)
  • Loading branch information
kashif-m authored Oct 22, 2024
1 parent e5710fa commit 3d1a3cd
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 27 deletions.
62 changes: 60 additions & 2 deletions crates/router/src/connector/worldpay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})
}
Expand Down Expand Up @@ -344,7 +344,25 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe
res: Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
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(
Expand Down Expand Up @@ -510,6 +528,14 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res, event_builder)
}

fn get_5xx_error_response(
&self,
res: Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res, event_builder)
}
}

impl api::PaymentSession for Worldpay {}
Expand Down Expand Up @@ -622,6 +648,14 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res, event_builder)
}

fn get_5xx_error_response(
&self,
res: Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res, event_builder)
}
}

impl api::PaymentsCompleteAuthorize for Worldpay {}
Expand Down Expand Up @@ -729,6 +763,14 @@ impl
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res, event_builder)
}

fn get_5xx_error_response(
&self,
res: Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res, event_builder)
}
}

impl api::Refund for Worldpay {}
Expand Down Expand Up @@ -839,6 +881,14 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res, event_builder)
}

fn get_5xx_error_response(
&self,
res: Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res, event_builder)
}
}

impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData> for Worldpay {
Expand Down Expand Up @@ -909,6 +959,14 @@ impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponse
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res, event_builder)
}

fn get_5xx_error_response(
&self,
res: Response,
event_builder: Option<&mut ConnectorEvent>,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
self.build_error_response(res, event_builder)
}
}

#[async_trait::async_trait]
Expand Down
4 changes: 2 additions & 2 deletions crates/router/src/connector/worldpay/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ pub struct FraudHighRiskResponse {
pub struct RefusedResponse {
pub refusal_description: String,
pub refusal_code: String,
pub risk_factors: Vec<RiskFactorsInner>,
pub fraud: Fraud,
pub risk_factors: Option<Vec<RiskFactorsInner>>,
pub fraud: Option<Fraud>,
#[serde(rename = "threeDS")]
pub three_ds: Option<ThreeDsResponse>,
}
Expand Down
55 changes: 32 additions & 23 deletions crates/router/src/connector/worldpay/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,13 +419,13 @@ impl<F, T>
),
) -> Result<Self, Self::Error> {
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,
Expand All @@ -444,6 +444,7 @@ impl<F, T>
),
]),
}),
None,
),
WorldpayPaymentResponseFields::ThreeDsChallenged(res) => (
None,
Expand All @@ -455,28 +456,30 @@ impl<F, T>
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(),
Expand All @@ -489,17 +492,23 @@ impl<F, T>
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,
Expand Down

0 comments on commit 3d1a3cd

Please sign in to comment.