mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 09:07:09 +08:00
fix: introduce net_amount field in payment response (#3115)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
@ -2037,6 +2037,11 @@ pub struct PaymentsResponse {
|
||||
#[schema(example = 100)]
|
||||
pub amount: i64,
|
||||
|
||||
/// The payment net amount. net_amount = amount + surcharge_details.surcharge_amount + surcharge_details.tax_amount,
|
||||
/// If no surcharge_details, net_amount = amount
|
||||
#[schema(example = 110)]
|
||||
pub net_amount: i64,
|
||||
|
||||
/// The maximum amount that could be captured from the payment
|
||||
#[schema(minimum = 100, example = 6540)]
|
||||
pub amount_capturable: Option<i64>,
|
||||
|
||||
@ -107,6 +107,7 @@ pub struct PaymentAttempt {
|
||||
pub attempt_id: String,
|
||||
pub status: storage_enums::AttemptStatus,
|
||||
pub amount: i64,
|
||||
pub net_amount: i64,
|
||||
pub currency: Option<storage_enums::Currency>,
|
||||
pub save_to_locker: Option<bool>,
|
||||
pub connector: Option<String>,
|
||||
@ -183,6 +184,9 @@ pub struct PaymentAttemptNew {
|
||||
pub attempt_id: String,
|
||||
pub status: storage_enums::AttemptStatus,
|
||||
pub amount: i64,
|
||||
/// amount + surcharge_amount + tax_amount
|
||||
/// This field will always be derived before updating in the Database
|
||||
pub net_amount: i64,
|
||||
pub currency: Option<storage_enums::Currency>,
|
||||
// pub auto_capture: Option<bool>,
|
||||
pub save_to_locker: Option<bool>,
|
||||
@ -230,6 +234,19 @@ pub struct PaymentAttemptNew {
|
||||
pub unified_message: Option<String>,
|
||||
}
|
||||
|
||||
impl PaymentAttemptNew {
|
||||
/// returns amount + surcharge_amount + tax_amount
|
||||
pub fn calculate_net_amount(&self) -> i64 {
|
||||
self.amount + self.surcharge_amount.unwrap_or(0) + self.tax_amount.unwrap_or(0)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PaymentAttemptUpdate {
|
||||
Update {
|
||||
|
||||
@ -63,6 +63,15 @@ pub struct PaymentAttempt {
|
||||
pub encoded_data: Option<String>,
|
||||
pub unified_code: Option<String>,
|
||||
pub unified_message: Option<String>,
|
||||
pub net_amount: Option<i64>,
|
||||
}
|
||||
|
||||
impl PaymentAttempt {
|
||||
pub fn get_or_calculate_net_amount(&self) -> i64 {
|
||||
self.net_amount.unwrap_or(
|
||||
self.amount + self.surcharge_amount.unwrap_or(0) + self.tax_amount.unwrap_or(0),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Queryable, Serialize, Deserialize)]
|
||||
@ -128,6 +137,25 @@ pub struct PaymentAttemptNew {
|
||||
pub encoded_data: Option<String>,
|
||||
pub unified_code: Option<String>,
|
||||
pub unified_message: Option<String>,
|
||||
pub net_amount: Option<i64>,
|
||||
}
|
||||
|
||||
impl PaymentAttemptNew {
|
||||
/// returns amount + surcharge_amount + tax_amount
|
||||
pub fn calculate_net_amount(&self) -> i64 {
|
||||
self.amount + self.surcharge_amount.unwrap_or(0) + self.tax_amount.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn get_or_calculate_net_amount(&self) -> i64 {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@ -279,6 +307,7 @@ pub enum PaymentAttemptUpdate {
|
||||
#[diesel(table_name = payment_attempt)]
|
||||
pub struct PaymentAttemptUpdateInternal {
|
||||
amount: Option<i64>,
|
||||
net_amount: Option<i64>,
|
||||
currency: Option<storage_enums::Currency>,
|
||||
status: Option<storage_enums::AttemptStatus>,
|
||||
connector_transaction_id: Option<String>,
|
||||
@ -316,10 +345,29 @@ pub struct PaymentAttemptUpdateInternal {
|
||||
unified_message: Option<Option<String>>,
|
||||
}
|
||||
|
||||
impl PaymentAttemptUpdateInternal {
|
||||
pub fn populate_derived_fields(self, source: &PaymentAttempt) -> Self {
|
||||
let mut update_internal = self;
|
||||
update_internal.net_amount = Some(
|
||||
update_internal.amount.unwrap_or(source.amount)
|
||||
+ update_internal
|
||||
.surcharge_amount
|
||||
.or(source.surcharge_amount)
|
||||
.unwrap_or(0)
|
||||
+ update_internal
|
||||
.tax_amount
|
||||
.or(source.tax_amount)
|
||||
.unwrap_or(0),
|
||||
);
|
||||
update_internal
|
||||
}
|
||||
}
|
||||
|
||||
impl PaymentAttemptUpdate {
|
||||
pub fn apply_changeset(self, source: PaymentAttempt) -> PaymentAttempt {
|
||||
let PaymentAttemptUpdateInternal {
|
||||
amount,
|
||||
net_amount,
|
||||
currency,
|
||||
status,
|
||||
connector_transaction_id,
|
||||
@ -355,9 +403,10 @@ impl PaymentAttemptUpdate {
|
||||
encoded_data,
|
||||
unified_code,
|
||||
unified_message,
|
||||
} = self.into();
|
||||
} = PaymentAttemptUpdateInternal::from(self).populate_derived_fields(&source);
|
||||
PaymentAttempt {
|
||||
amount: amount.unwrap_or(source.amount),
|
||||
net_amount: net_amount.or(source.net_amount),
|
||||
currency: currency.or(source.currency),
|
||||
status: status.unwrap_or(source.status),
|
||||
connector_transaction_id: connector_transaction_id.or(source.connector_transaction_id),
|
||||
|
||||
@ -23,7 +23,7 @@ use crate::{
|
||||
impl PaymentAttemptNew {
|
||||
#[instrument(skip(conn))]
|
||||
pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<PaymentAttempt> {
|
||||
generics::generic_insert(conn, self).await
|
||||
generics::generic_insert(conn, self.populate_derived_fields()).await
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ impl PaymentAttempt {
|
||||
dsl::attempt_id
|
||||
.eq(self.attempt_id.to_owned())
|
||||
.and(dsl::merchant_id.eq(self.merchant_id.to_owned())),
|
||||
PaymentAttemptUpdateInternal::from(payment_attempt),
|
||||
PaymentAttemptUpdateInternal::from(payment_attempt).populate_derived_fields(&self),
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
||||
@ -643,6 +643,7 @@ diesel::table! {
|
||||
unified_code -> Nullable<Varchar>,
|
||||
#[max_length = 1024]
|
||||
unified_message -> Nullable<Varchar>,
|
||||
net_amount -> Nullable<Int8>,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -62,6 +62,7 @@ pub struct PaymentAttemptBatchNew {
|
||||
pub encoded_data: Option<String>,
|
||||
pub unified_code: Option<String>,
|
||||
pub unified_message: Option<String>,
|
||||
pub net_amount: Option<i64>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -114,6 +115,7 @@ impl PaymentAttemptBatchNew {
|
||||
encoded_data: self.encoded_data,
|
||||
unified_code: self.unified_code,
|
||||
unified_message: self.unified_message,
|
||||
net_amount: self.net_amount,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3089,8 +3089,8 @@ impl AttemptType {
|
||||
|
||||
error_message: None,
|
||||
offer_amount: old_payment_attempt.offer_amount,
|
||||
surcharge_amount: old_payment_attempt.surcharge_amount,
|
||||
tax_amount: old_payment_attempt.tax_amount,
|
||||
surcharge_amount: None,
|
||||
tax_amount: None,
|
||||
payment_method_id: None,
|
||||
payment_method: None,
|
||||
capture_method: old_payment_attempt.capture_method,
|
||||
@ -3133,6 +3133,7 @@ impl AttemptType {
|
||||
merchant_connector_id: None,
|
||||
unified_code: None,
|
||||
unified_message: None,
|
||||
net_amount: old_payment_attempt.amount,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -565,6 +565,7 @@ where
|
||||
});
|
||||
services::ApplicationResponse::JsonWithHeaders((
|
||||
response
|
||||
.set_net_amount(payment_attempt.net_amount)
|
||||
.set_payment_id(Some(payment_attempt.payment_id))
|
||||
.set_merchant_id(Some(payment_attempt.merchant_id))
|
||||
.set_status(payment_intent.status)
|
||||
@ -714,6 +715,7 @@ where
|
||||
}
|
||||
None => services::ApplicationResponse::JsonWithHeaders((
|
||||
api::PaymentsResponse {
|
||||
net_amount: payment_attempt.net_amount,
|
||||
payment_id: Some(payment_attempt.payment_id),
|
||||
merchant_id: Some(payment_attempt.merchant_id),
|
||||
status: payment_intent.status,
|
||||
|
||||
@ -97,7 +97,7 @@ impl PaymentAttemptInterface for MockDb {
|
||||
#[allow(clippy::as_conversions)]
|
||||
let id = payment_attempts.len() as i32;
|
||||
let time = common_utils::date_time::now();
|
||||
|
||||
let payment_attempt = payment_attempt.populate_derived_fields();
|
||||
let payment_attempt = PaymentAttempt {
|
||||
id,
|
||||
payment_id: payment_attempt.payment_id,
|
||||
@ -105,6 +105,7 @@ impl PaymentAttemptInterface for MockDb {
|
||||
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,
|
||||
|
||||
@ -331,6 +331,7 @@ impl<T: DatabaseStore> PaymentAttemptInterface for KVRouterStore<T> {
|
||||
.await
|
||||
}
|
||||
MerchantStorageScheme::RedisKv => {
|
||||
let payment_attempt = payment_attempt.populate_derived_fields();
|
||||
let key = format!(
|
||||
"mid_{}_pid_{}",
|
||||
payment_attempt.merchant_id, payment_attempt.payment_id
|
||||
@ -343,6 +344,7 @@ impl<T: DatabaseStore> PaymentAttemptInterface for KVRouterStore<T> {
|
||||
attempt_id: payment_attempt.attempt_id.clone(),
|
||||
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.clone(),
|
||||
@ -1035,6 +1037,7 @@ impl DataModelExt for PaymentAttempt {
|
||||
attempt_id: self.attempt_id,
|
||||
status: self.status,
|
||||
amount: self.amount,
|
||||
net_amount: Some(self.net_amount),
|
||||
currency: self.currency,
|
||||
save_to_locker: self.save_to_locker,
|
||||
connector: self.connector,
|
||||
@ -1081,6 +1084,7 @@ impl DataModelExt for PaymentAttempt {
|
||||
|
||||
fn from_storage_model(storage_model: Self::StorageModel) -> Self {
|
||||
Self {
|
||||
net_amount: storage_model.get_or_calculate_net_amount(),
|
||||
id: storage_model.id,
|
||||
payment_id: storage_model.payment_id,
|
||||
merchant_id: storage_model.merchant_id,
|
||||
@ -1139,6 +1143,7 @@ impl DataModelExt for PaymentAttemptNew {
|
||||
|
||||
fn to_storage_model(self) -> Self::StorageModel {
|
||||
DieselPaymentAttemptNew {
|
||||
net_amount: Some(self.net_amount),
|
||||
payment_id: self.payment_id,
|
||||
merchant_id: self.merchant_id,
|
||||
attempt_id: self.attempt_id,
|
||||
@ -1189,6 +1194,7 @@ impl DataModelExt for PaymentAttemptNew {
|
||||
|
||||
fn from_storage_model(storage_model: Self::StorageModel) -> Self {
|
||||
Self {
|
||||
net_amount: storage_model.get_or_calculate_net_amount(),
|
||||
payment_id: storage_model.payment_id,
|
||||
merchant_id: storage_model.merchant_id,
|
||||
attempt_id: storage_model.attempt_id,
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
ALTER TABLE payment_attempt DROP COLUMN IF EXISTS net_amount;
|
||||
@ -0,0 +1,5 @@
|
||||
ALTER TABLE payment_attempt
|
||||
ADD COLUMN IF NOT EXISTS net_amount BIGINT;
|
||||
-- Backfill
|
||||
UPDATE payment_attempt pa
|
||||
SET net_amount = pa.amount + COALESCE(pa.surcharge_amount, 0) + COALESCE(pa.tax_amount, 0);
|
||||
@ -10275,6 +10275,7 @@
|
||||
"required": [
|
||||
"status",
|
||||
"amount",
|
||||
"net_amount",
|
||||
"currency",
|
||||
"payment_method",
|
||||
"attempt_count"
|
||||
@ -10309,6 +10310,12 @@
|
||||
"description": "The payment amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc.,",
|
||||
"example": 100
|
||||
},
|
||||
"net_amount": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "The payment net amount. net_amount = amount + surcharge_details.surcharge_amount + surcharge_details.tax_amount,\nIf no surcharge_details, net_amount = amount",
|
||||
"example": 110
|
||||
},
|
||||
"amount_capturable": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
|
||||
Reference in New Issue
Block a user