refactor(router): send 200 response for 5xx status codes received from connector (#1440)

This commit is contained in:
Sai Harsha Vardhan
2023-06-15 13:40:59 +05:30
committed by GitHub
parent ee5466a3b0
commit 1e5d2a28f6
9 changed files with 83 additions and 17 deletions

View File

@ -2072,6 +2072,7 @@ impl AttemptType {
straight_through_algorithm: old_payment_attempt.straight_through_algorithm, straight_through_algorithm: old_payment_attempt.straight_through_algorithm,
mandate_details: old_payment_attempt.mandate_details, mandate_details: old_payment_attempt.mandate_details,
preprocessing_step_id: None, preprocessing_step_id: None,
error_reason: None,
} }
} }

View File

@ -64,15 +64,19 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsAuthorizeData
.await?; .await?;
router_response.map(|_| ()).or_else(|error_response| { router_response.map(|_| ()).or_else(|error_response| {
fp_utils::when(!(200..300).contains(&error_response.status_code), || { fp_utils::when(
Err(errors::ApiErrorResponse::ExternalConnectorError { !(200..300).contains(&error_response.status_code)
code: error_response.code, && !(500..=511).contains(&error_response.status_code),
message: error_response.message, || {
connector, Err(errors::ApiErrorResponse::ExternalConnectorError {
status_code: error_response.status_code, code: error_response.code,
reason: error_response.reason, message: error_response.message,
}) connector,
}) status_code: error_response.status_code,
reason: error_response.reason,
})
},
)
})?; })?;
Ok(payment_data) Ok(payment_data)
@ -295,9 +299,13 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
Err(err) => ( Err(err) => (
Some(storage::PaymentAttemptUpdate::ErrorUpdate { Some(storage::PaymentAttemptUpdate::ErrorUpdate {
connector: None, connector: None,
status: storage::enums::AttemptStatus::Failure, status: match err.status_code {
400..=499 => storage::enums::AttemptStatus::Failure,
_ => storage::enums::AttemptStatus::Pending,
},
error_message: Some(Some(err.message)), error_message: Some(Some(err.message)),
error_code: Some(Some(err.code)), error_code: Some(Some(err.code)),
error_reason: Some(err.reason),
}), }),
Some(storage::ConnectorResponseUpdate::ErrorUpdate { Some(storage::ConnectorResponseUpdate::ErrorUpdate {
connector_name: Some(router_data.connector.clone()), connector_name: Some(router_data.connector.clone()),
@ -361,7 +369,8 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
connector_metadata, connector_metadata,
payment_token: None, payment_token: None,
error_code: error_status.clone(), error_code: error_status.clone(),
error_message: error_status, error_message: error_status.clone(),
error_reason: error_status,
}; };
let connector_response_update = storage::ConnectorResponseUpdate::ResponseUpdate { let connector_response_update = storage::ConnectorResponseUpdate::ResponseUpdate {
@ -392,7 +401,8 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
connector_transaction_id, connector_transaction_id,
payment_method_id: Some(router_data.payment_method_id), payment_method_id: Some(router_data.payment_method_id),
error_code: Some(reason.clone().map(|cd| cd.code)), error_code: Some(reason.clone().map(|cd| cd.code)),
error_message: Some(reason.map(|cd| cd.message)), error_message: Some(reason.clone().map(|cd| cd.message)),
error_reason: Some(reason.map(|cd| cd.message)),
}), }),
None, None,
) )
@ -437,9 +447,12 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
None None
} }
}); });
let payment_intent_update = match router_data.response { let payment_intent_update = match &router_data.response {
Err(_) => storage::PaymentIntentUpdate::PGStatusUpdate { Err(err) => storage::PaymentIntentUpdate::PGStatusUpdate {
status: enums::IntentStatus::Failed, status: match err.status_code {
400..=499 => enums::IntentStatus::Failed,
_ => enums::IntentStatus::Processing,
},
}, },
Ok(_) => storage::PaymentIntentUpdate::ResponseUpdate { Ok(_) => storage::PaymentIntentUpdate::ResponseUpdate {
status: router_data.status.foreign_into(), status: router_data.status.foreign_into(),

View File

@ -406,7 +406,7 @@ where
auth_flow == services::AuthFlow::Merchant, auth_flow == services::AuthFlow::Merchant,
) )
.set_payment_token(payment_attempt.payment_token) .set_payment_token(payment_attempt.payment_token)
.set_error_message(payment_attempt.error_message) .set_error_message(payment_attempt.error_reason)
.set_error_code(payment_attempt.error_code) .set_error_code(payment_attempt.error_code)
.set_shipping(address.shipping) .set_shipping(address.shipping)
.set_billing(address.billing) .set_billing(address.billing)

View File

@ -303,6 +303,7 @@ impl PaymentAttemptInterface for MockDb {
straight_through_algorithm: payment_attempt.straight_through_algorithm, straight_through_algorithm: payment_attempt.straight_through_algorithm,
mandate_details: payment_attempt.mandate_details, mandate_details: payment_attempt.mandate_details,
preprocessing_step_id: payment_attempt.preprocessing_step_id, preprocessing_step_id: payment_attempt.preprocessing_step_id,
error_reason: payment_attempt.error_reason,
}; };
payment_attempts.push(payment_attempt.clone()); payment_attempts.push(payment_attempt.clone());
Ok(payment_attempt) Ok(payment_attempt)
@ -440,6 +441,7 @@ mod storage {
.clone(), .clone(),
mandate_details: payment_attempt.mandate_details.clone(), mandate_details: payment_attempt.mandate_details.clone(),
preprocessing_step_id: payment_attempt.preprocessing_step_id.clone(), preprocessing_step_id: payment_attempt.preprocessing_step_id.clone(),
error_reason: payment_attempt.error_reason.clone(),
}; };
let field = format!("pa_{}", created_attempt.attempt_id); let field = format!("pa_{}", created_attempt.attempt_id);

