mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 04:04:43 +08:00
refactor(disputes): resolve incorrect 5xx error mappings for disputes (#1360)
Co-authored-by: Kritik Modi <61862301+kritikmodi@users.noreply.github.com> Co-authored-by: kritikmodi <kritik.modi@juspay.in> Co-authored-by: Sai Harsha Vardhan <56996463+sai-harsha-vardhan@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
5535159d5c
commit
c9b400e186
@ -40,6 +40,9 @@ pub enum StripeErrorCode {
|
||||
#[error(error_type = StripeErrorType::ApiError, code = "payment_intent_payment_attempt_failed", message = "Capture attempt failed while processing with connector.")]
|
||||
PaymentIntentPaymentAttemptFailed { data: Option<serde_json::Value> },
|
||||
|
||||
#[error(error_type = StripeErrorType::ApiError, code = "dispute_failure", message = "Dispute failed while processing with connector. Retry operation.")]
|
||||
DisputeFailed { data: Option<serde_json::Value> },
|
||||
|
||||
#[error(error_type = StripeErrorType::CardError, code = "expired_card", message = "Card Expired. Please use another card")]
|
||||
ExpiredCard,
|
||||
|
||||
@ -405,6 +408,7 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode {
|
||||
errors::ApiErrorResponse::PaymentCaptureFailed { data } => {
|
||||
Self::PaymentIntentPaymentAttemptFailed { data }
|
||||
}
|
||||
errors::ApiErrorResponse::DisputeFailed { data } => Self::DisputeFailed { data },
|
||||
errors::ApiErrorResponse::InvalidCardData { data } => Self::InvalidCardType, // Maybe it is better to de generalize this router error
|
||||
errors::ApiErrorResponse::CardExpired { data } => Self::ExpiredCard,
|
||||
errors::ApiErrorResponse::RefundNotPossible { connector } => Self::RefundFailed,
|
||||
@ -548,6 +552,7 @@ impl actix_web::ResponseError for StripeErrorCode {
|
||||
| Self::DuplicatePaymentMethod
|
||||
| Self::PaymentFailed
|
||||
| Self::VerificationFailed { .. }
|
||||
| Self::DisputeFailed { .. }
|
||||
| Self::MaximumRefundCount
|
||||
| Self::PaymentIntentInvalidParameter { .. }
|
||||
| Self::SerdeQsError { .. }
|
||||
|
||||
@ -5,7 +5,7 @@ use router_env::{instrument, tracing};
|
||||
pub mod transformers;
|
||||
|
||||
use super::{
|
||||
errors::{self, RouterResponse, StorageErrorExt},
|
||||
errors::{self, ConnectorErrorExt, RouterResponse, StorageErrorExt},
|
||||
metrics,
|
||||
};
|
||||
use crate::{
|
||||
@ -129,7 +129,7 @@ pub async fn accept_dispute(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.map_err(|error| error.to_dispute_failed_response())
|
||||
.attach_printable("Failed while calling accept dispute connector api")?;
|
||||
let accept_dispute_response =
|
||||
response
|
||||
@ -236,7 +236,7 @@ pub async fn submit_evidence(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.map_err(|error| error.to_payment_failed_response())
|
||||
.attach_printable("Failed while calling submit evidence connector api")?;
|
||||
let submit_evidence_response =
|
||||
response
|
||||
@ -272,7 +272,7 @@ pub async fn submit_evidence(
|
||||
payments::CallConnectorAction::Trigger,
|
||||
)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.map_err(|error| error.to_payment_failed_response())
|
||||
.attach_printable("Failed while calling defend dispute connector api")?;
|
||||
let defend_dispute_response = defend_response.response.map_err(|err| {
|
||||
errors::ApiErrorResponse::ExternalConnectorError {
|
||||
@ -300,7 +300,9 @@ pub async fn submit_evidence(
|
||||
let updated_dispute = db
|
||||
.update_dispute(dispute.clone(), update_dispute)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.to_not_found_response(errors::ApiErrorResponse::DisputeNotFound {
|
||||
dispute_id: dispute_id.to_owned(),
|
||||
})
|
||||
.attach_printable_lazy(|| {
|
||||
format!("Unable to update dispute with dispute_id: {dispute_id}")
|
||||
})?;
|
||||
@ -373,7 +375,9 @@ pub async fn attach_evidence(
|
||||
};
|
||||
db.update_dispute(dispute, update_dispute)
|
||||
.await
|
||||
.change_context(errors::ApiErrorResponse::InternalServerError)
|
||||
.to_not_found_response(errors::ApiErrorResponse::DisputeNotFound {
|
||||
dispute_id: dispute_id.to_owned(),
|
||||
})
|
||||
.attach_printable_lazy(|| {
|
||||
format!("Unable to update dispute with dispute_id: {dispute_id}")
|
||||
})?;
|
||||
|
||||
@ -111,6 +111,8 @@ pub enum ApiErrorResponse {
|
||||
RefundFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_07", message = "Verification failed while processing with connector. Retry operation")]
|
||||
VerificationFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_08", message = "Dispute operation failed while processing with connector. Retry operation")]
|
||||
DisputeFailed { data: Option<serde_json::Value> },
|
||||
|
||||
#[error(error_type = ErrorType::ServerNotAvailable, code = "HE_00", message = "Something went wrong")]
|
||||
InternalServerError,
|
||||
@ -262,6 +264,7 @@ impl actix_web::ResponseError for ApiErrorResponse {
|
||||
| Self::VerificationFailed { .. }
|
||||
| Self::PaymentUnexpectedState { .. }
|
||||
| Self::MandateValidationFailed { .. }
|
||||
| Self::DisputeFailed { .. }
|
||||
| Self::RefundAmountExceedsPaymentAmount
|
||||
| Self::MaximumRefundCount
|
||||
| Self::IncorrectPaymentMethodConfiguration
|
||||
@ -428,6 +431,9 @@ impl common_utils::errors::ErrorSwitch<api_models::errors::types::ApiErrorRespon
|
||||
Self::PaymentCaptureFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 3, "Capture attempt failed while processing with connector", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::DisputeFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 1, "Dispute operation failed while processing with connector. Retry operation", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::InvalidCardData { data } => AER::BadRequest(ApiError::new("CE", 4, "The card data is invalid", Some(Extra { data: data.clone(), ..Default::default()}))),
|
||||
Self::CardExpired { data } => AER::BadRequest(ApiError::new("CE", 5, "The card has expired", Some(Extra { data: data.clone(), ..Default::default()}))),
|
||||
Self::RefundFailed { data } => AER::BadRequest(ApiError::new("CE", 6, "Refund failed while processing with connector. Retry refund", Some(Extra { data: data.clone(), ..Default::default()}))),
|
||||
|
||||
@ -50,6 +50,8 @@ pub trait ConnectorErrorExt {
|
||||
fn to_payment_failed_response(self) -> error_stack::Report<errors::ApiErrorResponse>;
|
||||
#[track_caller]
|
||||
fn to_verify_failed_response(self) -> error_stack::Report<errors::ApiErrorResponse>;
|
||||
#[track_caller]
|
||||
fn to_dispute_failed_response(self) -> error_stack::Report<errors::ApiErrorResponse>;
|
||||
}
|
||||
|
||||
impl ConnectorErrorExt for error_stack::Report<errors::ConnectorError> {
|
||||
@ -149,6 +151,36 @@ impl ConnectorErrorExt for error_stack::Report<errors::ConnectorError> {
|
||||
};
|
||||
self.change_context(data)
|
||||
}
|
||||
|
||||
fn to_dispute_failed_response(self) -> error_stack::Report<errors::ApiErrorResponse> {
|
||||
let error = match self.current_context() {
|
||||
errors::ConnectorError::ProcessingStepFailed(Some(bytes)) => {
|
||||
let response_str = std::str::from_utf8(bytes);
|
||||
let data = match response_str {
|
||||
Ok(s) => serde_json::from_str(s)
|
||||
.map_err(
|
||||
|error| logger::error!(%error,"Failed to convert response to JSON"),
|
||||
)
|
||||
.ok(),
|
||||
Err(error) => {
|
||||
logger::error!(%error,"Failed to convert response to UTF8 string");
|
||||
None
|
||||
}
|
||||
};
|
||||
errors::ApiErrorResponse::DisputeFailed { data }
|
||||
}
|
||||
errors::ConnectorError::MissingRequiredField { field_name } => {
|
||||
errors::ApiErrorResponse::MissingRequiredField { field_name }
|
||||
}
|
||||
errors::ConnectorError::MissingRequiredFields { field_names } => {
|
||||
errors::ApiErrorResponse::MissingRequiredFields {
|
||||
field_names: field_names.to_vec(),
|
||||
}
|
||||
}
|
||||
_ => errors::ApiErrorResponse::InternalServerError,
|
||||
};
|
||||
self.change_context(error)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RedisErrorExt {
|
||||
|
||||
Reference in New Issue
Block a user