From 3f3b797dc65c1bc6f710b122ef00d5bcb409e600 Mon Sep 17 00:00:00 2001 From: Hrithikesh <61539176+hrithikesh026@users.noreply.github.com> Date: Tue, 21 Nov 2023 20:25:38 +0530 Subject: [PATCH] fix: status goes from pending to partially captured in psync (#2915) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../src/payments/payment_attempt.rs | 7 ++++-- crates/diesel_models/src/payment_attempt.rs | 17 ++++++++++---- crates/router/src/connector/utils.rs | 20 ++++++++++++---- crates/router/src/core/payments/helpers.rs | 23 +++++++++++++++++++ .../payments/operations/payment_capture.rs | 23 +++++++++++++------ .../payments/operations/payment_create.rs | 14 ++++------- .../payments/operations/payment_response.rs | 2 ++ crates/router/src/core/payments/retry.rs | 2 ++ crates/router/src/types.rs | 11 +++++++-- crates/router/src/workflows/payment_sync.rs | 2 ++ .../src/payments/payment_attempt.rs | 20 ++++++++++++---- .../Payments - Create/request.json | 2 +- .../Recurring Payments - Create/request.json | 2 +- .../Payments - Create/request.json | 2 +- .../Payments - Create/request.json | 2 +- 15 files changed, 112 insertions(+), 37 deletions(-) diff --git a/crates/data_models/src/payments/payment_attempt.rs b/crates/data_models/src/payments/payment_attempt.rs index 1b43177feb5..80ae283be85 100644 --- a/crates/data_models/src/payments/payment_attempt.rs +++ b/crates/data_models/src/payments/payment_attempt.rs @@ -321,12 +321,15 @@ pub enum PaymentAttemptUpdate { error_message: Option>, error_reason: Option>, amount_capturable: Option, + surcharge_amount: Option, + tax_amount: Option, updated_by: String, unified_code: Option>, unified_message: Option>, }, - MultipleCaptureCountUpdate { - multiple_capture_count: i16, + CaptureUpdate { + amount_to_capture: Option, + multiple_capture_count: Option, updated_by: String, }, AmountToCaptureUpdate { diff --git a/crates/diesel_models/src/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs index f77e75491d8..82ab9a1c02e 100644 --- a/crates/diesel_models/src/payment_attempt.rs +++ b/crates/diesel_models/src/payment_attempt.rs @@ -238,12 +238,15 @@ pub enum PaymentAttemptUpdate { error_message: Option>, error_reason: Option>, amount_capturable: Option, + surcharge_amount: Option, + tax_amount: Option, updated_by: String, unified_code: Option>, unified_message: Option>, }, - MultipleCaptureCountUpdate { - multiple_capture_count: i16, + CaptureUpdate { + amount_to_capture: Option, + multiple_capture_count: Option, updated_by: String, }, AmountToCaptureUpdate { @@ -535,6 +538,8 @@ impl From for PaymentAttemptUpdateInternal { error_message, error_reason, amount_capturable, + surcharge_amount, + tax_amount, updated_by, unified_code, unified_message, @@ -547,6 +552,8 @@ impl From for PaymentAttemptUpdateInternal { error_reason, amount_capturable, updated_by, + surcharge_amount, + tax_amount, unified_code, unified_message, ..Default::default() @@ -618,12 +625,14 @@ impl From for PaymentAttemptUpdateInternal { updated_by, ..Default::default() }, - PaymentAttemptUpdate::MultipleCaptureCountUpdate { + PaymentAttemptUpdate::CaptureUpdate { multiple_capture_count, updated_by, + amount_to_capture, } => Self { - multiple_capture_count: Some(multiple_capture_count), + multiple_capture_count, updated_by, + amount_to_capture, ..Default::default() }, PaymentAttemptUpdate::AmountToCaptureUpdate { diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 9c19d4eed8f..8b20332ce5e 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -24,7 +24,10 @@ use crate::{ payments::PaymentData, }, pii::PeekInterface, - types::{self, api, transformers::ForeignTryFrom, PaymentsCancelData, ResponseId}, + types::{ + self, api, storage::payment_attempt::PaymentAttemptExt, transformers::ForeignTryFrom, + PaymentsCancelData, ResponseId, + }, utils::{OptionExt, ValueExt}, }; @@ -108,11 +111,20 @@ where } } enums::AttemptStatus::Charged => { - let captured_amount = types::Capturable::get_capture_amount(&self.request); - if Some(payment_data.payment_intent.amount) == captured_amount { - enums::AttemptStatus::Charged + let captured_amount = if self.request.is_psync() { + payment_data + .payment_attempt + .amount_to_capture + .or(Some(payment_data.payment_attempt.get_total_amount())) } else { + types::Capturable::get_capture_amount(&self.request) + }; + if Some(payment_data.payment_attempt.get_total_amount()) == captured_amount { + enums::AttemptStatus::Charged + } else if captured_amount.is_some() { enums::AttemptStatus::PartialCharged + } else { + self.status } } _ => self.status, diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index ae729ff8fa2..c823fcd4937 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -600,6 +600,29 @@ pub fn validate_request_amount_and_amount_to_capture( } } +/// if confirm = true and capture method = automatic, amount_to_capture(if provided) must be equal to amount +#[instrument(skip_all)] +pub fn validate_amount_to_capture_in_create_call_request( + request: &api_models::payments::PaymentsRequest, +) -> CustomResult<(), errors::ApiErrorResponse> { + if request.capture_method.unwrap_or_default() == api_enums::CaptureMethod::Automatic + && request.confirm.unwrap_or(false) + { + if let Some((amount_to_capture, amount)) = request.amount_to_capture.zip(request.amount) { + let amount_int: i64 = amount.into(); + utils::when(amount_to_capture != amount_int, || { + Err(report!(errors::ApiErrorResponse::PreconditionFailed { + message: "amount_to_capture must be equal to amount when confirm = true and capture_method = automatic".into() + })) + }) + } else { + Ok(()) + } + } else { + Ok(()) + } +} + #[instrument(skip_all)] pub fn validate_card_data( payment_method_data: Option, diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index 09e79064dc6..ef8e2b0153d 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -251,20 +251,29 @@ impl where F: 'b + Send, { - payment_data.payment_attempt = match &payment_data.multiple_capture_data { - Some(multiple_capture_data) => db - .store + payment_data.payment_attempt = if payment_data.multiple_capture_data.is_some() + || payment_data.payment_attempt.amount_to_capture.is_some() + { + let multiple_capture_count = payment_data + .multiple_capture_data + .as_ref() + .map(|multiple_capture_data| multiple_capture_data.get_captures_count()) + .transpose()?; + let amount_to_capture = payment_data.payment_attempt.amount_to_capture; + db.store .update_payment_attempt_with_attempt_id( payment_data.payment_attempt, - storage::PaymentAttemptUpdate::MultipleCaptureCountUpdate { - multiple_capture_count: multiple_capture_data.get_captures_count()?, + storage::PaymentAttemptUpdate::CaptureUpdate { + amount_to_capture, + multiple_capture_count, updated_by: storage_scheme.to_string(), }, storage_scheme, ) .await - .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?, - None => payment_data.payment_attempt, + .to_not_found_response(errors::ApiErrorResponse::InternalServerError)? + } else { + payment_data.payment_attempt }; Ok((Box::new(self), payment_data)) } diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 10c237cc8ab..845915cc332 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use api_models::{enums::FrmSuggestion, payment_methods}; +use api_models::enums::FrmSuggestion; use async_trait::async_trait; use common_utils::ext_traits::{AsyncExt, Encode, ValueExt}; use data_models::{mandates::MandateData, payments::payment_attempt::PaymentAttempt}; @@ -279,15 +279,7 @@ impl let setup_mandate = setup_mandate.map(MandateData::from); let surcharge_details = request.surcharge_details.map(|surcharge_details| { - payment_methods::SurchargeDetailsResponse { - surcharge: payment_methods::Surcharge::Fixed(surcharge_details.surcharge_amount), - tax_on_surcharge: None, - surcharge_amount: surcharge_details.surcharge_amount, - tax_on_surcharge_amount: surcharge_details.tax_amount.unwrap_or(0), - final_amount: payment_attempt.amount - + surcharge_details.surcharge_amount - + surcharge_details.tax_amount.unwrap_or(0), - } + surcharge_details.get_surcharge_details_object(payment_attempt.amount) }); let payment_data = PaymentData { @@ -546,6 +538,8 @@ impl ValidateRequest( } else { None }, + surcharge_amount: router_data.request.get_surcharge_amount(), + tax_amount: router_data.request.get_tax_on_surcharge_amount(), updated_by: storage_scheme.to_string(), unified_code: option_gsm.clone().map(|gsm| gsm.unified_code), unified_message: option_gsm.map(|gsm| gsm.unified_message), diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index 3c0106206e1..f16f7629578 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -410,6 +410,8 @@ where status: storage_enums::AttemptStatus::Failure, error_reason: Some(error_response.reason.clone()), amount_capturable: Some(0), + surcharge_amount: None, + tax_amount: None, updated_by: storage_scheme.to_string(), unified_code: option_gsm.clone().map(|gsm| gsm.unified_code), unified_message: option_gsm.map(|gsm| gsm.unified_message), diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index ceeb93f6976..203d4e30bf9 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -545,7 +545,7 @@ pub struct AccessTokenRequestData { pub trait Capturable { fn get_capture_amount(&self) -> Option { - Some(0) + None } fn get_surcharge_amount(&self) -> Option { None @@ -553,6 +553,9 @@ pub trait Capturable { fn get_tax_on_surcharge_amount(&self) -> Option { None } + fn is_psync(&self) -> bool { + false + } } impl Capturable for PaymentsAuthorizeData { @@ -591,7 +594,11 @@ impl Capturable for PaymentsCancelData {} impl Capturable for PaymentsApproveData {} impl Capturable for PaymentsRejectData {} impl Capturable for PaymentsSessionData {} -impl Capturable for PaymentsSyncData {} +impl Capturable for PaymentsSyncData { + fn is_psync(&self) -> bool { + true + } +} pub struct AddAccessTokenResult { pub access_token_result: Result, ErrorResponse>, diff --git a/crates/router/src/workflows/payment_sync.rs b/crates/router/src/workflows/payment_sync.rs index 43e327559a0..c4b35cd6301 100644 --- a/crates/router/src/workflows/payment_sync.rs +++ b/crates/router/src/workflows/payment_sync.rs @@ -135,6 +135,8 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow { consts::REQUEST_TIMEOUT_ERROR_MESSAGE_FROM_PSYNC.to_string(), )), amount_capturable: Some(0), + surcharge_amount: None, + tax_amount: None, updated_by: merchant_account.storage_scheme.to_string(), unified_code: None, unified_message: None, diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index cb74c981ea7..238a2d75087 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -1320,6 +1320,8 @@ impl DataModelExt for PaymentAttemptUpdate { error_message, error_reason, amount_capturable, + tax_amount, + surcharge_amount, updated_by, unified_code, unified_message, @@ -1330,16 +1332,20 @@ impl DataModelExt for PaymentAttemptUpdate { error_message, error_reason, amount_capturable, + surcharge_amount, + tax_amount, updated_by, unified_code, unified_message, }, - Self::MultipleCaptureCountUpdate { + Self::CaptureUpdate { multiple_capture_count, updated_by, - } => DieselPaymentAttemptUpdate::MultipleCaptureCountUpdate { + amount_to_capture, + } => DieselPaymentAttemptUpdate::CaptureUpdate { multiple_capture_count, updated_by, + amount_to_capture, }, Self::PreprocessingUpdate { status, @@ -1577,6 +1583,8 @@ impl DataModelExt for PaymentAttemptUpdate { error_message, error_reason, amount_capturable, + surcharge_amount, + tax_amount, updated_by, unified_code, unified_message, @@ -1588,13 +1596,17 @@ impl DataModelExt for PaymentAttemptUpdate { error_reason, amount_capturable, updated_by, + surcharge_amount, + tax_amount, unified_code, unified_message, }, - DieselPaymentAttemptUpdate::MultipleCaptureCountUpdate { + DieselPaymentAttemptUpdate::CaptureUpdate { + amount_to_capture, multiple_capture_count, updated_by, - } => Self::MultipleCaptureCountUpdate { + } => Self::CaptureUpdate { + amount_to_capture, multiple_capture_count, updated_by, }, diff --git a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario1-Create payment with confirm true/Payments - Create/request.json b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario1-Create payment with confirm true/Payments - Create/request.json index fe57a769892..55088058306 100644 --- a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario1-Create payment with confirm true/Payments - Create/request.json +++ b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario1-Create payment with confirm true/Payments - Create/request.json @@ -25,7 +25,7 @@ "business_label": "default", "capture_method": "automatic", "capture_on": "2022-09-10T10:11:12Z", - "amount_to_capture": 1, + "amount_to_capture": 6540, "customer_id": "bernard123", "email": "guest@example.com", "name": "John Doe", diff --git a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario11-Refund recurring payment/Recurring Payments - Create/request.json b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario11-Refund recurring payment/Recurring Payments - Create/request.json index 90c966e10f1..304d0335058 100644 --- a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario11-Refund recurring payment/Recurring Payments - Create/request.json +++ b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario11-Refund recurring payment/Recurring Payments - Create/request.json @@ -23,7 +23,7 @@ "confirm": true, "capture_method": "automatic", "capture_on": "2022-09-10T10:11:12Z", - "amount_to_capture": 6540, + "amount_to_capture": 6570, "customer_id": "StripeCustomer", "email": "guest@example.com", "name": "John Doe", diff --git a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario27-Create a failure card payment with confirm true/Payments - Create/request.json b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario27-Create a failure card payment with confirm true/Payments - Create/request.json index 150139b8e10..6542d21542d 100644 --- a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario27-Create a failure card payment with confirm true/Payments - Create/request.json +++ b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario27-Create a failure card payment with confirm true/Payments - Create/request.json @@ -25,7 +25,7 @@ "business_label": "default", "capture_method": "automatic", "capture_on": "2022-09-10T10:11:12Z", - "amount_to_capture": 1, + "amount_to_capture": 6540, "customer_id": "bernard123", "email": "guest@example.com", "name": "John Doe", diff --git a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario27-Create payment without customer_id and with billing address and shipping address/Payments - Create/request.json b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario27-Create payment without customer_id and with billing address and shipping address/Payments - Create/request.json index 21f05484389..e37391b78b5 100644 --- a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario27-Create payment without customer_id and with billing address and shipping address/Payments - Create/request.json +++ b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario27-Create payment without customer_id and with billing address and shipping address/Payments - Create/request.json @@ -25,7 +25,7 @@ "business_label": "default", "capture_method": "automatic", "capture_on": "2022-09-10T10:11:12Z", - "amount_to_capture": 1, + "amount_to_capture": 6540, "customer_id": "bernard123", "email": "guest@example.com", "name": "John Doe",