diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 11249c5b63..235ef14e7c 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -2072,6 +2072,7 @@ impl AttemptType { straight_through_algorithm: old_payment_attempt.straight_through_algorithm, mandate_details: old_payment_attempt.mandate_details, preprocessing_step_id: None, + error_reason: None, } } diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 6b5a6d19a5..5736d83978 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -64,15 +64,19 @@ impl PostUpdateTracker, types::PaymentsAuthorizeData .await?; router_response.map(|_| ()).or_else(|error_response| { - fp_utils::when(!(200..300).contains(&error_response.status_code), || { - Err(errors::ApiErrorResponse::ExternalConnectorError { - code: error_response.code, - message: error_response.message, - connector, - status_code: error_response.status_code, - reason: error_response.reason, - }) - }) + fp_utils::when( + !(200..300).contains(&error_response.status_code) + && !(500..=511).contains(&error_response.status_code), + || { + Err(errors::ApiErrorResponse::ExternalConnectorError { + code: error_response.code, + message: error_response.message, + connector, + status_code: error_response.status_code, + reason: error_response.reason, + }) + }, + ) })?; Ok(payment_data) @@ -295,9 +299,13 @@ async fn payment_response_update_tracker( Err(err) => ( Some(storage::PaymentAttemptUpdate::ErrorUpdate { 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_code: Some(Some(err.code)), + error_reason: Some(err.reason), }), Some(storage::ConnectorResponseUpdate::ErrorUpdate { connector_name: Some(router_data.connector.clone()), @@ -361,7 +369,8 @@ async fn payment_response_update_tracker( connector_metadata, payment_token: None, 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 { @@ -392,7 +401,8 @@ async fn payment_response_update_tracker( connector_transaction_id, payment_method_id: Some(router_data.payment_method_id), 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, ) @@ -437,9 +447,12 @@ async fn payment_response_update_tracker( None } }); - let payment_intent_update = match router_data.response { - Err(_) => storage::PaymentIntentUpdate::PGStatusUpdate { - status: enums::IntentStatus::Failed, + let payment_intent_update = match &router_data.response { + Err(err) => storage::PaymentIntentUpdate::PGStatusUpdate { + status: match err.status_code { + 400..=499 => enums::IntentStatus::Failed, + _ => enums::IntentStatus::Processing, + }, }, Ok(_) => storage::PaymentIntentUpdate::ResponseUpdate { status: router_data.status.foreign_into(), diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 95557c5cda..5ded67b261 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -406,7 +406,7 @@ where auth_flow == services::AuthFlow::Merchant, ) .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_shipping(address.shipping) .set_billing(address.billing) diff --git a/crates/router/src/db/payment_attempt.rs b/crates/router/src/db/payment_attempt.rs index b576969023..644409a01a 100644 --- a/crates/router/src/db/payment_attempt.rs +++ b/crates/router/src/db/payment_attempt.rs @@ -303,6 +303,7 @@ impl PaymentAttemptInterface for MockDb { straight_through_algorithm: payment_attempt.straight_through_algorithm, mandate_details: payment_attempt.mandate_details, preprocessing_step_id: payment_attempt.preprocessing_step_id, + error_reason: payment_attempt.error_reason, }; payment_attempts.push(payment_attempt.clone()); Ok(payment_attempt) @@ -440,6 +441,7 @@ mod storage { .clone(), mandate_details: payment_attempt.mandate_details.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); diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 4ed2ce9d7a..cc4ce8d00b 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -145,6 +145,32 @@ pub trait ConnectorIntegration: ConnectorIntegrationAny CustomResult { + 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( &self, _req: &types::RouterData, @@ -278,7 +304,13 @@ where 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 diff --git a/crates/storage_models/src/payment_attempt.rs b/crates/storage_models/src/payment_attempt.rs index f7f265336a..f93124d3cc 100644 --- a/crates/storage_models/src/payment_attempt.rs +++ b/crates/storage_models/src/payment_attempt.rs @@ -49,6 +49,7 @@ pub struct PaymentAttempt { pub preprocessing_step_id: Option, // providing a location to store mandate details intermediately for transaction pub mandate_details: Option, + pub error_reason: Option, } #[derive( @@ -96,6 +97,7 @@ pub struct PaymentAttemptNew { pub straight_through_algorithm: Option, pub preprocessing_step_id: Option, pub mandate_details: Option, + pub error_reason: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -150,6 +152,7 @@ pub enum PaymentAttemptUpdate { payment_token: Option, error_code: Option>, error_message: Option>, + error_reason: Option>, }, UnresolvedResponseUpdate { status: storage_enums::AttemptStatus, @@ -158,6 +161,7 @@ pub enum PaymentAttemptUpdate { payment_method_id: Option>, error_code: Option>, error_message: Option>, + error_reason: Option>, }, StatusUpdate { status: storage_enums::AttemptStatus, @@ -167,6 +171,7 @@ pub enum PaymentAttemptUpdate { status: storage_enums::AttemptStatus, error_code: Option>, error_message: Option>, + error_reason: Option>, }, PreprocessingUpdate { status: storage_enums::AttemptStatus, @@ -201,6 +206,7 @@ pub struct PaymentAttemptUpdateInternal { business_sub_label: Option, straight_through_algorithm: Option, preprocessing_step_id: Option, + error_reason: Option>, } impl PaymentAttemptUpdate { @@ -319,6 +325,7 @@ impl From for PaymentAttemptUpdateInternal { payment_token, error_code, error_message, + error_reason, } => Self { status: Some(status), connector, @@ -331,6 +338,7 @@ impl From for PaymentAttemptUpdateInternal { error_code, error_message, payment_token, + error_reason, ..Default::default() }, PaymentAttemptUpdate::ErrorUpdate { @@ -338,12 +346,14 @@ impl From for PaymentAttemptUpdateInternal { status, error_code, error_message, + error_reason, } => Self { connector, status: Some(status), error_message, error_code, modified_at: Some(common_utils::date_time::now()), + error_reason, ..Default::default() }, PaymentAttemptUpdate::StatusUpdate { status } => Self { @@ -367,6 +377,7 @@ impl From for PaymentAttemptUpdateInternal { payment_method_id, error_code, error_message, + error_reason, } => Self { status: Some(status), connector, @@ -375,6 +386,7 @@ impl From for PaymentAttemptUpdateInternal { modified_at: Some(common_utils::date_time::now()), error_code, error_message, + error_reason, ..Default::default() }, PaymentAttemptUpdate::PreprocessingUpdate { diff --git a/crates/storage_models/src/schema.rs b/crates/storage_models/src/schema.rs index 577991583b..4e77a0b7f7 100644 --- a/crates/storage_models/src/schema.rs +++ b/crates/storage_models/src/schema.rs @@ -429,6 +429,7 @@ diesel::table! { straight_through_algorithm -> Nullable, preprocessing_step_id -> Nullable, mandate_details -> Nullable, + error_reason -> Nullable, } } diff --git a/migrations/2023-06-14-105035_add_reason_in_payment_attempt/down.sql b/migrations/2023-06-14-105035_add_reason_in_payment_attempt/down.sql new file mode 100644 index 0000000000..2abb48f451 --- /dev/null +++ b/migrations/2023-06-14-105035_add_reason_in_payment_attempt/down.sql @@ -0,0 +1,3 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE payment_attempt +DROP COLUMN error_reason; diff --git a/migrations/2023-06-14-105035_add_reason_in_payment_attempt/up.sql b/migrations/2023-06-14-105035_add_reason_in_payment_attempt/up.sql new file mode 100644 index 0000000000..a7d8b062de --- /dev/null +++ b/migrations/2023-06-14-105035_add_reason_in_payment_attempt/up.sql @@ -0,0 +1,2 @@ +ALTER TABLE payment_attempt +ADD COLUMN error_reason TEXT;