diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index f6f7408e3d20..856c6a9ccbf6 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -19522,8 +19522,7 @@ "surcharge", "display_surcharge_amount", "display_tax_on_surcharge_amount", - "display_total_surcharge_amount", - "display_final_amount" + "display_total_surcharge_amount" ], "properties": { "surcharge": { @@ -19551,11 +19550,6 @@ "type": "number", "format": "double", "description": "sum of display_surcharge_amount and display_tax_on_surcharge_amount" - }, - "display_final_amount": { - "type": "number", - "format": "double", - "description": "sum of original amount," } } }, diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index d245600b8140..3143ce9387ea 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -23361,8 +23361,7 @@ "surcharge", "display_surcharge_amount", "display_tax_on_surcharge_amount", - "display_total_surcharge_amount", - "display_final_amount" + "display_total_surcharge_amount" ], "properties": { "surcharge": { @@ -23390,11 +23389,6 @@ "type": "number", "format": "double", "description": "sum of display_surcharge_amount and display_tax_on_surcharge_amount" - }, - "display_final_amount": { - "type": "number", - "format": "double", - "description": "sum of original amount," } } }, diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 1a82dc0e26bd..84106a87d9b6 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -1144,8 +1144,6 @@ pub struct SurchargeDetailsResponse { pub display_tax_on_surcharge_amount: f64, /// sum of display_surcharge_amount and display_tax_on_surcharge_amount pub display_total_surcharge_amount: f64, - /// sum of original amount, - pub display_final_amount: f64, } #[derive(Clone, Debug, PartialEq, serde::Serialize, ToSchema)] diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 9d606dacb9ff..1e491a49d4d3 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -880,6 +880,14 @@ impl RequestSurchargeDetails { pub fn get_total_surcharge_amount(&self) -> MinorUnit { self.surcharge_amount + self.tax_amount.unwrap_or_default() } + + pub fn get_surcharge_amount(&self) -> MinorUnit { + self.surcharge_amount + } + + pub fn get_tax_amount(&self) -> Option { + self.tax_amount + } } #[derive(Default, Debug, Clone)] diff --git a/crates/diesel_models/src/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs index 75a9aeda2b86..061f00f8295e 100644 --- a/crates/diesel_models/src/payment_attempt.rs +++ b/crates/diesel_models/src/payment_attempt.rs @@ -150,19 +150,6 @@ pub struct PaymentAttempt { pub order_tax_amount: Option, } -#[cfg(feature = "v1")] -impl PaymentAttempt { - pub fn get_or_calculate_net_amount(&self) -> MinorUnit { - self.net_amount.unwrap_or( - self.amount - + self.surcharge_amount.unwrap_or(MinorUnit::new(0)) - + self.tax_amount.unwrap_or(MinorUnit::new(0)) - + self.shipping_cost.unwrap_or(MinorUnit::new(0)) - + self.order_tax_amount.unwrap_or(MinorUnit::new(0)), - ) - } -} - #[derive(Clone, Debug, Eq, PartialEq, Queryable, Serialize, Deserialize)] pub struct PaymentListFilters { pub connector: Vec, @@ -298,47 +285,6 @@ pub struct PaymentAttemptNew { pub order_tax_amount: Option, } -#[cfg(feature = "v1")] -impl PaymentAttemptNew { - /// returns amount + surcharge_amount + tax_amount (surcharge) + shipping_cost + order_tax_amount - pub fn calculate_net_amount(&self) -> MinorUnit { - self.amount - + self.surcharge_amount.unwrap_or(MinorUnit::new(0)) - + self.tax_amount.unwrap_or(MinorUnit::new(0)) - + self.shipping_cost.unwrap_or(MinorUnit::new(0)) - } - - pub fn get_or_calculate_net_amount(&self) -> MinorUnit { - self.net_amount - .unwrap_or_else(|| self.calculate_net_amount()) - } - - pub fn populate_derived_fields(self) -> Self { - let mut payment_attempt_new = self; - payment_attempt_new.net_amount = Some(payment_attempt_new.calculate_net_amount()); - payment_attempt_new - } -} - -#[cfg(feature = "v2")] -impl PaymentAttemptNew { - /// returns amount + surcharge_amount + tax_amount - pub fn calculate_net_amount(&self) -> MinorUnit { - todo!(); - } - - pub fn get_or_calculate_net_amount(&self) -> MinorUnit { - self.net_amount - .unwrap_or_else(|| self.calculate_net_amount()) - } - - pub fn populate_derived_fields(self) -> Self { - let mut payment_attempt_new = self; - payment_attempt_new.net_amount = Some(payment_attempt_new.calculate_net_amount()); - payment_attempt_new - } -} - #[cfg(feature = "v1")] #[derive(Debug, Clone, Serialize, Deserialize)] pub enum PaymentAttemptUpdate { diff --git a/crates/diesel_models/src/query/payment_attempt.rs b/crates/diesel_models/src/query/payment_attempt.rs index ad056aef6d07..67af7a3bef5c 100644 --- a/crates/diesel_models/src/query/payment_attempt.rs +++ b/crates/diesel_models/src/query/payment_attempt.rs @@ -24,7 +24,7 @@ use crate::{ impl PaymentAttemptNew { pub async fn insert(self, conn: &PgPooledConn) -> StorageResult { - generics::generic_insert(conn, self.populate_derived_fields()).await + generics::generic_insert(conn, self).await } } diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index c71e08c79e8e..31423c33d23a 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -11,6 +11,7 @@ use common_utils::{ }; use diesel_models::{ PaymentAttempt as DieselPaymentAttempt, PaymentAttemptNew as DieselPaymentAttemptNew, + PaymentAttemptUpdate as DieselPaymentAttemptUpdate, }; use error_stack::ResultExt; use masking::Secret; @@ -24,7 +25,7 @@ use crate::merchant_key_store::MerchantKeyStore; use crate::{ behaviour, errors, mandates::{MandateDataType, MandateDetails}, - ForeignIDRef, + router_request_types, ForeignIDRef, }; #[async_trait::async_trait] @@ -273,15 +274,12 @@ pub struct PaymentAttempt { pub merchant_id: id_type::MerchantId, pub attempt_id: String, pub status: storage_enums::AttemptStatus, - pub amount: MinorUnit, - pub net_amount: MinorUnit, + pub net_amount: NetAmount, pub currency: Option, pub save_to_locker: Option, pub connector: Option, pub error_message: Option, pub offer_amount: Option, - pub surcharge_amount: Option, - pub tax_amount: Option, pub payment_method_id: Option, pub payment_method: Option, pub connector_transaction_id: Option, @@ -334,8 +332,149 @@ pub struct PaymentAttempt { pub customer_acceptance: Option, pub profile_id: id_type::ProfileId, pub organization_id: id_type::OrganizationId, - pub shipping_cost: Option, - pub order_tax_amount: Option, +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default)] +pub struct NetAmount { + /// The payment amount + order_amount: MinorUnit, + /// The shipping cost of the order + shipping_cost: Option, + /// Tax amount related to the order + order_tax_amount: Option, + /// The surcharge amount to be added to the order + surcharge_amount: Option, + /// tax on surcharge amount + tax_on_surcharge: Option, +} + +impl NetAmount { + pub fn new( + order_amount: MinorUnit, + shipping_cost: Option, + order_tax_amount: Option, + surcharge_amount: Option, + tax_on_surcharge: Option, + ) -> Self { + Self { + order_amount, + shipping_cost, + order_tax_amount, + surcharge_amount, + tax_on_surcharge, + } + } + + pub fn get_order_amount(&self) -> MinorUnit { + self.order_amount + } + + pub fn get_shipping_cost(&self) -> Option { + self.shipping_cost + } + + pub fn get_order_tax_amount(&self) -> Option { + self.order_tax_amount + } + + pub fn get_surcharge_amount(&self) -> Option { + self.surcharge_amount + } + + pub fn get_tax_on_surcharge(&self) -> Option { + self.tax_on_surcharge + } + + pub fn get_total_surcharge_amount(&self) -> Option { + self.surcharge_amount + .map(|surcharge_amount| surcharge_amount + self.tax_on_surcharge.unwrap_or_default()) + } + + pub fn get_total_amount(&self) -> MinorUnit { + self.order_amount + + self.shipping_cost.unwrap_or_default() + + self.order_tax_amount.unwrap_or_default() + + self.surcharge_amount.unwrap_or_default() + + self.tax_on_surcharge.unwrap_or_default() + } + + pub fn set_order_amount(&mut self, order_amount: MinorUnit) { + self.order_amount = order_amount; + } + + pub fn set_order_tax_amount(&mut self, order_tax_amount: Option) { + self.order_tax_amount = order_tax_amount; + } + + pub fn set_surcharge_details( + &mut self, + surcharge_details: Option, + ) { + self.surcharge_amount = surcharge_details + .clone() + .map(|details| details.surcharge_amount); + self.tax_on_surcharge = surcharge_details.map(|details| details.tax_on_surcharge_amount); + } + + pub fn from_payments_request( + payments_request: &api_models::payments::PaymentsRequest, + order_amount: MinorUnit, + ) -> Self { + let surcharge_amount = payments_request + .surcharge_details + .map(|surcharge_details| surcharge_details.surcharge_amount); + let tax_on_surcharge = payments_request + .surcharge_details + .and_then(|surcharge_details| surcharge_details.tax_amount); + Self { + order_amount, + shipping_cost: payments_request.shipping_cost, + order_tax_amount: None, + surcharge_amount, + tax_on_surcharge, + } + } + + #[cfg(feature = "v1")] + pub fn from_payments_request_and_payment_attempt( + payments_request: &api_models::payments::PaymentsRequest, + payment_attempt: Option<&PaymentAttempt>, + ) -> Option { + let option_order_amount = payments_request + .amount + .map(MinorUnit::from) + .or(payment_attempt + .map(|payment_attempt| payment_attempt.net_amount.get_order_amount())); + option_order_amount.map(|order_amount| { + let shipping_cost = payments_request.shipping_cost.or(payment_attempt + .and_then(|payment_attempt| payment_attempt.net_amount.get_shipping_cost())); + let order_tax_amount = payment_attempt + .and_then(|payment_attempt| payment_attempt.net_amount.get_order_tax_amount()); + let surcharge_amount = payments_request + .surcharge_details + .map(|surcharge_details| surcharge_details.get_surcharge_amount()) + .or_else(|| { + payment_attempt.and_then(|payment_attempt| { + payment_attempt.net_amount.get_surcharge_amount() + }) + }); + let tax_on_surcharge = payments_request + .surcharge_details + .and_then(|surcharge_details| surcharge_details.get_tax_amount()) + .or_else(|| { + payment_attempt.and_then(|payment_attempt| { + payment_attempt.net_amount.get_tax_on_surcharge() + }) + }); + Self { + order_amount, + shipping_cost, + order_tax_amount, + surcharge_amount, + tax_on_surcharge, + } + }) + } } #[cfg(feature = "v2")] @@ -352,14 +491,11 @@ impl PaymentAttempt { #[cfg(feature = "v1")] impl PaymentAttempt { pub fn get_total_amount(&self) -> MinorUnit { - self.amount - + self.surcharge_amount.unwrap_or_default() - + self.tax_amount.unwrap_or_default() + self.net_amount.get_total_amount() } pub fn get_total_surcharge_amount(&self) -> Option { - self.surcharge_amount - .map(|surcharge_amount| surcharge_amount + self.tax_amount.unwrap_or_default()) + self.net_amount.get_total_surcharge_amount() } } @@ -429,18 +565,15 @@ pub struct PaymentAttemptNew { pub merchant_id: id_type::MerchantId, pub attempt_id: String, pub status: storage_enums::AttemptStatus, - pub amount: MinorUnit, /// amount + surcharge_amount + tax_amount /// This field will always be derived before updating in the Database - pub net_amount: MinorUnit, + pub net_amount: NetAmount, pub currency: Option, // pub auto_capture: Option, pub save_to_locker: Option, pub connector: Option, pub error_message: Option, pub offer_amount: Option, - pub surcharge_amount: Option, - pub tax_amount: Option, pub payment_method_id: Option, pub payment_method: Option, pub capture_method: Option, @@ -490,45 +623,13 @@ pub struct PaymentAttemptNew { pub customer_acceptance: Option, pub profile_id: id_type::ProfileId, pub organization_id: id_type::OrganizationId, - pub shipping_cost: Option, - pub order_tax_amount: Option, -} - -#[cfg(feature = "v2")] -impl PaymentAttemptNew { - /// returns amount + surcharge_amount + tax_amount - pub fn calculate_net_amount(&self) -> MinorUnit { - todo!(); - } - - pub fn populate_derived_fields(self) -> Self { - todo!() - } -} - -#[cfg(feature = "v1")] -impl PaymentAttemptNew { - /// returns amount + surcharge_amount + tax_amount - pub fn calculate_net_amount(&self) -> MinorUnit { - self.amount - + self.surcharge_amount.unwrap_or_default() - + self.tax_amount.unwrap_or_default() - + self.shipping_cost.unwrap_or_default() - + self.order_tax_amount.unwrap_or_default() - } - - pub fn populate_derived_fields(self) -> Self { - let mut payment_attempt_new = self; - payment_attempt_new.net_amount = payment_attempt_new.calculate_net_amount(); - payment_attempt_new - } } #[cfg(feature = "v1")] #[derive(Debug, Clone, Serialize, Deserialize)] pub enum PaymentAttemptUpdate { Update { - amount: MinorUnit, + net_amount: NetAmount, currency: storage_enums::Currency, status: storage_enums::AttemptStatus, authentication_type: Option, @@ -540,8 +641,6 @@ pub enum PaymentAttemptUpdate { business_sub_label: Option, amount_to_capture: Option, capture_method: Option, - surcharge_amount: Option, - tax_amount: Option, fingerprint_id: Option, payment_method_billing_address_id: Option, updated_by: String, @@ -561,7 +660,7 @@ pub enum PaymentAttemptUpdate { updated_by: String, }, ConfirmUpdate { - amount: MinorUnit, + net_amount: NetAmount, currency: storage_enums::Currency, status: storage_enums::AttemptStatus, authentication_type: Option, @@ -579,8 +678,6 @@ pub enum PaymentAttemptUpdate { error_message: Option>, amount_capturable: Option, updated_by: String, - surcharge_amount: Option, - tax_amount: Option, merchant_connector_id: Option, external_three_ds_authentication_attempted: Option, authentication_connector: Option, @@ -591,8 +688,6 @@ pub enum PaymentAttemptUpdate { client_source: Option, client_version: Option, customer_acceptance: Option, - shipping_cost: Option, - order_tax_amount: Option, }, RejectUpdate { status: storage_enums::AttemptStatus, @@ -694,7 +789,7 @@ pub enum PaymentAttemptUpdate { updated_by: String, }, IncrementalAuthorizationAmountUpdate { - amount: MinorUnit, + net_amount: NetAmount, amount_capturable: MinorUnit, }, AuthenticationUpdate { @@ -716,6 +811,359 @@ pub enum PaymentAttemptUpdate { }, } +#[cfg(feature = "v1")] +impl PaymentAttemptUpdate { + pub fn to_storage_model(self) -> diesel_models::PaymentAttemptUpdate { + match self { + Self::Update { + net_amount, + currency, + status, + authentication_type, + payment_method, + payment_token, + payment_method_data, + payment_method_type, + payment_experience, + business_sub_label, + amount_to_capture, + capture_method, + fingerprint_id, + payment_method_billing_address_id, + updated_by, + } => DieselPaymentAttemptUpdate::Update { + amount: net_amount.get_order_amount(), + currency, + status, + authentication_type, + payment_method, + payment_token, + payment_method_data, + payment_method_type, + payment_experience, + business_sub_label, + amount_to_capture, + capture_method, + surcharge_amount: net_amount.get_surcharge_amount(), + tax_amount: net_amount.get_tax_on_surcharge(), + fingerprint_id, + payment_method_billing_address_id, + updated_by, + }, + Self::UpdateTrackers { + payment_token, + connector, + straight_through_algorithm, + amount_capturable, + updated_by, + surcharge_amount, + tax_amount, + merchant_connector_id, + } => DieselPaymentAttemptUpdate::UpdateTrackers { + payment_token, + connector, + straight_through_algorithm, + amount_capturable, + surcharge_amount, + tax_amount, + updated_by, + merchant_connector_id, + }, + Self::AuthenticationTypeUpdate { + authentication_type, + updated_by, + } => DieselPaymentAttemptUpdate::AuthenticationTypeUpdate { + authentication_type, + updated_by, + }, + Self::BlocklistUpdate { + status, + error_code, + error_message, + updated_by, + } => DieselPaymentAttemptUpdate::BlocklistUpdate { + status, + error_code, + error_message, + updated_by, + }, + Self::PaymentMethodDetailsUpdate { + payment_method_id, + updated_by, + } => DieselPaymentAttemptUpdate::PaymentMethodDetailsUpdate { + payment_method_id, + updated_by, + }, + Self::ConfirmUpdate { + net_amount, + currency, + status, + authentication_type, + capture_method, + payment_method, + browser_info, + connector, + payment_token, + payment_method_data, + payment_method_type, + payment_experience, + business_sub_label, + straight_through_algorithm, + error_code, + error_message, + amount_capturable, + fingerprint_id, + updated_by, + merchant_connector_id: connector_id, + payment_method_id, + external_three_ds_authentication_attempted, + authentication_connector, + authentication_id, + payment_method_billing_address_id, + client_source, + client_version, + customer_acceptance, + } => DieselPaymentAttemptUpdate::ConfirmUpdate { + amount: net_amount.get_order_amount(), + currency, + status, + authentication_type, + capture_method, + payment_method, + browser_info, + connector, + payment_token, + payment_method_data, + payment_method_type, + payment_experience, + business_sub_label, + straight_through_algorithm, + error_code, + error_message, + amount_capturable, + surcharge_amount: net_amount.get_surcharge_amount(), + tax_amount: net_amount.get_tax_on_surcharge(), + fingerprint_id, + updated_by, + merchant_connector_id: connector_id, + payment_method_id, + external_three_ds_authentication_attempted, + authentication_connector, + authentication_id, + payment_method_billing_address_id, + client_source, + client_version, + customer_acceptance, + shipping_cost: net_amount.get_shipping_cost(), + order_tax_amount: net_amount.get_order_tax_amount(), + }, + Self::VoidUpdate { + status, + cancellation_reason, + updated_by, + } => DieselPaymentAttemptUpdate::VoidUpdate { + status, + cancellation_reason, + updated_by, + }, + Self::ResponseUpdate { + status, + connector, + connector_transaction_id, + authentication_type, + payment_method_id, + mandate_id, + connector_metadata, + payment_token, + error_code, + error_message, + error_reason, + connector_response_reference_id, + amount_capturable, + updated_by, + authentication_data, + encoded_data, + unified_code, + unified_message, + payment_method_data, + charge_id, + } => DieselPaymentAttemptUpdate::ResponseUpdate { + status, + connector, + connector_transaction_id, + authentication_type, + payment_method_id, + mandate_id, + connector_metadata, + payment_token, + error_code, + error_message, + error_reason, + connector_response_reference_id, + amount_capturable, + updated_by, + authentication_data, + encoded_data, + unified_code, + unified_message, + payment_method_data, + charge_id, + }, + Self::UnresolvedResponseUpdate { + status, + connector, + connector_transaction_id, + payment_method_id, + error_code, + error_message, + error_reason, + connector_response_reference_id, + updated_by, + } => DieselPaymentAttemptUpdate::UnresolvedResponseUpdate { + status, + connector, + connector_transaction_id, + payment_method_id, + error_code, + error_message, + error_reason, + connector_response_reference_id, + updated_by, + }, + Self::StatusUpdate { status, updated_by } => { + DieselPaymentAttemptUpdate::StatusUpdate { status, updated_by } + } + Self::ErrorUpdate { + connector, + status, + error_code, + error_message, + error_reason, + amount_capturable, + updated_by, + unified_code, + unified_message, + connector_transaction_id, + payment_method_data, + authentication_type, + } => DieselPaymentAttemptUpdate::ErrorUpdate { + connector, + status, + error_code, + error_message, + error_reason, + amount_capturable, + updated_by, + unified_code, + unified_message, + connector_transaction_id, + payment_method_data, + authentication_type, + }, + Self::CaptureUpdate { + multiple_capture_count, + updated_by, + amount_to_capture, + } => DieselPaymentAttemptUpdate::CaptureUpdate { + multiple_capture_count, + updated_by, + amount_to_capture, + }, + Self::PreprocessingUpdate { + status, + payment_method_id, + connector_metadata, + preprocessing_step_id, + connector_transaction_id, + connector_response_reference_id, + updated_by, + } => DieselPaymentAttemptUpdate::PreprocessingUpdate { + status, + payment_method_id, + connector_metadata, + preprocessing_step_id, + connector_transaction_id, + connector_response_reference_id, + updated_by, + }, + Self::RejectUpdate { + status, + error_code, + error_message, + updated_by, + } => DieselPaymentAttemptUpdate::RejectUpdate { + status, + error_code, + error_message, + updated_by, + }, + Self::AmountToCaptureUpdate { + status, + amount_capturable, + updated_by, + } => DieselPaymentAttemptUpdate::AmountToCaptureUpdate { + status, + amount_capturable, + updated_by, + }, + Self::ConnectorResponse { + authentication_data, + encoded_data, + connector_transaction_id, + connector, + charge_id, + updated_by, + } => DieselPaymentAttemptUpdate::ConnectorResponse { + authentication_data, + encoded_data, + connector_transaction_id, + connector, + charge_id, + updated_by, + }, + Self::IncrementalAuthorizationAmountUpdate { + net_amount, + amount_capturable, + } => DieselPaymentAttemptUpdate::IncrementalAuthorizationAmountUpdate { + amount: net_amount.get_order_amount(), + amount_capturable, + }, + Self::AuthenticationUpdate { + status, + external_three_ds_authentication_attempted, + authentication_connector, + authentication_id, + updated_by, + } => DieselPaymentAttemptUpdate::AuthenticationUpdate { + status, + external_three_ds_authentication_attempted, + authentication_connector, + authentication_id, + updated_by, + }, + Self::ManualUpdate { + status, + error_code, + error_message, + error_reason, + updated_by, + unified_code, + unified_message, + connector_transaction_id, + } => DieselPaymentAttemptUpdate::ManualUpdate { + status, + error_code, + error_message, + error_reason, + updated_by, + unified_code, + unified_message, + connector_transaction_id, + }, + } + } +} + // TODO: Add fields as necessary #[cfg(feature = "v2")] #[derive(Debug, Clone, Serialize, Deserialize)] @@ -756,14 +1204,14 @@ impl behaviour::Conversion for PaymentAttempt { merchant_id: self.merchant_id, attempt_id: self.attempt_id, status: self.status, - amount: self.amount, + amount: self.net_amount.get_order_amount(), currency: self.currency, save_to_locker: self.save_to_locker, connector: self.connector, error_message: self.error_message, offer_amount: self.offer_amount, - surcharge_amount: self.surcharge_amount, - tax_amount: self.tax_amount, + surcharge_amount: self.net_amount.get_surcharge_amount(), + tax_amount: self.net_amount.get_tax_on_surcharge(), payment_method_id: self.payment_method_id, payment_method: self.payment_method, connector_transaction_id: self.connector_transaction_id, @@ -798,7 +1246,7 @@ impl behaviour::Conversion for PaymentAttempt { encoded_data: self.encoded_data, unified_code: self.unified_code, unified_message: self.unified_message, - net_amount: Some(self.net_amount), + net_amount: Some(self.net_amount.get_total_amount()), external_three_ds_authentication_attempted: self .external_three_ds_authentication_attempted, authentication_connector: self.authentication_connector, @@ -813,8 +1261,8 @@ impl behaviour::Conversion for PaymentAttempt { profile_id: self.profile_id, organization_id: self.organization_id, card_network, - order_tax_amount: self.order_tax_amount, - shipping_cost: self.shipping_cost, + order_tax_amount: self.net_amount.get_order_tax_amount(), + shipping_cost: self.net_amount.get_shipping_cost(), }) } @@ -828,21 +1276,23 @@ impl behaviour::Conversion for PaymentAttempt { Self: Sized, { async { - let net_amount = storage_model.get_or_calculate_net_amount(); Ok::>(Self { payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, attempt_id: storage_model.attempt_id, status: storage_model.status, - amount: storage_model.amount, - net_amount, + net_amount: NetAmount::new( + storage_model.amount, + storage_model.shipping_cost, + storage_model.order_tax_amount, + storage_model.surcharge_amount, + storage_model.tax_amount, + ), currency: storage_model.currency, save_to_locker: storage_model.save_to_locker, connector: storage_model.connector, error_message: storage_model.error_message, offer_amount: storage_model.offer_amount, - surcharge_amount: storage_model.surcharge_amount, - tax_amount: storage_model.tax_amount, payment_method_id: storage_model.payment_method_id, payment_method: storage_model.payment_method, connector_transaction_id: storage_model.connector_transaction_id, @@ -890,8 +1340,6 @@ impl behaviour::Conversion for PaymentAttempt { customer_acceptance: storage_model.customer_acceptance, profile_id: storage_model.profile_id, organization_id: storage_model.organization_id, - order_tax_amount: storage_model.order_tax_amount, - shipping_cost: storage_model.shipping_cost, }) } .await @@ -915,14 +1363,14 @@ impl behaviour::Conversion for PaymentAttempt { merchant_id: self.merchant_id, attempt_id: self.attempt_id, status: self.status, - amount: self.amount, + amount: self.net_amount.get_order_amount(), currency: self.currency, save_to_locker: self.save_to_locker, connector: self.connector, error_message: self.error_message, offer_amount: self.offer_amount, - surcharge_amount: self.surcharge_amount, - tax_amount: self.tax_amount, + surcharge_amount: self.net_amount.get_surcharge_amount(), + tax_amount: self.net_amount.get_tax_on_surcharge(), payment_method_id: self.payment_method_id, payment_method: self.payment_method, capture_method: self.capture_method, @@ -956,7 +1404,7 @@ impl behaviour::Conversion for PaymentAttempt { encoded_data: self.encoded_data, unified_code: self.unified_code, unified_message: self.unified_message, - net_amount: Some(self.net_amount), + net_amount: Some(self.net_amount.get_total_amount()), external_three_ds_authentication_attempted: self .external_three_ds_authentication_attempted, authentication_connector: self.authentication_connector, @@ -971,8 +1419,8 @@ impl behaviour::Conversion for PaymentAttempt { profile_id: self.profile_id, organization_id: self.organization_id, card_network, - order_tax_amount: self.order_tax_amount, - shipping_cost: self.shipping_cost, + order_tax_amount: self.net_amount.get_order_tax_amount(), + shipping_cost: self.net_amount.get_shipping_cost(), }) } } diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index d26f1975b71f..b67621e9f069 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -512,8 +512,6 @@ pub struct SurchargeDetails { pub surcharge_amount: MinorUnit, /// tax on surcharge amount for this payment pub tax_on_surcharge_amount: MinorUnit, - /// sum of original amount, - pub final_amount: MinorUnit, } impl SurchargeDetails { @@ -546,14 +544,13 @@ impl let surcharge_amount = request_surcharge_details.surcharge_amount; let tax_on_surcharge_amount = request_surcharge_details.tax_amount.unwrap_or_default(); Self { - original_amount: payment_attempt.amount, + original_amount: payment_attempt.net_amount.get_order_amount(), surcharge: common_utils::types::Surcharge::Fixed( request_surcharge_details.surcharge_amount, ), tax_on_surcharge: None, surcharge_amount, tax_on_surcharge_amount, - final_amount: payment_attempt.amount + surcharge_amount + tax_on_surcharge_amount, } } } diff --git a/crates/router/src/core/fraud_check/flows/checkout_flow.rs b/crates/router/src/core/fraud_check/flows/checkout_flow.rs index 92dc2a99e8a6..64c8694a5bf6 100644 --- a/crates/router/src/core/fraud_check/flows/checkout_flow.rs +++ b/crates/router/src/core/fraud_check/flows/checkout_flow.rs @@ -93,7 +93,11 @@ impl ConstructFlowSpecificData( minor_amount_captured: payment_intent.amount_captured, payment_method_status: None, request: FraudCheckFulfillmentData { - amount: payment_attempt.amount.get_amount_as_i64(), + amount: payment_attempt + .net_amount + .get_total_amount() + .get_amount_as_i64(), order_details: payment_intent.order_details.clone(), fulfillment_req: fulfillment_request, }, diff --git a/crates/router/src/core/fraud_check/flows/record_return.rs b/crates/router/src/core/fraud_check/flows/record_return.rs index e4d002931ec2..1c55bffeb870 100644 --- a/crates/router/src/core/fraud_check/flows/record_return.rs +++ b/crates/router/src/core/fraud_check/flows/record_return.rs @@ -88,7 +88,11 @@ impl ConstructFlowSpecificData amount, surcharge_decision_configs::SurchargeOutput::Rate(percentage) => percentage - .apply_and_ceil_result(payment_attempt.amount) + .apply_and_ceil_result(payment_attempt.net_amount.get_total_amount()) .change_context(ConfigError::DslExecutionError) .attach_printable("Failed to Calculate surcharge amount by applying percentage")?, }; @@ -473,7 +473,7 @@ fn get_surcharge_details_from_surcharge_output( .transpose()? .unwrap_or_default(); Ok(types::SurchargeDetails { - original_amount: payment_attempt.amount, + original_amount: payment_attempt.net_amount.get_order_amount(), surcharge: match surcharge_details.surcharge { surcharge_decision_configs::SurchargeOutput::Fixed { amount } => { common_utils_types::Surcharge::Fixed(amount) @@ -485,7 +485,6 @@ fn get_surcharge_details_from_surcharge_output( tax_on_surcharge: surcharge_details.tax_on_surcharge, surcharge_amount, tax_on_surcharge_amount, - final_amount: payment_attempt.amount + surcharge_amount + tax_on_surcharge_amount, }) } diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index d7899e8b9a9c..14e45d17ded4 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -801,7 +801,13 @@ where } }; - payment_data.surcharge_details = calculated_surcharge_details; + payment_data.surcharge_details = calculated_surcharge_details.clone(); + + //Update payment_attempt net_amount with surcharge details + payment_data + .payment_attempt + .net_amount + .set_surcharge_details(calculated_surcharge_details); } else { let surcharge_details = payment_data @@ -854,17 +860,17 @@ pub async fn call_surcharge_decision_management_for_session_flow( billing_address: Option, session_connector_data: &[api::SessionConnectorData], ) -> RouterResult> { - if let Some(surcharge_amount) = payment_attempt.surcharge_amount { - let tax_on_surcharge_amount = payment_attempt.tax_amount.unwrap_or_default(); - let final_amount = payment_attempt.amount + surcharge_amount + tax_on_surcharge_amount; + if let Some(surcharge_amount) = payment_attempt.net_amount.get_surcharge_amount() { Ok(Some(api::SessionSurchargeDetails::PreDetermined( types::SurchargeDetails { - original_amount: payment_attempt.amount, + original_amount: payment_attempt.net_amount.get_order_amount(), surcharge: Surcharge::Fixed(surcharge_amount), tax_on_surcharge: None, surcharge_amount, - tax_on_surcharge_amount, - final_amount, + tax_on_surcharge_amount: payment_attempt + .net_amount + .get_tax_on_surcharge() + .unwrap_or_default(), }, ))) } else { diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index f0f650fa7410..062f75e4bcee 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -479,13 +479,13 @@ pub async fn get_token_pm_type_mandate_details( } } RecurringDetails::MandateId(mandate_id) => { - let mandate_generic_data = get_token_for_recurring_mandate( + let mandate_generic_data = Box::pin(get_token_for_recurring_mandate( state, request, merchant_account, merchant_key_store, mandate_id.to_owned(), - ) + )) .await?; ( @@ -538,13 +538,13 @@ pub async fn get_token_pm_type_mandate_details( } None => { if let Some(mandate_id) = request.mandate_id.clone() { - let mandate_generic_data = get_token_for_recurring_mandate( + let mandate_generic_data = Box::pin(get_token_for_recurring_mandate( state, request, merchant_account, merchant_key_store, mandate_id, - ) + )) .await?; ( mandate_generic_data.token, @@ -726,9 +726,26 @@ pub async fn get_token_for_recurring_mandate( .await .flatten(); - let original_payment_authorized_amount = original_payment_intent + let original_payment_attempt = original_payment_intent + .as_ref() + .async_map(|payment_intent| async { + db.find_payment_attempt_by_payment_id_merchant_id_attempt_id( + &payment_intent.payment_id, + &mandate.merchant_id, + payment_intent.active_attempt.get_id().as_str(), + merchant_account.storage_scheme, + ) + .await + .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound) + .map_err(|err| logger::error!(mandate_original_payment_attempt_not_found=?err)) + .ok() + }) + .await + .flatten(); + + let original_payment_authorized_amount = original_payment_attempt .clone() - .map(|pi| pi.amount.get_amount_as_i64()); + .map(|pa| pa.net_amount.get_total_amount().get_amount_as_i64()); let original_payment_authorized_currency = original_payment_intent.clone().and_then(|pi| pi.currency); let customer = req.get_customer_id().get_required_value("customer_id")?; @@ -894,28 +911,18 @@ pub fn validate_amount_to_capture_and_capture_method( payment_attempt: Option<&PaymentAttempt>, request: &api_models::payments::PaymentsRequest, ) -> CustomResult<(), errors::ApiErrorResponse> { + let option_net_amount = hyperswitch_domain_models::payments::payment_attempt::NetAmount::from_payments_request_and_payment_attempt( + request, + payment_attempt, + ); let capture_method = request .capture_method .or(payment_attempt .map(|payment_attempt| payment_attempt.capture_method.unwrap_or_default())) .unwrap_or_default(); if capture_method == api_enums::CaptureMethod::Automatic { - let original_amount = request - .amount - .map(MinorUnit::from) - .or(payment_attempt.map(|payment_attempt| payment_attempt.amount)); - let surcharge_amount = request - .surcharge_details - .map(|surcharge_details| surcharge_details.get_total_surcharge_amount()) - .or_else(|| { - payment_attempt.map(|payment_attempt| { - payment_attempt.surcharge_amount.unwrap_or_default() - + payment_attempt.tax_amount.unwrap_or_default() - }) - }) - .unwrap_or_default(); let total_capturable_amount = - original_amount.map(|original_amount| original_amount + surcharge_amount); + option_net_amount.map(|net_amount| net_amount.get_total_amount()); let amount_to_capture = request .amount_to_capture @@ -3931,7 +3938,6 @@ impl AttemptType { // A new payment attempt is getting created so, used the same function which is used to populate status in PaymentCreate Flow. status: payment_attempt_status_fsm(payment_method_data, Some(true)), - amount: old_payment_attempt.amount, currency: old_payment_attempt.currency, save_to_locker: old_payment_attempt.save_to_locker, @@ -3939,8 +3945,6 @@ impl AttemptType { error_message: None, offer_amount: old_payment_attempt.offer_amount, - surcharge_amount: None, - tax_amount: None, payment_method_id: None, payment_method: None, capture_method: old_payment_attempt.capture_method, @@ -3976,14 +3980,14 @@ impl AttemptType { error_reason: None, multiple_capture_count: None, connector_response_reference_id: None, - amount_capturable: old_payment_attempt.amount, + amount_capturable: old_payment_attempt.net_amount.get_total_amount(), updated_by: storage_scheme.to_string(), authentication_data: None, encoded_data: None, merchant_connector_id: None, unified_code: None, unified_message: None, - net_amount: old_payment_attempt.amount, + net_amount: old_payment_attempt.net_amount, external_three_ds_authentication_attempted: old_payment_attempt .external_three_ds_authentication_attempted, authentication_connector: None, @@ -3998,8 +4002,6 @@ impl AttemptType { customer_acceptance: old_payment_attempt.customer_acceptance, organization_id: old_payment_attempt.organization_id, profile_id: old_payment_attempt.profile_id, - shipping_cost: old_payment_attempt.shipping_cost, - order_tax_amount: None, } } diff --git a/crates/router/src/core/payments/operations/payment_complete_authorize.rs b/crates/router/src/core/payments/operations/payment_complete_authorize.rs index 99d8df2dfe98..92e462c78bcb 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -125,7 +125,7 @@ impl GetTracker, api::PaymentsRequest> for Co recurring_mandate_payment_data, mandate_connector, payment_method_info, - } = helpers::get_token_pm_type_mandate_details( + } = Box::pin(helpers::get_token_pm_type_mandate_details( state, request, mandate_type.to_owned(), @@ -133,7 +133,7 @@ impl GetTracker, api::PaymentsRequest> for Co key_store, payment_attempt.payment_method_id.clone(), payment_intent.customer_id.as_ref(), - ) + )) .await?; let customer_acceptance: Option = request .customer_acceptance diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index 658a02f7d080..77ba5676c27d 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -540,7 +540,7 @@ impl GetTracker, api::PaymentsRequest> for Pa let mandate_details_fut = tokio::spawn( async move { - helpers::get_token_pm_type_mandate_details( + Box::pin(helpers::get_token_pm_type_mandate_details( &m_state, &m_request, m_mandate_type, @@ -548,7 +548,7 @@ impl GetTracker, api::PaymentsRequest> for Pa &m_key_store, None, payment_intent_customer_id.as_ref(), - ) + )) .await } .in_current_span(), @@ -690,6 +690,26 @@ impl GetTracker, api::PaymentsRequest> for Pa _ => None, }); + let pmt_order_tax_amount = payment_intent.tax_details.clone().and_then(|tax| { + if tax.payment_method_type.clone().map(|a| a.pmt) == payment_attempt.payment_method_type + { + tax.payment_method_type.map(|a| a.order_tax_amount) + } else { + None + } + }); + + let order_tax_amount = pmt_order_tax_amount.or_else(|| { + payment_intent + .tax_details + .clone() + .and_then(|tax| tax.default.map(|a| a.order_tax_amount)) + }); + + payment_attempt + .net_amount + .set_order_tax_amount(order_tax_amount); + let payment_data = PaymentData { flow: PhantomData, payment_intent, @@ -1222,11 +1242,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen let order_details = payment_data.payment_intent.order_details.clone(); let metadata = payment_data.payment_intent.metadata.clone(); let frm_metadata = payment_data.payment_intent.frm_metadata.clone(); - let authorized_amount = payment_data - .surcharge_details - .as_ref() - .map(|surcharge_details| surcharge_details.final_amount) - .unwrap_or(payment_data.payment_attempt.amount); + let authorized_amount = payment_data.payment_attempt.get_total_amount(); let client_source = header_payload .client_source @@ -1280,37 +1296,11 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen None => (None, None, None), }; - let shipping_cost = payment_data.payment_intent.shipping_cost; - - let pmt_order_tax_amount = - payment_data - .payment_intent - .tax_details - .clone() - .and_then(|tax| { - if tax.payment_method_type.clone().map(|a| a.pmt) - == payment_data.payment_attempt.payment_method_type - { - tax.payment_method_type.map(|a| a.order_tax_amount) - } else { - None - } - }); - - let order_tax_amount = pmt_order_tax_amount.or_else(|| { - payment_data - .payment_intent - .tax_details - .clone() - .and_then(|tax| tax.default.map(|a| a.order_tax_amount)) - }); - let payment_attempt_fut = tokio::spawn( async move { m_db.update_payment_attempt_with_attempt_id( m_payment_data_payment_attempt, storage::PaymentAttemptUpdate::ConfirmUpdate { - amount: payment_data.payment_attempt.amount, currency: payment_data.currency, status: attempt_status, payment_method, @@ -1329,8 +1319,6 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen amount_capturable: Some(authorized_amount), updated_by: storage_scheme.to_string(), merchant_connector_id, - surcharge_amount, - tax_amount, external_three_ds_authentication_attempted, authentication_connector, authentication_id, @@ -1340,8 +1328,17 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen client_source, client_version, customer_acceptance: payment_data.payment_attempt.customer_acceptance, - shipping_cost, - order_tax_amount, + net_amount: + hyperswitch_domain_models::payments::payment_attempt::NetAmount::new( + payment_data.payment_attempt.net_amount.get_order_amount(), + payment_data.payment_intent.shipping_cost, + payment_data + .payment_attempt + .net_amount + .get_order_tax_amount(), + surcharge_amount, + tax_amount, + ), }, storage_scheme, ) diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 0921e38317a6..46f313278fd1 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -801,7 +801,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen .payment_attempt .straight_through_algorithm .clone(); - let authorized_amount = payment_data.payment_attempt.amount; + let authorized_amount = payment_data.payment_attempt.get_total_amount(); let merchant_connector_id = payment_data.payment_attempt.merchant_connector_id.clone(); let surcharge_amount = payment_data @@ -1113,12 +1113,6 @@ impl PaymentCreate { } else { payment_id.get_attempt_id(1) }; - let surcharge_amount = request - .surcharge_details - .map(|surcharge_details| surcharge_details.surcharge_amount); - let tax_amount = request - .surcharge_details - .and_then(|surcharge_details| surcharge_details.tax_amount); if request.mandate_data.as_ref().map_or(false, |mandate_data| { mandate_data.update_mandate_id.is_some() && mandate_data.mandate_type.is_some() @@ -1146,7 +1140,6 @@ impl PaymentCreate { attempt_id, status, currency, - amount: MinorUnit::from(amount), payment_method, capture_method: request.capture_method, capture_on: request.capture_on, @@ -1163,8 +1156,6 @@ impl PaymentCreate { payment_token: request.payment_token.clone(), mandate_id: request.mandate_id.clone(), business_sub_label: request.business_sub_label.clone(), - surcharge_amount, - tax_amount, mandate_details: request .mandate_data .as_ref() @@ -1172,7 +1163,10 @@ impl PaymentCreate { external_three_ds_authentication_attempted: None, mandate_data, payment_method_billing_address_id, - net_amount: MinorUnit::new(i64::default()), + net_amount: hyperswitch_domain_models::payments::payment_attempt::NetAmount::from_payments_request( + request, + MinorUnit::from(amount), + ), save_to_locker: None, connector: None, error_message: None, @@ -1210,8 +1204,6 @@ impl PaymentCreate { .map(Secret::new), organization_id: organization_id.clone(), profile_id, - shipping_cost: request.shipping_cost, - order_tax_amount: None, }, additional_pm_data, )) diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 6a5299db8c41..fd5c544b2857 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -371,18 +371,25 @@ impl PostUpdateTracker, types::PaymentsIncrementalAu .attach_printable("missing incremental_authorization_details in payment_data") })?; // Update payment_intent and payment_attempt 'amount' if incremental_authorization is successful - let (option_payment_attempt_update, option_payment_intent_update) = - match router_data.response.clone() { - Err(_) => (None, None), - Ok(types::PaymentsResponseData::IncrementalAuthorizationResponse { - status, - .. - }) => { - if status == AuthorizationStatus::Success { - ( + let (option_payment_attempt_update, option_payment_intent_update) = match router_data + .response + .clone() + { + Err(_) => (None, None), + Ok(types::PaymentsResponseData::IncrementalAuthorizationResponse { + status, .. + }) => { + if status == AuthorizationStatus::Success { + ( Some( storage::PaymentAttemptUpdate::IncrementalAuthorizationAmountUpdate { - amount: incremental_authorization_details.total_amount, + net_amount: hyperswitch_domain_models::payments::payment_attempt::NetAmount::new( + incremental_authorization_details.total_amount, + None, + None, + None, + None, + ), amount_capturable: incremental_authorization_details.total_amount, }, ), @@ -392,13 +399,13 @@ impl PostUpdateTracker, types::PaymentsIncrementalAu }, ), ) - } else { - (None, None) - } + } else { + (None, None) } - _ => Err(errors::ApiErrorResponse::InternalServerError) - .attach_printable("unexpected response in incremental_authorization flow")?, - }; + } + _ => Err(errors::ApiErrorResponse::InternalServerError) + .attach_printable("unexpected response in incremental_authorization flow")?, + }; //payment_attempt update if let Some(payment_attempt_update) = option_payment_attempt_update { #[cfg(feature = "v1")] @@ -1657,7 +1664,13 @@ async fn payment_response_update_tracker( tokenization::update_connector_mandate_details_in_payment_method( payment_method.clone(), payment_method.payment_method_type, - Some(payment_data.payment_attempt.amount.get_amount_as_i64()), + Some( + payment_data + .payment_attempt + .net_amount + .get_total_amount() + .get_amount_as_i64(), + ), payment_data.payment_attempt.currency, payment_data.payment_attempt.merchant_connector_id.clone(), connector_mandate_id, diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index c69595d1893e..5dc4168dfcd8 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -150,7 +150,7 @@ impl GetTracker, api::PaymentsRequest> for Pa recurring_mandate_payment_data, mandate_connector, payment_method_info, - } = helpers::get_token_pm_type_mandate_details( + } = Box::pin(helpers::get_token_pm_type_mandate_details( state, request, mandate_type.to_owned(), @@ -158,7 +158,7 @@ impl GetTracker, api::PaymentsRequest> for Pa key_store, None, payment_intent.customer_id.as_ref(), - ) + )) .await?; helpers::validate_amount_to_capture_and_capture_method(Some(&payment_attempt), request)?; @@ -186,7 +186,7 @@ impl GetTracker, api::PaymentsRequest> for Pa let amount = request .amount - .unwrap_or_else(|| payment_attempt.amount.into()); + .unwrap_or_else(|| payment_attempt.net_amount.get_order_amount().into()); if request.confirm.unwrap_or(false) { helpers::validate_customer_id_mandatory_cases( @@ -348,8 +348,8 @@ impl GetTracker, api::PaymentsRequest> for Pa let amount = request .amount .map(Into::into) - .unwrap_or(payment_attempt.amount); - payment_attempt.amount = amount; + .unwrap_or(payment_attempt.net_amount.get_order_amount()); + payment_attempt.net_amount.set_order_amount(amount); payment_intent.amount = amount; let surcharge_amount = request .surcharge_details @@ -779,7 +779,6 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen .update_payment_attempt_with_attempt_id( payment_data.payment_attempt, storage::PaymentAttemptUpdate::Update { - amount: payment_data.amount.into(), currency: payment_data.currency, status: get_attempt_status(), authentication_type: None, @@ -791,11 +790,17 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen business_sub_label, amount_to_capture, capture_method, - surcharge_amount, - tax_amount, fingerprint_id: None, payment_method_billing_address_id, updated_by: storage_scheme.to_string(), + net_amount: + hyperswitch_domain_models::payments::payment_attempt::NetAmount::new( + payment_data.amount.into(), + None, + None, + surcharge_amount, + tax_amount, + ), }, storage_scheme, ) diff --git a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs index 4e020c788b64..758a17d3fa74 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -89,12 +89,6 @@ impl })? } - if payment_intent.amount > request.amount { - Err(errors::ApiErrorResponse::PreconditionFailed { - message: "Amount should be greater than original authorized amount".to_owned(), - })? - } - let attempt_id = payment_intent.active_attempt.get_id().clone(); let payment_attempt = db .find_payment_attempt_by_payment_id_merchant_id_attempt_id( @@ -106,6 +100,14 @@ impl .await .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; + // Incremental authorization should be performed on an amount greater than the original authorized amount (in this case, greater than the net_amount which is sent for authorization) + // request.amount is the total amount that should be authorized in incremental authorization which should be greater than the original authorized amount + if payment_attempt.get_total_amount() > request.amount { + Err(errors::ApiErrorResponse::PreconditionFailed { + message: "Amount should be greater than original authorized amount".to_owned(), + })? + } + let currency = payment_attempt.currency.get_required_value("currency")?; let amount = payment_attempt.get_total_amount(); @@ -232,7 +234,7 @@ impl UpdateTracker, PaymentsIncrementalAut error_code: None, error_message: None, connector_authorization_id: None, - previously_authorized_amount: payment_data.payment_intent.amount, + previously_authorized_amount: payment_data.payment_attempt.get_total_amount(), }; let authorization = state .store diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index c3c4a6d01ab4..374c5680685f 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -588,12 +588,9 @@ pub fn make_new_payment_attempt( payment_id: old_payment_attempt.payment_id, merchant_id: old_payment_attempt.merchant_id, status: old_payment_attempt.status, - amount: old_payment_attempt.amount, currency: old_payment_attempt.currency, save_to_locker: old_payment_attempt.save_to_locker, offer_amount: old_payment_attempt.offer_amount, - surcharge_amount: old_payment_attempt.surcharge_amount, - tax_amount: old_payment_attempt.tax_amount, payment_method_id: old_payment_attempt.payment_method_id, payment_method: old_payment_attempt.payment_method, payment_method_type: old_payment_attempt.payment_method_type, @@ -616,8 +613,7 @@ pub fn make_new_payment_attempt( last_synced, profile_id: old_payment_attempt.profile_id, organization_id: old_payment_attempt.organization_id, - shipping_cost: old_payment_attempt.shipping_cost, - net_amount: Default::default(), + net_amount: old_payment_attempt.net_amount, error_message: Default::default(), cancellation_reason: Default::default(), error_code: Default::default(), @@ -646,7 +642,6 @@ pub fn make_new_payment_attempt( fingerprint_id: Default::default(), charge_id: Default::default(), customer_acceptance: Default::default(), - order_tax_amount: Default::default(), } } diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index 04080a427306..c3a7900b434a 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -232,7 +232,7 @@ pub fn make_dsl_input( }; let payment_input = dsl_inputs::PaymentInput { - amount: payments_dsl_input.payment_intent.amount, + amount: payments_dsl_input.payment_attempt.get_total_amount(), card_bin: payments_dsl_input.payment_method_data.as_ref().and_then( |pm_data| match pm_data { domain::PaymentMethodData::Card(card) => { @@ -864,7 +864,7 @@ pub async fn perform_session_flow_routing( #[cfg(feature = "v1")] let payment_input = dsl_inputs::PaymentInput { - amount: session_input.payment_intent.amount, + amount: session_input.payment_attempt.get_total_amount(), currency: session_input .payment_intent .currency @@ -1159,7 +1159,7 @@ pub fn make_dsl_input_for_surcharge( }; let payment_input = dsl_inputs::PaymentInput { - amount: payment_attempt.amount, + amount: payment_attempt.get_total_amount(), // currency is always populated in payment_attempt during payment create currency: payment_attempt .currency diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index f96ead676a73..0d8322854f07 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -703,7 +703,12 @@ where .as_ref() .get_required_value("currency")?; let amount = currency - .to_currency_base_unit(payment_attempt.amount.get_amount_as_i64()) + .to_currency_base_unit( + payment_attempt + .net_amount + .get_total_amount() + .get_amount_as_i64(), + ) .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "amount", })?; @@ -777,10 +782,11 @@ where let surcharge_details = payment_attempt - .surcharge_amount + .net_amount + .get_surcharge_amount() .map(|surcharge_amount| RequestSurchargeDetails { surcharge_amount, - tax_amount: payment_attempt.tax_amount, + tax_amount: payment_attempt.net_amount.get_tax_on_surcharge(), }); let merchant_decision = payment_intent.merchant_decision.to_owned(); let frm_message = payment_data.get_frm_message().map(FrmMessage::foreign_from); @@ -1041,7 +1047,7 @@ where ))?; Some(PaymentChargeResponse { - charge_id: payment_attempt.charge_id, + charge_id: payment_attempt.charge_id.clone(), charge_type: payment_charges.charge_type, application_fees: payment_charges.fees, transfer_account_id: payment_charges.transfer_account_id, @@ -1096,7 +1102,8 @@ where let order_tax_amount = payment_data .get_payment_attempt() - .order_tax_amount + .net_amount + .get_order_tax_amount() .or_else(|| { payment_data .get_payment_intent() @@ -1124,8 +1131,8 @@ where payment_id: payment_intent.payment_id, merchant_id: payment_intent.merchant_id, status: payment_intent.status, - amount: payment_attempt.amount, - net_amount: payment_attempt.net_amount, + amount: payment_attempt.net_amount.get_order_amount(), + net_amount: payment_attempt.get_total_amount(), amount_capturable: payment_attempt.amount_capturable, amount_received: payment_intent.amount_captured, connector: routed_through, @@ -1424,7 +1431,7 @@ impl ForeignFrom<(storage::PaymentIntent, storage::PaymentAttempt)> for api::Pay } ), // TODO: fill in details based on requirement - net_amount: pa.net_amount, + net_amount: pa.net_amount.get_total_amount(), amount_received: None, refunds: None, disputes: None, @@ -1690,11 +1697,7 @@ impl TryFrom> for types::PaymentsAuthoriz None } }); - let amount = payment_data - .surcharge_details - .as_ref() - .map(|surcharge_details| surcharge_details.final_amount) - .unwrap_or(payment_data.amount.into()); + let amount = payment_data.payment_attempt.get_total_amount(); let customer_name = additional_data .customer_data @@ -1791,11 +1794,7 @@ impl TryFrom> for types::PaymentsSyncData fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result { let payment_data = additional_data.payment_data; let capture_method = payment_data.get_capture_method(); - let amount = payment_data - .surcharge_details - .as_ref() - .map(|surcharge_details| surcharge_details.final_amount) - .unwrap_or(payment_data.amount.into()); + let amount = payment_data.payment_attempt.get_total_amount(); let payment_method_type = payment_data .payment_attempt @@ -1936,7 +1935,7 @@ impl TryFrom> for types::PaymentsCaptureD let amount_to_capture = payment_data .payment_attempt .amount_to_capture - .map_or(payment_data.amount.into(), |capture_amount| capture_amount); + .unwrap_or(payment_data.payment_attempt.get_total_amount()); let browser_info: Option = payment_data .payment_attempt .browser_info @@ -1946,7 +1945,7 @@ impl TryFrom> for types::PaymentsCaptureD .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "browser_info", })?; - let amount = MinorUnit::from(payment_data.amount); + let amount = payment_data.payment_attempt.get_total_amount(); Ok(Self { amount_to_capture: amount_to_capture.get_amount_as_i64(), // This should be removed once we start moving to connector module minor_amount_to_capture: amount_to_capture, @@ -2005,7 +2004,7 @@ impl TryFrom> for types::PaymentsCancelDa .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "browser_info", })?; - let amount = MinorUnit::from(payment_data.amount); + let amount = payment_data.payment_attempt.get_total_amount(); Ok(Self { amount: Some(amount.get_amount_as_i64()), // This should be removed once we start moving to connector module minor_amount: Some(amount), @@ -2027,7 +2026,7 @@ impl TryFrom> for types::PaymentsApproveD fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result { let payment_data = additional_data.payment_data; - let amount = MinorUnit::from(payment_data.amount); + let amount = payment_data.payment_attempt.get_total_amount(); Ok(Self { amount: Some(amount.get_amount_as_i64()), //need to change after we move to connector module currency: Some(payment_data.currency), @@ -2058,10 +2057,22 @@ impl TryFrom> for types::SdkPaymentsSessi .ok_or(errors::ApiErrorResponse::MissingRequiredField { field_name: "order_tax_amount", })?; - let amount = payment_data.payment_intent.amount; - + let surcharge_amount = payment_data + .surcharge_details + .as_ref() + .map(|surcharge_details| surcharge_details.get_total_surcharge_amount()) + .unwrap_or_default(); + let shipping_cost = payment_data + .payment_intent + .shipping_cost + .unwrap_or_default(); + // net_amount here would include amount, order_tax_amount, surcharge_amount and shipping_cost + let net_amount = payment_data.payment_intent.amount + + order_tax_amount + + shipping_cost + + surcharge_amount; Ok(Self { - net_amount: amount + order_tax_amount, //need to change after we move to connector module + net_amount, order_tax_amount, }) } @@ -2072,7 +2083,7 @@ impl TryFrom> for types::PaymentsRejectDa fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result { let payment_data = additional_data.payment_data; - let amount = MinorUnit::from(payment_data.amount); + let amount = payment_data.payment_attempt.get_total_amount(); Ok(Self { amount: Some(amount.get_amount_as_i64()), //need to change after we move to connector module currency: Some(payment_data.currency), @@ -2103,14 +2114,31 @@ impl TryFrom> for types::PaymentsSessionD .collect::, _>>() }) .transpose()?; - let amount = payment_data + let surcharge_amount = payment_data .surcharge_details .as_ref() - .map(|surcharge_details| surcharge_details.final_amount) - .unwrap_or(payment_data.amount.into()); + .map(|surcharge_details| surcharge_details.get_total_surcharge_amount()) + .unwrap_or_default(); + #[cfg(feature = "v1")] + let amount = payment_data.payment_intent.amount; + #[cfg(feature = "v2")] + let amount = payment_data.payment_intent.amount_details.order_amount; + #[cfg(feature = "v1")] + let shipping_cost = payment_data + .payment_intent + .shipping_cost + .unwrap_or_default(); + #[cfg(feature = "v2")] + let shipping_cost = payment_data + .payment_intent + .amount_details + .shipping_cost + .unwrap_or_default(); + // net_amount here would include amount, surcharge_amount and shipping_cost + let net_amount = amount + surcharge_amount + shipping_cost; Ok(Self { - amount: amount.get_amount_as_i64(), //need to change once we move to connector module + amount: net_amount.get_amount_as_i64(), //need to change once we move to connector module minor_amount: amount, currency: payment_data.currency, country: payment_data.address.get_payment_method_billing().and_then( @@ -2160,7 +2188,7 @@ impl TryFrom> for types::SetupMandateRequ .as_ref() .map(|customer| customer.clone().into_inner()) }); - let amount = MinorUnit::from(payment_data.amount); + let amount = payment_data.payment_attempt.get_total_amount(); Ok(Self { currency: payment_data.currency, confirm: true, @@ -2269,11 +2297,7 @@ impl TryFrom> for types::CompleteAuthoriz payload: redirect.json_payload, } }); - let amount = payment_data - .surcharge_details - .as_ref() - .map(|surcharge_details| surcharge_details.final_amount) - .unwrap_or(payment_data.amount.into()); + let amount = payment_data.payment_attempt.get_total_amount(); let complete_authorize_url = Some(helpers::create_complete_authorize_url( router_base_url, attempt, @@ -2375,11 +2399,7 @@ impl TryFrom> for types::PaymentsPreProce .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "browser_info", })?; - let amount = payment_data - .surcharge_details - .as_ref() - .map(|surcharge_details| surcharge_details.final_amount) - .unwrap_or(payment_data.amount.into()); + let amount = payment_data.payment_attempt.get_total_amount(); Ok(Self { payment_method_data: payment_method_data.map(From::from), diff --git a/crates/router/src/core/payments/types.rs b/crates/router/src/core/payments/types.rs index 01533cefa5a1..3034b74db455 100644 --- a/crates/router/src/core/payments/types.rs +++ b/crates/router/src/core/payments/types.rs @@ -212,8 +212,6 @@ impl ForeignTryFrom<(&SurchargeDetails, &PaymentAttempt)> for SurchargeDetailsRe .tax_on_surcharge_amount .get_amount_as_i64(), )?; - let display_final_amount = currency - .to_currency_base_unit_asf64(surcharge_details.final_amount.get_amount_as_i64())?; let display_total_surcharge_amount = currency.to_currency_base_unit_asf64( (surcharge_details.surcharge_amount + surcharge_details.tax_on_surcharge_amount) .get_amount_as_i64(), @@ -224,7 +222,6 @@ impl ForeignTryFrom<(&SurchargeDetails, &PaymentAttempt)> for SurchargeDetailsRe display_surcharge_amount, display_tax_on_surcharge_amount, display_total_surcharge_amount, - display_final_amount, }) } } diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index 7a26048a4d9a..cf0374fe826b 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -178,7 +178,7 @@ pub async fn trigger_refund_to_gateway( &routed_through, merchant_account, key_store, - (payment_attempt.amount, currency), + (payment_attempt.get_total_amount(), currency), payment_intent, payment_attempt, refund, @@ -521,7 +521,7 @@ pub async fn sync_refund_with_gateway( &connector_id, merchant_account, key_store, - (payment_attempt.amount, currency), + (payment_attempt.get_total_amount(), currency), payment_intent, payment_attempt, refund, @@ -780,7 +780,7 @@ pub async fn validate_and_create_refund( let total_amount_captured = payment_intent .amount_captured - .unwrap_or(payment_attempt.amount); + .unwrap_or(payment_attempt.get_total_amount()); validator::validate_refund_amount( total_amount_captured.get_amount_as_i64(), @@ -809,7 +809,7 @@ pub async fn validate_and_create_refund( connector_transaction_id: connecter_transaction_id.to_string(), connector, refund_type: req.refund_type.unwrap_or_default().foreign_into(), - total_amount: payment_attempt.amount, + total_amount: payment_attempt.get_total_amount(), refund_amount, currency, created_at: common_utils::date_time::now(), diff --git a/crates/router/src/services/kafka/payment_attempt.rs b/crates/router/src/services/kafka/payment_attempt.rs index 76894928434a..e585b21d4b2b 100644 --- a/crates/router/src/services/kafka/payment_attempt.rs +++ b/crates/router/src/services/kafka/payment_attempt.rs @@ -67,14 +67,14 @@ impl<'a> KafkaPaymentAttempt<'a> { merchant_id: &attempt.merchant_id, attempt_id: &attempt.attempt_id, status: attempt.status, - amount: attempt.amount, + amount: attempt.net_amount.get_order_amount(), currency: attempt.currency, save_to_locker: attempt.save_to_locker, connector: attempt.connector.as_ref(), error_message: attempt.error_message.as_ref(), offer_amount: attempt.offer_amount, - surcharge_amount: attempt.surcharge_amount, - tax_amount: attempt.tax_amount, + surcharge_amount: attempt.net_amount.get_surcharge_amount(), + tax_amount: attempt.net_amount.get_tax_on_surcharge(), payment_method_id: attempt.payment_method_id.as_ref(), payment_method: attempt.payment_method, connector_transaction_id: attempt.connector_transaction_id.as_ref(), @@ -98,7 +98,7 @@ impl<'a> KafkaPaymentAttempt<'a> { multiple_capture_count: attempt.multiple_capture_count, amount_capturable: attempt.amount_capturable, merchant_connector_id: attempt.merchant_connector_id.as_ref(), - net_amount: attempt.net_amount, + net_amount: attempt.net_amount.get_total_amount(), unified_code: attempt.unified_code.as_ref(), unified_message: attempt.unified_message.as_ref(), mandate_data: attempt.mandate_data.as_ref(), diff --git a/crates/router/src/services/kafka/payment_attempt_event.rs b/crates/router/src/services/kafka/payment_attempt_event.rs index b4d6cd8835ad..cbce46ad9c75 100644 --- a/crates/router/src/services/kafka/payment_attempt_event.rs +++ b/crates/router/src/services/kafka/payment_attempt_event.rs @@ -68,14 +68,14 @@ impl<'a> KafkaPaymentAttemptEvent<'a> { merchant_id: &attempt.merchant_id, attempt_id: &attempt.attempt_id, status: attempt.status, - amount: attempt.amount, + amount: attempt.net_amount.get_order_amount(), currency: attempt.currency, save_to_locker: attempt.save_to_locker, connector: attempt.connector.as_ref(), error_message: attempt.error_message.as_ref(), offer_amount: attempt.offer_amount, - surcharge_amount: attempt.surcharge_amount, - tax_amount: attempt.tax_amount, + surcharge_amount: attempt.net_amount.get_surcharge_amount(), + tax_amount: attempt.net_amount.get_tax_on_surcharge(), payment_method_id: attempt.payment_method_id.as_ref(), payment_method: attempt.payment_method, connector_transaction_id: attempt.connector_transaction_id.as_ref(), @@ -99,7 +99,7 @@ impl<'a> KafkaPaymentAttemptEvent<'a> { multiple_capture_count: attempt.multiple_capture_count, amount_capturable: attempt.amount_capturable, merchant_connector_id: attempt.merchant_connector_id.as_ref(), - net_amount: attempt.net_amount, + net_amount: attempt.net_amount.get_total_amount(), unified_code: attempt.unified_code.as_ref(), unified_message: attempt.unified_message.as_ref(), mandate_data: attempt.mandate_data.as_ref(), diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 548d216d6e8f..11f63d6c0217 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -252,15 +252,16 @@ pub trait Capturable { } impl Capturable for PaymentsAuthorizeData { - fn get_captured_amount(&self, _payment_data: &PaymentData) -> Option + fn get_captured_amount(&self, payment_data: &PaymentData) -> Option where F: Clone, { - let final_amount = self - .surcharge_details - .as_ref() - .map(|surcharge_details| surcharge_details.final_amount.get_amount_as_i64()); - final_amount.or(Some(self.amount)) + Some( + payment_data + .payment_attempt + .get_total_amount() + .get_amount_as_i64(), + ) } fn get_amount_capturable( @@ -331,11 +332,16 @@ impl Capturable for PaymentsCaptureData { } impl Capturable for CompleteAuthorizeData { - fn get_captured_amount(&self, _payment_data: &PaymentData) -> Option + fn get_captured_amount(&self, payment_data: &PaymentData) -> Option where F: Clone, { - Some(self.amount) + Some( + payment_data + .payment_attempt + .get_total_amount() + .get_amount_as_i64(), + ) } fn get_amount_capturable( &self, diff --git a/crates/router/src/types/storage/payment_attempt.rs b/crates/router/src/types/storage/payment_attempt.rs index f6caa64fe6e1..88d9b433ecb0 100644 --- a/crates/router/src/types/storage/payment_attempt.rs +++ b/crates/router/src/types/storage/payment_attempt.rs @@ -79,12 +79,14 @@ impl PaymentAttemptExt for PaymentAttempt { #[cfg(feature = "v1")] fn get_surcharge_details(&self) -> Option { - self.surcharge_amount.map(|surcharge_amount| { - api_models::payments::RequestSurchargeDetails { - surcharge_amount, - tax_amount: self.tax_amount, - } - }) + self.net_amount + .get_surcharge_amount() + .map( + |surcharge_amount| api_models::payments::RequestSurchargeDetails { + surcharge_amount, + tax_amount: self.net_amount.get_tax_on_surcharge(), + }, + ) } #[cfg(feature = "v2")] @@ -94,9 +96,7 @@ impl PaymentAttemptExt for PaymentAttempt { #[cfg(feature = "v1")] fn get_total_amount(&self) -> MinorUnit { - self.amount - + self.surcharge_amount.unwrap_or_default() - + self.tax_amount.unwrap_or_default() + self.net_amount.get_total_amount() } #[cfg(feature = "v2")] @@ -167,14 +167,11 @@ mod tests { merchant_id: Default::default(), attempt_id: Default::default(), status: Default::default(), - amount: Default::default(), net_amount: Default::default(), currency: Default::default(), save_to_locker: Default::default(), error_message: Default::default(), offer_amount: Default::default(), - surcharge_amount: Default::default(), - tax_amount: Default::default(), payment_method_id: Default::default(), payment_method: Default::default(), capture_method: Default::default(), @@ -218,8 +215,6 @@ mod tests { customer_acceptance: Default::default(), profile_id: common_utils::generate_profile_id_of_default_length(), organization_id: Default::default(), - shipping_cost: Default::default(), - order_tax_amount: Default::default(), }; let store = state @@ -255,14 +250,11 @@ mod tests { modified_at: current_time.into(), attempt_id: attempt_id.clone(), status: Default::default(), - amount: Default::default(), net_amount: Default::default(), currency: Default::default(), save_to_locker: Default::default(), error_message: Default::default(), offer_amount: Default::default(), - surcharge_amount: Default::default(), - tax_amount: Default::default(), payment_method_id: Default::default(), payment_method: Default::default(), capture_method: Default::default(), @@ -306,8 +298,6 @@ mod tests { customer_acceptance: Default::default(), profile_id: common_utils::generate_profile_id_of_default_length(), organization_id: Default::default(), - shipping_cost: Default::default(), - order_tax_amount: Default::default(), }; let store = state .stores @@ -357,14 +347,11 @@ mod tests { mandate_id: Some("man_121212".to_string()), attempt_id: uuid.clone(), status: Default::default(), - amount: Default::default(), net_amount: Default::default(), currency: Default::default(), save_to_locker: Default::default(), error_message: Default::default(), offer_amount: Default::default(), - surcharge_amount: Default::default(), - tax_amount: Default::default(), payment_method_id: Default::default(), payment_method: Default::default(), capture_method: Default::default(), @@ -407,8 +394,6 @@ mod tests { customer_acceptance: Default::default(), profile_id: common_utils::generate_profile_id_of_default_length(), organization_id: Default::default(), - shipping_cost: Default::default(), - order_tax_amount: Default::default(), }; let store = state .stores diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index a75ef879daf4..1f876342ac0c 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -1294,7 +1294,7 @@ impl ForeignFrom for payments::PaymentAttemptResponse { Self { attempt_id: payment_attempt.attempt_id, status: payment_attempt.status, - amount: payment_attempt.amount, + amount: payment_attempt.net_amount.get_order_amount(), currency: payment_attempt.currency, connector: payment_attempt.connector, error_message: payment_attempt.error_reason, @@ -1549,7 +1549,8 @@ impl currency: payment_attempt.map(|pa| pa.currency.unwrap_or_default()), shipping: shipping.map(api_types::Address::from), billing: billing_address, - amount: payment_attempt.map(|pa| api_types::Amount::from(pa.amount)), + amount: payment_attempt + .map(|pa| api_types::Amount::from(pa.net_amount.get_order_amount())), email: customer .and_then(|cust| cust.email.as_ref().map(|em| pii::Email::from(em.clone()))) .or(customer_details_from_pi.clone().and_then(|cd| cd.email)), diff --git a/crates/storage_impl/src/mock_db/payment_attempt.rs b/crates/storage_impl/src/mock_db/payment_attempt.rs index c37f9f6d3dac..13c75e005c4e 100644 --- a/crates/storage_impl/src/mock_db/payment_attempt.rs +++ b/crates/storage_impl/src/mock_db/payment_attempt.rs @@ -123,21 +123,17 @@ impl PaymentAttemptInterface for MockDb { ) -> CustomResult { let mut payment_attempts = self.payment_attempts.lock().await; let time = common_utils::date_time::now(); - let payment_attempt = payment_attempt.populate_derived_fields(); let payment_attempt = PaymentAttempt { payment_id: payment_attempt.payment_id, merchant_id: payment_attempt.merchant_id, attempt_id: payment_attempt.attempt_id, status: payment_attempt.status, - amount: payment_attempt.amount, net_amount: payment_attempt.net_amount, currency: payment_attempt.currency, save_to_locker: payment_attempt.save_to_locker, connector: payment_attempt.connector, error_message: payment_attempt.error_message, offer_amount: payment_attempt.offer_amount, - surcharge_amount: payment_attempt.surcharge_amount, - tax_amount: payment_attempt.tax_amount, payment_method_id: payment_attempt.payment_method_id, payment_method: payment_attempt.payment_method, connector_transaction_id: None, @@ -185,8 +181,6 @@ impl PaymentAttemptInterface for MockDb { customer_acceptance: payment_attempt.customer_acceptance, organization_id: payment_attempt.organization_id, profile_id: payment_attempt.profile_id, - shipping_cost: payment_attempt.shipping_cost, - order_tax_amount: payment_attempt.order_tax_amount, }; payment_attempts.push(payment_attempt.clone()); Ok(payment_attempt) diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index 63f5a0ff9f82..9053b7561adb 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -9,7 +9,6 @@ use diesel_models::{ kv, payment_attempt::{ PaymentAttempt as DieselPaymentAttempt, PaymentAttemptNew as DieselPaymentAttemptNew, - PaymentAttemptUpdate as DieselPaymentAttemptUpdate, }, reverse_lookup::{ReverseLookup, ReverseLookupNew}, }; @@ -459,7 +458,6 @@ impl PaymentAttemptInterface for KVRouterStore { .await } MerchantStorageScheme::RedisKv => { - let payment_attempt = payment_attempt.populate_derived_fields(); let merchant_id = payment_attempt.merchant_id.clone(); let payment_id = payment_attempt.payment_id.clone(); let key = PartitionKey::MerchantIdPaymentId { @@ -472,15 +470,12 @@ impl PaymentAttemptInterface for KVRouterStore { merchant_id: payment_attempt.merchant_id.clone(), attempt_id: payment_attempt.attempt_id.clone(), status: payment_attempt.status, - amount: payment_attempt.amount, - net_amount: payment_attempt.net_amount, + net_amount: payment_attempt.net_amount.clone(), currency: payment_attempt.currency, save_to_locker: payment_attempt.save_to_locker, connector: payment_attempt.connector.clone(), error_message: payment_attempt.error_message.clone(), offer_amount: payment_attempt.offer_amount, - surcharge_amount: payment_attempt.surcharge_amount, - tax_amount: payment_attempt.tax_amount, payment_method_id: payment_attempt.payment_method_id.clone(), payment_method: payment_attempt.payment_method, connector_transaction_id: None, @@ -534,8 +529,6 @@ impl PaymentAttemptInterface for KVRouterStore { customer_acceptance: payment_attempt.customer_acceptance.clone(), organization_id: payment_attempt.organization_id.clone(), profile_id: payment_attempt.profile_id.clone(), - shipping_cost: payment_attempt.shipping_cost, - order_tax_amount: payment_attempt.order_tax_amount, }; let field = format!("pa_{}", created_attempt.attempt_id); @@ -1379,15 +1372,15 @@ impl DataModelExt for PaymentAttempt { merchant_id: self.merchant_id, attempt_id: self.attempt_id, status: self.status, - amount: self.amount, - net_amount: Some(self.net_amount), + amount: self.net_amount.get_order_amount(), + net_amount: Some(self.net_amount.get_total_amount()), currency: self.currency, save_to_locker: self.save_to_locker, connector: self.connector, error_message: self.error_message, offer_amount: self.offer_amount, - surcharge_amount: self.surcharge_amount, - tax_amount: self.tax_amount, + surcharge_amount: self.net_amount.get_surcharge_amount(), + tax_amount: self.net_amount.get_tax_on_surcharge(), payment_method_id: self.payment_method_id, payment_method: self.payment_method, connector_transaction_id: self.connector_transaction_id, @@ -1444,26 +1437,29 @@ impl DataModelExt for PaymentAttempt { customer_acceptance: self.customer_acceptance, organization_id: self.organization_id, profile_id: self.profile_id, - shipping_cost: self.shipping_cost, - order_tax_amount: self.order_tax_amount, + shipping_cost: self.net_amount.get_shipping_cost(), + order_tax_amount: self.net_amount.get_order_tax_amount(), } } fn from_storage_model(storage_model: Self::StorageModel) -> Self { Self { - net_amount: storage_model.get_or_calculate_net_amount(), + net_amount: hyperswitch_domain_models::payments::payment_attempt::NetAmount::new( + storage_model.amount, + storage_model.shipping_cost, + storage_model.order_tax_amount, + storage_model.surcharge_amount, + storage_model.tax_amount, + ), payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, attempt_id: storage_model.attempt_id, status: storage_model.status, - amount: storage_model.amount, currency: storage_model.currency, save_to_locker: storage_model.save_to_locker, connector: storage_model.connector, error_message: storage_model.error_message, offer_amount: storage_model.offer_amount, - surcharge_amount: storage_model.surcharge_amount, - tax_amount: storage_model.tax_amount, payment_method_id: storage_model.payment_method_id, payment_method: storage_model.payment_method, connector_transaction_id: storage_model.connector_transaction_id, @@ -1515,8 +1511,6 @@ impl DataModelExt for PaymentAttempt { customer_acceptance: storage_model.customer_acceptance, organization_id: storage_model.organization_id, profile_id: storage_model.profile_id, - shipping_cost: storage_model.shipping_cost, - order_tax_amount: storage_model.order_tax_amount, } } } @@ -1527,19 +1521,19 @@ impl DataModelExt for PaymentAttemptNew { fn to_storage_model(self) -> Self::StorageModel { DieselPaymentAttemptNew { - net_amount: Some(self.net_amount), + net_amount: Some(self.net_amount.get_total_amount()), payment_id: self.payment_id, merchant_id: self.merchant_id, attempt_id: self.attempt_id, status: self.status, - amount: self.amount, + amount: self.net_amount.get_order_amount(), currency: self.currency, save_to_locker: self.save_to_locker, connector: self.connector, error_message: self.error_message, offer_amount: self.offer_amount, - surcharge_amount: self.surcharge_amount, - tax_amount: self.tax_amount, + surcharge_amount: self.net_amount.get_surcharge_amount(), + tax_amount: self.net_amount.get_tax_on_surcharge(), payment_method_id: self.payment_method_id, payment_method: self.payment_method, capture_method: self.capture_method, @@ -1597,26 +1591,29 @@ impl DataModelExt for PaymentAttemptNew { customer_acceptance: self.customer_acceptance, organization_id: self.organization_id, profile_id: self.profile_id, - shipping_cost: self.shipping_cost, - order_tax_amount: self.order_tax_amount, + shipping_cost: self.net_amount.get_shipping_cost(), + order_tax_amount: self.net_amount.get_order_tax_amount(), } } fn from_storage_model(storage_model: Self::StorageModel) -> Self { Self { - net_amount: storage_model.get_or_calculate_net_amount(), + net_amount: hyperswitch_domain_models::payments::payment_attempt::NetAmount::new( + storage_model.amount, + storage_model.shipping_cost, + storage_model.order_tax_amount, + storage_model.surcharge_amount, + storage_model.tax_amount, + ), payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, attempt_id: storage_model.attempt_id, status: storage_model.status, - amount: storage_model.amount, currency: storage_model.currency, save_to_locker: storage_model.save_to_locker, connector: storage_model.connector, error_message: storage_model.error_message, offer_amount: storage_model.offer_amount, - surcharge_amount: storage_model.surcharge_amount, - tax_amount: storage_model.tax_amount, payment_method_id: storage_model.payment_method_id, payment_method: storage_model.payment_method, capture_method: storage_model.capture_method, @@ -1667,725 +1664,6 @@ impl DataModelExt for PaymentAttemptNew { customer_acceptance: storage_model.customer_acceptance, organization_id: storage_model.organization_id, profile_id: storage_model.profile_id, - shipping_cost: storage_model.shipping_cost, - order_tax_amount: storage_model.order_tax_amount, - } - } -} - -#[cfg(feature = "v1")] -impl DataModelExt for PaymentAttemptUpdate { - type StorageModel = DieselPaymentAttemptUpdate; - - fn to_storage_model(self) -> Self::StorageModel { - match self { - Self::Update { - amount, - currency, - status, - authentication_type, - payment_method, - payment_token, - payment_method_data, - payment_method_type, - payment_experience, - business_sub_label, - amount_to_capture, - capture_method, - surcharge_amount, - tax_amount, - fingerprint_id, - payment_method_billing_address_id, - updated_by, - } => DieselPaymentAttemptUpdate::Update { - amount, - currency, - status, - authentication_type, - payment_method, - payment_token, - payment_method_data, - payment_method_type, - payment_experience, - business_sub_label, - amount_to_capture, - capture_method, - surcharge_amount, - tax_amount, - fingerprint_id, - payment_method_billing_address_id, - updated_by, - }, - Self::UpdateTrackers { - payment_token, - connector, - straight_through_algorithm, - amount_capturable, - updated_by, - surcharge_amount, - tax_amount, - merchant_connector_id, - } => DieselPaymentAttemptUpdate::UpdateTrackers { - payment_token, - connector, - straight_through_algorithm, - amount_capturable, - surcharge_amount, - tax_amount, - updated_by, - merchant_connector_id, - }, - Self::AuthenticationTypeUpdate { - authentication_type, - updated_by, - } => DieselPaymentAttemptUpdate::AuthenticationTypeUpdate { - authentication_type, - updated_by, - }, - Self::BlocklistUpdate { - status, - error_code, - error_message, - updated_by, - } => DieselPaymentAttemptUpdate::BlocklistUpdate { - status, - error_code, - error_message, - updated_by, - }, - Self::PaymentMethodDetailsUpdate { - payment_method_id, - updated_by, - } => DieselPaymentAttemptUpdate::PaymentMethodDetailsUpdate { - payment_method_id, - updated_by, - }, - Self::ConfirmUpdate { - amount, - currency, - status, - authentication_type, - capture_method, - payment_method, - browser_info, - connector, - payment_token, - payment_method_data, - payment_method_type, - payment_experience, - business_sub_label, - straight_through_algorithm, - error_code, - error_message, - amount_capturable, - surcharge_amount, - tax_amount, - fingerprint_id, - updated_by, - merchant_connector_id: connector_id, - payment_method_id, - external_three_ds_authentication_attempted, - authentication_connector, - authentication_id, - payment_method_billing_address_id, - client_source, - client_version, - customer_acceptance, - shipping_cost, - order_tax_amount, - } => DieselPaymentAttemptUpdate::ConfirmUpdate { - amount, - currency, - status, - authentication_type, - capture_method, - payment_method, - browser_info, - connector, - payment_token, - payment_method_data, - payment_method_type, - payment_experience, - business_sub_label, - straight_through_algorithm, - error_code, - error_message, - amount_capturable, - surcharge_amount, - tax_amount, - fingerprint_id, - updated_by, - merchant_connector_id: connector_id, - payment_method_id, - external_three_ds_authentication_attempted, - authentication_connector, - authentication_id, - payment_method_billing_address_id, - client_source, - client_version, - customer_acceptance, - shipping_cost, - order_tax_amount, - }, - Self::VoidUpdate { - status, - cancellation_reason, - updated_by, - } => DieselPaymentAttemptUpdate::VoidUpdate { - status, - cancellation_reason, - updated_by, - }, - Self::ResponseUpdate { - status, - connector, - connector_transaction_id, - authentication_type, - payment_method_id, - mandate_id, - connector_metadata, - payment_token, - error_code, - error_message, - error_reason, - connector_response_reference_id, - amount_capturable, - updated_by, - authentication_data, - encoded_data, - unified_code, - unified_message, - payment_method_data, - charge_id, - } => DieselPaymentAttemptUpdate::ResponseUpdate { - status, - connector, - connector_transaction_id, - authentication_type, - payment_method_id, - mandate_id, - connector_metadata, - payment_token, - error_code, - error_message, - error_reason, - connector_response_reference_id, - amount_capturable, - updated_by, - authentication_data, - encoded_data, - unified_code, - unified_message, - payment_method_data, - charge_id, - }, - Self::UnresolvedResponseUpdate { - status, - connector, - connector_transaction_id, - payment_method_id, - error_code, - error_message, - error_reason, - connector_response_reference_id, - updated_by, - } => DieselPaymentAttemptUpdate::UnresolvedResponseUpdate { - status, - connector, - connector_transaction_id, - payment_method_id, - error_code, - error_message, - error_reason, - connector_response_reference_id, - updated_by, - }, - Self::StatusUpdate { status, updated_by } => { - DieselPaymentAttemptUpdate::StatusUpdate { status, updated_by } - } - Self::ErrorUpdate { - connector, - status, - error_code, - error_message, - error_reason, - amount_capturable, - updated_by, - unified_code, - unified_message, - connector_transaction_id, - payment_method_data, - authentication_type, - } => DieselPaymentAttemptUpdate::ErrorUpdate { - connector, - status, - error_code, - error_message, - error_reason, - amount_capturable, - updated_by, - unified_code, - unified_message, - connector_transaction_id, - payment_method_data, - authentication_type, - }, - Self::CaptureUpdate { - multiple_capture_count, - updated_by, - amount_to_capture, - } => DieselPaymentAttemptUpdate::CaptureUpdate { - multiple_capture_count, - updated_by, - amount_to_capture, - }, - Self::PreprocessingUpdate { - status, - payment_method_id, - connector_metadata, - preprocessing_step_id, - connector_transaction_id, - connector_response_reference_id, - updated_by, - } => DieselPaymentAttemptUpdate::PreprocessingUpdate { - status, - payment_method_id, - connector_metadata, - preprocessing_step_id, - connector_transaction_id, - connector_response_reference_id, - updated_by, - }, - Self::RejectUpdate { - status, - error_code, - error_message, - updated_by, - } => DieselPaymentAttemptUpdate::RejectUpdate { - status, - error_code, - error_message, - updated_by, - }, - Self::AmountToCaptureUpdate { - status, - amount_capturable, - updated_by, - } => DieselPaymentAttemptUpdate::AmountToCaptureUpdate { - status, - amount_capturable, - updated_by, - }, - Self::ConnectorResponse { - authentication_data, - encoded_data, - connector_transaction_id, - connector, - charge_id, - updated_by, - } => DieselPaymentAttemptUpdate::ConnectorResponse { - authentication_data, - encoded_data, - connector_transaction_id, - connector, - charge_id, - updated_by, - }, - Self::IncrementalAuthorizationAmountUpdate { - amount, - amount_capturable, - } => DieselPaymentAttemptUpdate::IncrementalAuthorizationAmountUpdate { - amount, - amount_capturable, - }, - Self::AuthenticationUpdate { - status, - external_three_ds_authentication_attempted, - authentication_connector, - authentication_id, - updated_by, - } => DieselPaymentAttemptUpdate::AuthenticationUpdate { - status, - external_three_ds_authentication_attempted, - authentication_connector, - authentication_id, - updated_by, - }, - Self::ManualUpdate { - status, - error_code, - error_message, - error_reason, - updated_by, - unified_code, - unified_message, - connector_transaction_id, - } => DieselPaymentAttemptUpdate::ManualUpdate { - status, - error_code, - error_message, - error_reason, - updated_by, - unified_code, - unified_message, - connector_transaction_id, - }, - } - } - - fn from_storage_model(storage_model: Self::StorageModel) -> Self { - match storage_model { - DieselPaymentAttemptUpdate::Update { - amount, - currency, - status, - authentication_type, - payment_method, - payment_token, - payment_method_data, - payment_method_type, - payment_experience, - business_sub_label, - amount_to_capture, - capture_method, - surcharge_amount, - tax_amount, - fingerprint_id, - updated_by, - payment_method_billing_address_id, - } => Self::Update { - amount, - currency, - status, - authentication_type, - payment_method, - payment_token, - payment_method_data, - payment_method_type, - payment_experience, - business_sub_label, - amount_to_capture, - capture_method, - surcharge_amount, - tax_amount, - fingerprint_id, - payment_method_billing_address_id, - updated_by, - }, - DieselPaymentAttemptUpdate::UpdateTrackers { - payment_token, - connector, - straight_through_algorithm, - amount_capturable, - updated_by, - surcharge_amount, - tax_amount, - merchant_connector_id: connector_id, - } => Self::UpdateTrackers { - payment_token, - connector, - straight_through_algorithm, - amount_capturable, - surcharge_amount, - tax_amount, - updated_by, - merchant_connector_id: connector_id, - }, - DieselPaymentAttemptUpdate::AuthenticationTypeUpdate { - authentication_type, - updated_by, - } => Self::AuthenticationTypeUpdate { - authentication_type, - updated_by, - }, - DieselPaymentAttemptUpdate::ConfirmUpdate { - amount, - currency, - status, - authentication_type, - capture_method, - payment_method, - browser_info, - connector, - payment_token, - payment_method_data, - payment_method_type, - payment_experience, - business_sub_label, - straight_through_algorithm, - error_code, - error_message, - amount_capturable, - surcharge_amount, - tax_amount, - fingerprint_id, - updated_by, - merchant_connector_id: connector_id, - payment_method_id, - external_three_ds_authentication_attempted, - authentication_connector, - authentication_id, - payment_method_billing_address_id, - client_source, - client_version, - customer_acceptance, - shipping_cost, - order_tax_amount, - } => Self::ConfirmUpdate { - amount, - currency, - status, - authentication_type, - capture_method, - payment_method, - browser_info, - connector, - payment_token, - payment_method_data, - payment_method_type, - payment_experience, - business_sub_label, - straight_through_algorithm, - error_code, - error_message, - amount_capturable, - surcharge_amount, - tax_amount, - fingerprint_id, - updated_by, - merchant_connector_id: connector_id, - payment_method_id, - external_three_ds_authentication_attempted, - authentication_connector, - authentication_id, - payment_method_billing_address_id, - client_source, - client_version, - customer_acceptance, - shipping_cost, - order_tax_amount, - }, - DieselPaymentAttemptUpdate::VoidUpdate { - status, - cancellation_reason, - updated_by, - } => Self::VoidUpdate { - status, - cancellation_reason, - updated_by, - }, - DieselPaymentAttemptUpdate::BlocklistUpdate { - status, - error_code, - error_message, - updated_by, - } => Self::BlocklistUpdate { - status, - error_code, - error_message, - updated_by, - }, - DieselPaymentAttemptUpdate::PaymentMethodDetailsUpdate { - payment_method_id, - updated_by, - } => Self::PaymentMethodDetailsUpdate { - payment_method_id, - updated_by, - }, - DieselPaymentAttemptUpdate::ResponseUpdate { - status, - connector, - connector_transaction_id, - authentication_type, - payment_method_id, - mandate_id, - connector_metadata, - payment_token, - error_code, - error_message, - error_reason, - connector_response_reference_id, - amount_capturable, - updated_by, - authentication_data, - encoded_data, - unified_code, - unified_message, - payment_method_data, - charge_id, - } => Self::ResponseUpdate { - status, - connector, - connector_transaction_id, - authentication_type, - payment_method_id, - mandate_id, - connector_metadata, - payment_token, - error_code, - error_message, - error_reason, - connector_response_reference_id, - amount_capturable, - updated_by, - authentication_data, - encoded_data, - unified_code, - unified_message, - payment_method_data, - charge_id, - }, - DieselPaymentAttemptUpdate::UnresolvedResponseUpdate { - status, - connector, - connector_transaction_id, - payment_method_id, - error_code, - error_message, - error_reason, - connector_response_reference_id, - updated_by, - } => Self::UnresolvedResponseUpdate { - status, - connector, - connector_transaction_id, - payment_method_id, - error_code, - error_message, - error_reason, - connector_response_reference_id, - updated_by, - }, - DieselPaymentAttemptUpdate::StatusUpdate { status, updated_by } => { - Self::StatusUpdate { status, updated_by } - } - DieselPaymentAttemptUpdate::ErrorUpdate { - connector, - status, - error_code, - error_message, - error_reason, - amount_capturable, - updated_by, - unified_code, - unified_message, - connector_transaction_id, - payment_method_data, - authentication_type, - } => Self::ErrorUpdate { - connector, - status, - error_code, - error_message, - error_reason, - amount_capturable, - updated_by, - unified_code, - unified_message, - connector_transaction_id, - payment_method_data, - authentication_type, - }, - DieselPaymentAttemptUpdate::CaptureUpdate { - amount_to_capture, - multiple_capture_count, - updated_by, - } => Self::CaptureUpdate { - amount_to_capture, - multiple_capture_count, - updated_by, - }, - DieselPaymentAttemptUpdate::PreprocessingUpdate { - status, - payment_method_id, - connector_metadata, - preprocessing_step_id, - connector_transaction_id, - connector_response_reference_id, - updated_by, - } => Self::PreprocessingUpdate { - status, - payment_method_id, - connector_metadata, - preprocessing_step_id, - connector_transaction_id, - connector_response_reference_id, - updated_by, - }, - DieselPaymentAttemptUpdate::RejectUpdate { - status, - error_code, - error_message, - updated_by, - } => Self::RejectUpdate { - status, - error_code, - error_message, - updated_by, - }, - DieselPaymentAttemptUpdate::AmountToCaptureUpdate { - status, - amount_capturable, - updated_by, - } => Self::AmountToCaptureUpdate { - status, - amount_capturable, - updated_by, - }, - DieselPaymentAttemptUpdate::ConnectorResponse { - authentication_data, - encoded_data, - connector_transaction_id, - connector, - charge_id, - updated_by, - } => Self::ConnectorResponse { - authentication_data, - encoded_data, - connector_transaction_id, - connector, - charge_id, - updated_by, - }, - DieselPaymentAttemptUpdate::IncrementalAuthorizationAmountUpdate { - amount, - amount_capturable, - } => Self::IncrementalAuthorizationAmountUpdate { - amount, - amount_capturable, - }, - DieselPaymentAttemptUpdate::AuthenticationUpdate { - status, - external_three_ds_authentication_attempted, - authentication_connector, - authentication_id, - updated_by, - } => Self::AuthenticationUpdate { - status, - external_three_ds_authentication_attempted, - authentication_connector, - authentication_id, - updated_by, - }, - DieselPaymentAttemptUpdate::ManualUpdate { - status, - error_code, - error_message, - error_reason, - updated_by, - unified_code, - unified_message, - connector_transaction_id, - } => Self::ManualUpdate { - status, - error_code, - error_message, - error_reason, - updated_by, - unified_code, - unified_message, - connector_transaction_id, - }, } } }