View File

@ -145,6 +145,32 @@ pub trait ConnectorIntegration<T, Req, Resp>: ConnectorIntegrationAny<T, Req, Re
Ok(ErrorResponse::get_not_implemented()) Ok(ErrorResponse::get_not_implemented())
} }
fn get_5xx_error_response(
&self,
res: types::Response,
) -> CustomResult<ErrorResponse, errors::ConnectorError> {
let error_message = match res.status_code {
500 => "internal_server_error",
501 => "not_implemented",
502 => "bad_gateway",
503 => "service_unavailable",
504 => "gateway_timeout",
505 => "http_version_not_supported",
506 => "variant_also_negotiates",
507 => "insufficient_storage",
508 => "loop_detected",
510 => "not_extended",
511 => "network_authentication_required",
_ => "unknown_error",
};
Ok(ErrorResponse {
code: res.status_code.to_string(),
message: error_message.to_string(),
reason: String::from_utf8(res.response.to_vec()).ok(),
status_code: res.status_code,
})
}
fn get_certificate( fn get_certificate(
&self, &self,
_req: &types::RouterData<T, Req, Resp>, _req: &types::RouterData<T, Req, Resp>,
@ -278,7 +304,13 @@ where
req.connector.clone(), req.connector.clone(),
)], )],
); );
let error = connector_integration.get_error_response(body)?; let error = match body.status_code {
500..=511 => {
connector_integration.get_5xx_error_response(body)?
}
_ => connector_integration.get_error_response(body)?,
};
router_data.response = Err(error); router_data.response = Err(error);
router_data router_data

View File

