From 12f25f057dcc56c0b6f0b79a65a8fbf7375100a9 Mon Sep 17 00:00:00 2001 From: Narayan Bhat <48803246+Narayanbhat166@users.noreply.github.com> Date: Sun, 26 Feb 2023 16:46:59 +0530 Subject: [PATCH] feat(stripe): get error message for failed redirect payments (#615) --- .../src/connector/dlocal/transformers.rs | 2 +- crates/router/src/connector/stripe.rs | 9 ++- .../src/connector/stripe/transformers.rs | 77 ++++++++++++++++++- .../payments/operations/payment_response.rs | 4 +- 4 files changed, 85 insertions(+), 7 deletions(-) diff --git a/crates/router/src/connector/dlocal/transformers.rs b/crates/router/src/connector/dlocal/transformers.rs index 3ec3e50e2b..f429d6cd3e 100644 --- a/crates/router/src/connector/dlocal/transformers.rs +++ b/crates/router/src/connector/dlocal/transformers.rs @@ -130,7 +130,7 @@ fn get_payer_name(address: &AddressDetails) -> Option> { .last_name .clone() .map_or("".to_string(), |last_name| last_name.peek().to_string()); - let name: String = format!("{} {}", first_name, last_name).trim().to_string(); + let name: String = format!("{first_name} {last_name}").trim().to_string(); if !name.is_empty() { Some(Secret::new(name)) } else { diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs index a93246114c..1f15f8eca7 100644 --- a/crates/router/src/connector/stripe.rs +++ b/crates/router/src/connector/stripe.rs @@ -266,7 +266,7 @@ impl { let response: stripe::PaymentIntentResponse = res .response - .parse_struct("PaymentIntentResponse") + .parse_struct("PaymentSyncResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; types::RouterData::try_from(types::ResponseRouterData { response, @@ -982,7 +982,12 @@ impl services::ConnectorRedirectResponse for Stripe { Ok(query .redirect_status .map_or(payments::CallConnectorAction::Trigger, |status| { - payments::CallConnectorAction::StatusUpdate(status.into()) + // Get failed error message by triggering call to connector + if status == transformers::StripePaymentStatus::Failed { + payments::CallConnectorAction::Trigger + } else { + payments::CallConnectorAction::StatusUpdate(status.into()) + } })) } } diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 2399ff81dc..a38a9a1040 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -1,4 +1,4 @@ -use std::str::FromStr; +use std::{ops::Deref, str::FromStr}; use api_models::{self, payments}; use common_utils::{fp_utils, pii::Email}; @@ -459,7 +459,7 @@ impl From for enums::AttemptStatus { } } -#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)] +#[derive(Debug, Default, Eq, PartialEq, Deserialize)] pub struct PaymentIntentResponse { pub id: String, pub object: String, @@ -477,6 +477,22 @@ pub struct PaymentIntentResponse { pub metadata: StripeMetadata, pub next_action: Option, pub payment_method_options: Option, + pub last_payment_error: Option, +} + +#[derive(Debug, Default, Eq, PartialEq, Deserialize)] +pub struct PaymentSyncResponse { + #[serde(flatten)] + pub intent_fields: PaymentIntentResponse, + pub last_payment_error: Option, +} + +impl Deref for PaymentSyncResponse { + type Target = PaymentIntentResponse; + + fn deref(&self) -> &Self::Target { + &self.intent_fields + } } #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)] @@ -538,6 +554,63 @@ impl } } +impl + TryFrom> + for types::RouterData +{ + type Error = error_stack::Report; + fn try_from( + item: types::ResponseRouterData, + ) -> Result { + let redirection_data = item.response.next_action.as_ref().map( + |StripeNextActionResponse::RedirectToUrl(response)| { + services::RedirectForm::from((response.url.clone(), services::Method::Get)) + }, + ); + + let mandate_reference = + item.response + .payment_method_options + .to_owned() + .and_then(|payment_method_options| match payment_method_options { + StripePaymentMethodOptions::Card { + mandate_options, .. + } => mandate_options.map(|mandate_options| mandate_options.reference), + StripePaymentMethodOptions::Klarna {} + | StripePaymentMethodOptions::Affirm {} + | StripePaymentMethodOptions::AfterpayClearpay {} => None, + }); + + let error_res = + item.response + .last_payment_error + .as_ref() + .map(|error| types::ErrorResponse { + code: error.code.to_owned().unwrap_or_default(), + message: error.message.to_owned().unwrap_or_default(), + reason: None, + status_code: item.http_code, + }); + + let response = error_res.map_or( + Ok(types::PaymentsResponseData::TransactionResponse { + resource_id: types::ResponseId::ConnectorTransactionId(item.response.id.clone()), + redirection_data, + mandate_reference, + connector_metadata: None, + }), + Err, + ); + + Ok(Self { + status: enums::AttemptStatus::from(item.response.status.to_owned()), + response, + amount_captured: Some(item.response.amount_received), + ..item.data + }) + } +} + impl TryFrom> for types::RouterData diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 1236b71e24..6f2cc750f1 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -273,7 +273,7 @@ async fn payment_response_update_tracker( Err(err) => ( Some(storage::PaymentAttemptUpdate::ErrorUpdate { connector: Some(router_data.connector.clone()), - status: storage::enums::AttemptStatus::Failure, + status: router_data.status.foreign_into(), error_message: Some(err.message), error_code: Some(err.code), }), @@ -364,7 +364,7 @@ async fn payment_response_update_tracker( let payment_intent_update = match router_data.response { Err(_) => storage::PaymentIntentUpdate::PGStatusUpdate { - status: enums::IntentStatus::Failed, + status: router_data.status.foreign_into(), }, Ok(_) => storage::PaymentIntentUpdate::ResponseUpdate { status: router_data.status.foreign_into(),