diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index cacff51844..2037a784ae 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -1433,6 +1433,9 @@ pub struct PaymentsResponse { /// ephemeral_key for the customer_id mentioned pub ephemeral_key: Option, + /// If true the payment can be retried with same or different payment method which means the confirm call can be made again. + pub manual_retry_allowed: Option, + /// Any user defined fields can be passed here. #[schema(value_type = Option, example = r#"{ "udf1": "some-value", "udf2": "some-value" }"#)] pub udf: Option, diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index aaaeaba0a3..52591a9124 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -9,7 +9,7 @@ use common_utils::{ use error_stack::{report, IntoReport, ResultExt}; use josekit::jwe; use masking::{ExposeInterface, PeekInterface}; -use router_env::{instrument, tracing}; +use router_env::{instrument, logger, tracing}; use storage_models::{enums, payment_intent}; use time::Duration; use uuid::Uuid; @@ -2375,6 +2375,54 @@ impl AttemptType { } } +#[inline(always)] +pub fn is_manual_retry_allowed( + intent_status: &storage_enums::IntentStatus, + attempt_status: &storage_enums::AttemptStatus, +) -> Option { + match intent_status { + enums::IntentStatus::Failed => match attempt_status { + enums::AttemptStatus::Started + | enums::AttemptStatus::AuthenticationPending + | enums::AttemptStatus::AuthenticationSuccessful + | enums::AttemptStatus::Authorized + | enums::AttemptStatus::Charged + | enums::AttemptStatus::Authorizing + | enums::AttemptStatus::CodInitiated + | enums::AttemptStatus::VoidInitiated + | enums::AttemptStatus::CaptureInitiated + | enums::AttemptStatus::Unresolved + | enums::AttemptStatus::Pending + | enums::AttemptStatus::ConfirmationAwaited + | enums::AttemptStatus::PartialCharged + | enums::AttemptStatus::Voided + | enums::AttemptStatus::AutoRefunded + | enums::AttemptStatus::PaymentMethodAwaited + | enums::AttemptStatus::DeviceDataCollectionPending => { + logger::error!("Payment Attempt should not be in this state because Attempt to Intent status mapping doesn't allow it"); + None + } + + storage_enums::AttemptStatus::VoidFailed + | storage_enums::AttemptStatus::RouterDeclined + | storage_enums::AttemptStatus::CaptureFailed => Some(false), + + storage_enums::AttemptStatus::AuthenticationFailed + | storage_enums::AttemptStatus::AuthorizationFailed + | storage_enums::AttemptStatus::Failure => Some(true), + }, + enums::IntentStatus::Cancelled + | enums::IntentStatus::RequiresCapture + | enums::IntentStatus::Processing + | enums::IntentStatus::Succeeded => Some(false), + + enums::IntentStatus::RequiresCustomerAction + | enums::IntentStatus::RequiresMerchantAction + | enums::IntentStatus::RequiresPaymentMethod + | enums::IntentStatus::RequiresConfirmation => None, + } +} + pub fn validate_and_add_order_details_to_payment_intent( payment_intent: &mut storage::payment_intent::PaymentIntent, request: &api::PaymentsRequest, diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 359fe44560..a9ad00b969 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -464,6 +464,10 @@ where .and_then(|metadata| metadata.allowed_payment_method_types), ) .set_ephemeral_key(ephemeral_key_option.map(ForeignFrom::foreign_from)) + .set_manual_retry_allowed(helpers::is_manual_retry_allowed( + &payment_intent.status, + &payment_attempt.status, + )) .set_udf(payment_intent.udf) .set_connector_transaction_id(payment_attempt.connector_transaction_id) .to_owned(), @@ -508,6 +512,10 @@ where cancellation_reason: payment_attempt.cancellation_reason, payment_token: payment_attempt.payment_token, metadata: payment_intent.metadata, + manual_retry_allowed: helpers::is_manual_retry_allowed( + &payment_intent.status, + &payment_attempt.status, + ), order_details: payment_intent.order_details, udf: payment_intent.udf, connector_transaction_id: payment_attempt.connector_transaction_id,