@ -49,6 +49,7 @@ pub struct PaymentAttempt {
pub preprocessing_step_id: Option<String>, pub preprocessing_step_id: Option<String>,
// providing a location to store mandate details intermediately for transaction // providing a location to store mandate details intermediately for transaction
pub mandate_details: Option<storage_enums::MandateDataType>, pub mandate_details: Option<storage_enums::MandateDataType>,
pub error_reason: Option<String>,
} }
#[derive( #[derive(
@ -96,6 +97,7 @@ pub struct PaymentAttemptNew {
pub straight_through_algorithm: Option<serde_json::Value>, pub straight_through_algorithm: Option<serde_json::Value>,
pub preprocessing_step_id: Option<String>, pub preprocessing_step_id: Option<String>,
pub mandate_details: Option<storage_enums::MandateDataType>, pub mandate_details: Option<storage_enums::MandateDataType>,
pub error_reason: Option<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -150,6 +152,7 @@ pub enum PaymentAttemptUpdate {
payment_token: Option<String>, payment_token: Option<String>,
error_code: Option<Option<String>>, error_code: Option<Option<String>>,
error_message: Option<Option<String>>, error_message: Option<Option<String>>,
error_reason: Option<Option<String>>,
}, },
UnresolvedResponseUpdate { UnresolvedResponseUpdate {
status: storage_enums::AttemptStatus, status: storage_enums::AttemptStatus,
@ -158,6 +161,7 @@ pub enum PaymentAttemptUpdate {
payment_method_id: Option<Option<String>>, payment_method_id: Option<Option<String>>,
error_code: Option<Option<String>>, error_code: Option<Option<String>>,
error_message: Option<Option<String>>, error_message: Option<Option<String>>,
error_reason: Option<Option<String>>,
}, },
StatusUpdate { StatusUpdate {
status: storage_enums::AttemptStatus, status: storage_enums::AttemptStatus,
@ -167,6 +171,7 @@ pub enum PaymentAttemptUpdate {
status: storage_enums::AttemptStatus, status: storage_enums::AttemptStatus,
error_code: Option<Option<String>>, error_code: Option<Option<String>>,
error_message: Option<Option<String>>, error_message: Option<Option<String>>,
error_reason: Option<Option<String>>,
}, },
PreprocessingUpdate { PreprocessingUpdate {
status: storage_enums::AttemptStatus, status: storage_enums::AttemptStatus,
@ -201,6 +206,7 @@ pub struct PaymentAttemptUpdateInternal {
business_sub_label: Option<String>, business_sub_label: Option<String>,
straight_through_algorithm: Option<serde_json::Value>, straight_through_algorithm: Option<serde_json::Value>,
preprocessing_step_id: Option<String>, preprocessing_step_id: Option<String>,
error_reason: Option<Option<String>>,
} }
impl PaymentAttemptUpdate { impl PaymentAttemptUpdate {
@ -319,6 +325,7 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
payment_token, payment_token,
error_code, error_code,
error_message, error_message,
error_reason,
} => Self { } => Self {
status: Some(status), status: Some(status),
connector, connector,
@ -331,6 +338,7 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
error_code, error_code,
error_message, error_message,
payment_token, payment_token,
error_reason,
..Default::default() ..Default::default()
}, },
PaymentAttemptUpdate::ErrorUpdate { PaymentAttemptUpdate::ErrorUpdate {
@ -338,12 +346,14 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
status, status,
error_code, error_code,
error_message, error_message,
error_reason,
} => Self { } => Self {
connector, connector,
status: Some(status), status: Some(status),
error_message, error_message,
error_code, error_code,
modified_at: Some(common_utils::date_time::now()), modified_at: Some(common_utils::date_time::now()),
error_reason,
..Default::default() ..Default::default()
}, },
PaymentAttemptUpdate::StatusUpdate { status } => Self { PaymentAttemptUpdate::StatusUpdate { status } => Self {
@ -367,6 +377,7 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
payment_method_id, payment_method_id,
error_code, error_code,
error_message, error_message,
error_reason,
} => Self { } => Self {
status: Some(status), status: Some(status),
connector, connector,
@ -375,6 +386,7 @@ impl From<PaymentAttemptUpdate> for PaymentAttemptUpdateInternal {
modified_at: Some(common_utils::date_time::now()), modified_at: Some(common_utils::date_time::now()),
error_code, error_code,
error_message, error_message,
error_reason,
..Default::default() ..Default::default()
}, },
PaymentAttemptUpdate::PreprocessingUpdate { PaymentAttemptUpdate::PreprocessingUpdate {

View File

@ -429,6 +429,7 @@ diesel::table! {
straight_through_algorithm -> Nullable<Jsonb>, straight_through_algorithm -> Nullable<Jsonb>,
preprocessing_step_id -> Nullable<Varchar>, preprocessing_step_id -> Nullable<Varchar>,
mandate_details -> Nullable<Jsonb>, mandate_details -> Nullable<Jsonb>,
error_reason -> Nullable<Text>,
} }
} }

View File

@ -0,0 +1,3 @@
-- This file should undo anything in `up.sql`
ALTER TABLE payment_attempt
DROP COLUMN error_reason;

View File

@ -0,0 +1,2 @@
ALTER TABLE payment_attempt
ADD COLUMN error_reason TEXT;