From 9ef9de988f4ccb86eb59f0d48be8b0225baad00d Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 13 May 2024 16:50:04 +0530 Subject: [PATCH 01/82] refactor(router): added a new type minor unit to amount --- connector-template/transformers.rs | 4 +- crates/api_models/src/currency.rs | 4 +- crates/api_models/src/payment_methods.rs | 4 +- crates/api_models/src/payments.rs | 113 +++++++++--- .../hyperswitch_domain_models/src/mandates.rs | 4 +- .../hyperswitch_domain_models/src/payments.rs | 5 +- .../src/payments/payment_attempt.rs | 85 +++++---- .../src/payments/payment_intent.rs | 15 +- .../stripe/payment_intents/types.rs | 20 +- .../src/connector/adyen/transformers.rs | 2 +- .../src/connector/checkout/transformers.rs | 4 +- .../src/connector/cryptopay/transformers.rs | 4 +- .../router/src/connector/noon/transformers.rs | 5 +- .../src/connector/paypal/transformers.rs | 2 +- .../router/src/connector/payu/transformers.rs | 4 +- .../src/connector/square/transformers.rs | 4 +- .../src/connector/stripe/transformers.rs | 8 +- crates/router/src/connector/utils.rs | 33 ++-- crates/router/src/core/authentication.rs | 2 +- .../src/core/authentication/transformers.rs | 4 +- crates/router/src/core/fraud_check.rs | 2 +- .../core/fraud_check/flows/checkout_flow.rs | 2 +- .../fraud_check/flows/fulfillment_flow.rs | 2 +- .../core/fraud_check/flows/record_return.rs | 2 +- .../src/core/fraud_check/flows/sale_flow.rs | 2 +- .../fraud_check/flows/transaction_flow.rs | 2 +- crates/router/src/core/payment_link.rs | 4 +- .../router/src/core/payment_methods/cards.rs | 10 +- .../surcharge_decision_configs.rs | 14 +- crates/router/src/core/payments.rs | 12 +- crates/router/src/core/payments/helpers.rs | 45 +++-- .../payments/operations/payment_capture.rs | 10 +- .../payments/operations/payment_confirm.rs | 2 +- .../payments/operations/payment_create.rs | 15 +- .../payments/operations/payment_response.rs | 87 +++++---- .../payments/operations/payment_update.rs | 17 +- .../payments_incremental_authorization.rs | 8 +- crates/router/src/core/payments/retry.rs | 5 +- crates/router/src/core/payments/routing.rs | 6 +- .../router/src/core/payments/transformers.rs | 35 ++-- crates/router/src/core/payments/types.rs | 74 +++++--- crates/router/src/core/payouts.rs | 9 +- crates/router/src/core/refunds.rs | 18 +- crates/router/src/routes/currency.rs | 4 +- .../src/services/kafka/payment_attempt.rs | 15 +- .../src/services/kafka/payment_intent.rs | 5 +- crates/router/src/types.rs | 23 ++- crates/router/src/types/api/payment_link.rs | 2 +- .../src/types/storage/payment_attempt.rs | 17 +- crates/router/src/types/transformers.rs | 12 +- crates/router/src/utils/user/sample_data.rs | 6 +- crates/router/src/workflows/payment_sync.rs | 2 +- .../src/payments/payment_attempt.rs | 173 +++++++++++------- .../src/payments/payment_intent.rs | 29 +-- 54 files changed, 616 insertions(+), 381 deletions(-) diff --git a/connector-template/transformers.rs b/connector-template/transformers.rs index 60b13693054..02cce418097 100644 --- a/connector-template/transformers.rs +++ b/connector-template/transformers.rs @@ -4,7 +4,7 @@ use crate::{connector::utils::{PaymentsAuthorizeRequestData},core::errors,types: //TODO: Fill the struct with respective fields pub struct {{project-name | downcase | pascal_case}}RouterData { - pub amount: i64, // The type of amount that a connector accepts, for example, String, i64, f64, etc. + pub amount: MinorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc. pub router_data: T, } @@ -140,7 +140,7 @@ incremental_authorization_allowed: None, // Type definition for RefundRequest #[derive(Default, Debug, Serialize)] pub struct {{project-name | downcase | pascal_case}}RefundRequest { - pub amount: i64 + pub amount: MinorUnit } impl TryFrom<&{{project-name | downcase | pascal_case}}RouterData<&types::RefundsRouterData>> for {{project-name | downcase | pascal_case}}RefundRequest { diff --git a/crates/api_models/src/currency.rs b/crates/api_models/src/currency.rs index c1d7e422d04..32140e4c6d7 100644 --- a/crates/api_models/src/currency.rs +++ b/crates/api_models/src/currency.rs @@ -1,10 +1,12 @@ use common_utils::events::ApiEventMetric; +use crate::payments::MinorUnit; + /// QueryParams to be send to convert the amount -> from_currency -> to_currency #[derive(Debug, serde::Deserialize)] #[serde(rename_all = "snake_case")] pub struct CurrencyConversionParams { - pub amount: i64, + pub amount: MinorUnit, pub to_currency: String, pub from_currency: String, } diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index e9ff261a632..b88ed425817 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -14,7 +14,7 @@ use utoipa::{schema, ToSchema}; use crate::payouts; use crate::{ admin, enums as api_enums, - payments::{self, BankCodeResponse}, + payments::{self, BankCodeResponse, MinorUnit}, }; #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)] @@ -656,7 +656,7 @@ pub struct PaymentMethodListRequest { /// Filter by amount #[schema(example = 60)] - pub amount: Option, + pub amount: Option, /// Indicates whether the payment method is eligible for recurring payments #[schema(example = true)] diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 819e67a73bb..6efca674287 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -224,7 +224,7 @@ pub struct PaymentsRequest { /// The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount. #[schema(example = 6540)] - pub amount_to_capture: Option, + pub amount_to_capture: Option, /// Unique identifier for the payment. This ensures idempotency for multiple payments /// that have been done by a single merchant. This field is auto generated and is returned in the API response. @@ -470,21 +470,21 @@ pub struct PaymentsRequest { } impl PaymentsRequest { - pub fn get_total_capturable_amount(&self) -> Option { + pub fn get_total_capturable_amount(&self) -> Option { let surcharge_amount = self .surcharge_details .map(|surcharge_details| surcharge_details.get_total_surcharge_amount()) - .unwrap_or(0); + .unwrap_or_default(); self.amount - .map(|amount| i64::from(amount) + surcharge_amount) + .map(|amount| MinorUnit::from(amount).add(surcharge_amount)) } } #[derive( Default, Debug, Clone, serde::Serialize, serde::Deserialize, Copy, ToSchema, PartialEq, )] pub struct RequestSurchargeDetails { - pub surcharge_amount: i64, - pub tax_amount: Option, + pub surcharge_amount: MinorUnit, + pub tax_amount: Option, } /// Browser information to be used for 3DS 2.0 @@ -527,10 +527,12 @@ pub struct BrowserInformation { impl RequestSurchargeDetails { pub fn is_surcharge_zero(&self) -> bool { - self.surcharge_amount == 0 && self.tax_amount.unwrap_or(0) == 0 + self.surcharge_amount.get_amount_as_i64() == 0 + && self.tax_amount.unwrap_or_default().get_amount_as_i64() == 0 } - pub fn get_total_surcharge_amount(&self) -> i64 { - self.surcharge_amount + self.tax_amount.unwrap_or(0) + pub fn get_total_surcharge_amount(&self) -> MinorUnit { + self.surcharge_amount + .add(self.tax_amount.unwrap_or_default()) } } @@ -559,7 +561,7 @@ pub struct PaymentAttemptResponse { #[schema(value_type = AttemptStatus, example = "charged")] pub status: enums::AttemptStatus, /// The payment attempt amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., - pub amount: i64, + pub amount: MinorUnit, /// The currency of the amount of the payment attempt #[schema(value_type = Option, example = "USD")] pub currency: Option, @@ -613,7 +615,7 @@ pub struct CaptureResponse { #[schema(value_type = CaptureStatus, example = "charged")] pub status: enums::CaptureStatus, /// The capture amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., - pub amount: i64, + pub amount: MinorUnit, /// The currency of the amount of the capture #[schema(value_type = Option, example = "USD")] pub currency: Option, @@ -689,6 +691,50 @@ impl PaymentsRequest { } } +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)] +pub struct MinorUnit(i64); + +impl MinorUnit { + pub fn get_amount_as_i64(&self) -> i64 { + self.0 + } + + pub fn add(&self, a2: MinorUnit) -> Self { + MinorUnit::new(self.get_amount_as_i64() + a2.get_amount_as_i64()) + } + + pub fn substract(&self, a2: MinorUnit) -> Self { + MinorUnit::new(self.get_amount_as_i64() - a2.get_amount_as_i64()) + } + + pub fn get_optional_amount_as_i64(optional_amount: Option) -> Option { + optional_amount.map(|amount| amount.get_amount_as_i64()) + } + + pub fn new(value: i64) -> Self { + MinorUnit(value) + } + pub fn optional_new_from_i64_amount(value: i64) -> Option { + Some(MinorUnit(value)) + } + + pub fn new_from_optional_i64_amount(value: Option) -> Option { + value.map(|amount| MinorUnit(amount)) + } + + pub fn is_equal(&self, a2: MinorUnit) -> bool { + self.get_amount_as_i64() == a2.get_amount_as_i64() + } + + pub fn is_not_equal(&self, a2: MinorUnit) -> bool { + !self.is_equal(a2) + } + + pub fn is_greater_than(&self, a2: MinorUnit) -> bool { + self.get_amount_as_i64() > a2.get_amount_as_i64() + } +} + #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)] pub enum Amount { Value(NonZeroI64), @@ -696,21 +742,29 @@ pub enum Amount { Zero, } -impl From for i64 { +impl From for MinorUnit { fn from(amount: Amount) -> Self { match amount { - Amount::Value(val) => val.get(), - Amount::Zero => 0, + Amount::Value(val) => MinorUnit::new(val.get()), + Amount::Zero => MinorUnit::new(0), } } } -impl From for Amount { - fn from(val: i64) -> Self { - NonZeroI64::new(val).map_or(Self::Zero, Amount::Value) +impl fmt::Display for MinorUnit { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) } } +impl From for Amount { + fn from(minor_unit: MinorUnit) -> Self { + match minor_unit.0 { + 0 => Amount::Zero, + val => NonZeroI64::new(val).map_or(Self::Zero, Amount::Value), + } + } +} #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone)] #[serde(deny_unknown_fields)] pub struct PaymentsRedirectRequest { @@ -798,7 +852,7 @@ pub struct MandateData { #[derive(Clone, Eq, PartialEq, Copy, Debug, Default, serde::Serialize, serde::Deserialize)] pub struct SingleUseMandate { - pub amount: i64, + pub amount: MinorUnit, pub currency: api_enums::Currency, } @@ -806,7 +860,7 @@ pub struct SingleUseMandate { pub struct MandateAmountData { /// The maximum amount to be debited for the mandate transaction #[schema(example = 6540)] - pub amount: i64, + pub amount: MinorUnit, /// The currency for the transaction #[schema(value_type = Currency, example = "USD")] pub currency: api_enums::Currency, @@ -2851,7 +2905,7 @@ pub struct PaymentsCaptureRequest { /// The unique identifier for the merchant pub merchant_id: Option, /// The Amount to be captured/ debited from the user's payment method. - pub amount_to_capture: Option, + pub amount_to_capture: Option, /// Decider to refund the uncaptured amount pub refund_uncaptured_amount: Option, /// Provides information about a card payment that customers see on their statements. @@ -3105,20 +3159,20 @@ pub struct PaymentsResponse { /// 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., #[schema(example = 100)] - pub amount: i64, + pub amount: MinorUnit, /// 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, + pub net_amount: MinorUnit, /// The maximum amount that could be captured from the payment #[schema(minimum = 100, example = 6540)] - pub amount_capturable: Option, + pub amount_capturable: Option, /// The amount which is already captured from the payment #[schema(minimum = 100, example = 6540)] - pub amount_received: Option, + pub amount_received: Option, /// The connector used for the payment #[schema(example = "stripe")] @@ -3472,7 +3526,7 @@ pub struct IncrementalAuthorizationResponse { /// The unique identifier of authorization pub authorization_id: String, /// Amount the authorization has been made for - pub amount: i64, + pub amount: MinorUnit, #[schema(value_type= AuthorizationStatus)] /// The status of the authorization pub status: common_enums::AuthorizationStatus, @@ -3715,7 +3769,7 @@ pub struct PgRedirectResponse { pub status: api_enums::IntentStatus, pub gateway_id: String, pub customer_id: Option, - pub amount: Option, + pub amount: Option, } #[derive(Debug, serde::Serialize, PartialEq, Eq, serde::Deserialize)] @@ -4266,7 +4320,7 @@ pub struct PaymentsIncrementalAuthorizationRequest { pub payment_id: String, /// The total amount including previously authorized amount and additional amount #[schema(value_type = i64, example = 6540)] - pub amount: i64, + pub amount: MinorUnit, /// Reason for incremental authorization pub reason: Option, } @@ -4469,6 +4523,7 @@ pub mod amount { use super::Amount; struct AmountVisitor; struct OptionalAmountVisitor; + use crate::payments::MinorUnit; // This is defined to provide guarded deserialization of amount // which itself handles zero and non-zero values internally @@ -4501,7 +4556,7 @@ pub mod amount { "invalid value `{v}`, expected a positive integer" ))); } - Ok(Amount::from(v)) + Ok(Amount::from(MinorUnit::new(v))) } } @@ -4573,7 +4628,7 @@ pub struct RetrievePaymentLinkResponse { pub payment_link_id: String, pub merchant_id: String, pub link_to_pay: String, - pub amount: i64, + pub amount: MinorUnit, #[serde(with = "common_utils::custom_serde::iso8601")] pub created_at: PrimitiveDateTime, #[serde(with = "common_utils::custom_serde::iso8601::option")] diff --git a/crates/hyperswitch_domain_models/src/mandates.rs b/crates/hyperswitch_domain_models/src/mandates.rs index 912ddc67058..233e97e2420 100644 --- a/crates/hyperswitch_domain_models/src/mandates.rs +++ b/crates/hyperswitch_domain_models/src/mandates.rs @@ -1,7 +1,7 @@ use api_models::payments::{ AcceptanceType as ApiAcceptanceType, CustomerAcceptance as ApiCustomerAcceptance, MandateAmountData as ApiMandateAmountData, MandateData as ApiMandateData, MandateType, - OnlineMandate as ApiOnlineMandate, + MinorUnit, OnlineMandate as ApiOnlineMandate, }; use common_enums::Currency; use common_utils::{date_time, errors::ParsingError, pii}; @@ -24,7 +24,7 @@ pub enum MandateDataType { #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq)] pub struct MandateAmountData { - pub amount: i64, + pub amount: MinorUnit, pub currency: Currency, pub start_date: Option, pub end_date: Option, diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs index 8a7dfad5fcb..4788c957b77 100644 --- a/crates/hyperswitch_domain_models/src/payments.rs +++ b/crates/hyperswitch_domain_models/src/payments.rs @@ -1,3 +1,4 @@ +use api_models::payments::MinorUnit; use common_utils::pii; use time::PrimitiveDateTime; @@ -15,9 +16,9 @@ pub struct PaymentIntent { pub payment_id: String, pub merchant_id: String, pub status: storage_enums::IntentStatus, - pub amount: i64, + pub amount: MinorUnit, pub currency: Option, - pub amount_captured: Option, + pub amount_captured: Option, pub customer_id: Option, pub description: Option, pub return_url: Option, diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index 7e406ca24d5..6095ae4f7fe 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -1,4 +1,4 @@ -use api_models::enums::Connector; +use api_models::{enums::Connector, payments::MinorUnit}; use common_enums as storage_enums; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; @@ -111,15 +111,15 @@ pub struct PaymentAttempt { pub merchant_id: String, pub attempt_id: String, pub status: storage_enums::AttemptStatus, - pub amount: i64, - pub net_amount: i64, + pub amount: MinorUnit, + pub net_amount: MinorUnit, 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 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, @@ -135,7 +135,7 @@ pub struct PaymentAttempt { #[serde(default, with = "common_utils::custom_serde::iso8601::option")] pub last_synced: Option, pub cancellation_reason: Option, - pub amount_to_capture: Option, + pub amount_to_capture: Option, pub mandate_id: Option, pub browser_info: Option, pub error_code: Option, @@ -153,7 +153,7 @@ pub struct PaymentAttempt { pub multiple_capture_count: Option, // reference to the payment at connector side pub connector_response_reference_id: Option, - pub amount_capturable: i64, + pub amount_capturable: MinorUnit, pub updated_by: String, pub authentication_data: Option, pub encoded_data: Option, @@ -169,12 +169,17 @@ pub struct PaymentAttempt { } impl PaymentAttempt { - pub fn get_total_amount(&self) -> i64 { - self.amount + self.surcharge_amount.unwrap_or(0) + self.tax_amount.unwrap_or(0) + pub fn get_total_amount(&self) -> MinorUnit { + self.amount.add( + self.surcharge_amount + .unwrap_or_default() + .add(self.tax_amount.unwrap_or_default()), + ) } - pub fn get_total_surcharge_amount(&self) -> Option { + + pub fn get_total_surcharge_amount(&self) -> Option { self.surcharge_amount - .map(|surcharge_amount| surcharge_amount + self.tax_amount.unwrap_or(0)) + .map(|surcharge_amount| surcharge_amount.add(self.tax_amount.unwrap_or_default())) } } @@ -194,18 +199,18 @@ pub struct PaymentAttemptNew { pub merchant_id: String, pub attempt_id: String, pub status: storage_enums::AttemptStatus, - pub amount: i64, + pub amount: MinorUnit, /// amount + surcharge_amount + tax_amount /// This field will always be derived before updating in the Database - pub net_amount: i64, + pub net_amount: MinorUnit, 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 offer_amount: Option, + pub surcharge_amount: Option, + pub tax_amount: Option, pub payment_method_id: Option, pub payment_method: Option, pub capture_method: Option, @@ -220,7 +225,7 @@ pub struct PaymentAttemptNew { #[serde(default, with = "common_utils::custom_serde::iso8601::option")] pub last_synced: Option, pub cancellation_reason: Option, - pub amount_to_capture: Option, + pub amount_to_capture: Option, pub mandate_id: Option, pub browser_info: Option, pub payment_token: Option, @@ -236,7 +241,7 @@ pub struct PaymentAttemptNew { pub error_reason: Option, pub connector_response_reference_id: Option, pub multiple_capture_count: Option, - pub amount_capturable: i64, + pub amount_capturable: MinorUnit, pub updated_by: String, pub authentication_data: Option, pub encoded_data: Option, @@ -253,8 +258,12 @@ pub struct PaymentAttemptNew { 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 calculate_net_amount(&self) -> MinorUnit { + self.amount.add( + self.surcharge_amount + .unwrap_or_default() + .add(self.tax_amount.unwrap_or_default()), + ) } pub fn populate_derived_fields(self) -> Self { @@ -267,7 +276,7 @@ impl PaymentAttemptNew { #[derive(Debug, Clone, Serialize, Deserialize)] pub enum PaymentAttemptUpdate { Update { - amount: i64, + amount: MinorUnit, currency: storage_enums::Currency, status: storage_enums::AttemptStatus, authentication_type: Option, @@ -277,10 +286,10 @@ pub enum PaymentAttemptUpdate { payment_method_type: Option, payment_experience: Option, business_sub_label: Option, - amount_to_capture: Option, + amount_to_capture: Option, capture_method: Option, - surcharge_amount: Option, - tax_amount: Option, + surcharge_amount: Option, + tax_amount: Option, fingerprint_id: Option, updated_by: String, }, @@ -288,9 +297,9 @@ pub enum PaymentAttemptUpdate { payment_token: Option, connector: Option, straight_through_algorithm: Option, - amount_capturable: Option, - surcharge_amount: Option, - tax_amount: Option, + amount_capturable: Option, + surcharge_amount: Option, + tax_amount: Option, updated_by: String, merchant_connector_id: Option, }, @@ -299,7 +308,7 @@ pub enum PaymentAttemptUpdate { updated_by: String, }, ConfirmUpdate { - amount: i64, + amount: MinorUnit, currency: storage_enums::Currency, status: storage_enums::AttemptStatus, authentication_type: Option, @@ -315,10 +324,10 @@ pub enum PaymentAttemptUpdate { straight_through_algorithm: Option, error_code: Option>, error_message: Option>, - amount_capturable: Option, + amount_capturable: Option, updated_by: String, - surcharge_amount: Option, - tax_amount: Option, + surcharge_amount: Option, + tax_amount: Option, merchant_connector_id: Option, external_three_ds_authentication_attempted: Option, authentication_connector: Option, @@ -361,7 +370,7 @@ pub enum PaymentAttemptUpdate { error_message: Option>, error_reason: Option>, connector_response_reference_id: Option, - amount_capturable: Option, + amount_capturable: Option, updated_by: String, authentication_data: Option, encoded_data: Option, @@ -390,7 +399,7 @@ pub enum PaymentAttemptUpdate { error_code: Option>, error_message: Option>, error_reason: Option>, - amount_capturable: Option, + amount_capturable: Option, updated_by: String, unified_code: Option>, unified_message: Option>, @@ -398,13 +407,13 @@ pub enum PaymentAttemptUpdate { payment_method_data: Option, }, CaptureUpdate { - amount_to_capture: Option, + amount_to_capture: Option, multiple_capture_count: Option, updated_by: String, }, AmountToCaptureUpdate { status: storage_enums::AttemptStatus, - amount_capturable: i64, + amount_capturable: MinorUnit, updated_by: String, }, PreprocessingUpdate { @@ -424,8 +433,8 @@ pub enum PaymentAttemptUpdate { updated_by: String, }, IncrementalAuthorizationAmountUpdate { - amount: i64, - amount_capturable: i64, + amount: MinorUnit, + amount_capturable: MinorUnit, }, AuthenticationUpdate { status: storage_enums::AttemptStatus, diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs index a5e631b5ac3..b144271b76a 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -1,3 +1,4 @@ +use api_models::payments::MinorUnit; use common_enums as storage_enums; use common_utils::{ consts::{PAYMENTS_LIST_MAX_LIMIT_V1, PAYMENTS_LIST_MAX_LIMIT_V2}, @@ -74,9 +75,9 @@ pub struct PaymentIntentNew { pub payment_id: String, pub merchant_id: String, pub status: storage_enums::IntentStatus, - pub amount: i64, + pub amount: MinorUnit, pub currency: Option, - pub amount_captured: Option, + pub amount_captured: Option, pub customer_id: Option, pub description: Option, pub return_url: Option, @@ -119,7 +120,7 @@ pub struct PaymentIntentNew { pub enum PaymentIntentUpdate { ResponseUpdate { status: storage_enums::IntentStatus, - amount_captured: Option, + amount_captured: Option, return_url: Option, updated_by: String, fingerprint_id: Option, @@ -149,7 +150,7 @@ pub enum PaymentIntentUpdate { updated_by: String, }, Update { - amount: i64, + amount: MinorUnit, currency: storage_enums::Currency, setup_future_usage: Option, status: storage_enums::IntentStatus, @@ -196,7 +197,7 @@ pub enum PaymentIntentUpdate { updated_by: String, }, IncrementalAuthorizationAmountUpdate { - amount: i64, + amount: MinorUnit, }, AuthorizationCountUpdate { authorization_count: i32, @@ -205,10 +206,10 @@ pub enum PaymentIntentUpdate { #[derive(Clone, Debug, Default)] pub struct PaymentIntentUpdateInternal { - pub amount: Option, + pub amount: Option, pub currency: Option, pub status: Option, - pub amount_captured: Option, + pub amount_captured: Option, pub customer_id: Option, pub return_url: Option, pub setup_future_usage: Option, diff --git a/crates/router/src/compatibility/stripe/payment_intents/types.rs b/crates/router/src/compatibility/stripe/payment_intents/types.rs index eed80a1128e..886eef585c6 100644 --- a/crates/router/src/compatibility/stripe/payment_intents/types.rs +++ b/crates/router/src/compatibility/stripe/payment_intents/types.rs @@ -1,6 +1,6 @@ use std::str::FromStr; -use api_models::payments; +use api_models::{payments, payments::MinorUnit}; use common_utils::{ crypto::Encryptable, date_time, @@ -312,9 +312,11 @@ impl TryFrom for payments::PaymentsRequest { expected_format: "127.0.0.1".to_string(), })?; + let amount = item.amount.map(|amount| MinorUnit::new(amount).into()); + let request = Ok(Self { payment_id: item.id.map(payments::PaymentIdType::PaymentIntentId), - amount: item.amount.map(|amount| amount.into()), + amount, currency: item .currency .as_ref() @@ -324,7 +326,7 @@ impl TryFrom for payments::PaymentsRequest { field_name: "currency", })?, capture_method: item.capture_method, - amount_to_capture: item.amount_capturable, + amount_to_capture: MinorUnit::new_from_optional_i64_amount(item.amount_capturable), confirm: item.confirm, customer_id: item.customer, email: item.receipt_email, @@ -508,9 +510,9 @@ impl From for StripePaymentIntentResponse { object: "payment_intent", id: resp.payment_id, status: StripePaymentStatus::from(resp.status), - amount: resp.amount, - amount_capturable: resp.amount_capturable, - amount_received: resp.amount_received, + amount: resp.amount.get_amount_as_i64(), + amount_capturable: MinorUnit::get_optional_amount_as_i64(resp.amount_capturable), + amount_received: MinorUnit::get_optional_amount_as_i64(resp.amount_received), connector: resp.connector, client_secret: resp.client_secret, created: resp.created.map(|t| t.assume_utc().unix_timestamp()), @@ -727,7 +729,7 @@ impl ForeignTryFrom<(Option, Option)> for Option match item { StripeMandateType::SingleUse => Some(payments::MandateType::SingleUse( payments::MandateAmountData { - amount: mandate.amount.unwrap_or_default(), + amount: MinorUnit::new(mandate.amount.unwrap_or_default()), currency, start_date: mandate.start_date, end_date: mandate.end_date, @@ -736,7 +738,7 @@ impl ForeignTryFrom<(Option, Option)> for Option Some(payments::MandateType::MultiUse(Some( payments::MandateAmountData { - amount: mandate.amount.unwrap_or_default(), + amount: MinorUnit::new(mandate.amount.unwrap_or_default()), currency, start_date: mandate.start_date, end_date: mandate.end_date, @@ -746,7 +748,7 @@ impl ForeignTryFrom<(Option, Option)> for Option Some(api_models::payments::MandateType::MultiUse(Some( payments::MandateAmountData { - amount: mandate.amount.unwrap_or_default(), + amount: MinorUnit::new(mandate.amount.unwrap_or_default()), currency, start_date: mandate.start_date, end_date: mandate.end_date, diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index 6dfe899f2d1..b61c6faa4d4 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -3963,7 +3963,7 @@ impl TryFrom> connector_response_reference_id: Some(item.response.reference), incremental_authorization_allowed: None, }), - amount_captured: Some(0), + amount_captured: Some(api_models::payments::MinorUnit::new(0)), ..item.data }) } diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index 3fff6d940d6..0b98d7c683f 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -922,7 +922,9 @@ impl TryFrom> incremental_authorization_allowed: None, }), status, - amount_captured, + amount_captured: api_models::payments::MinorUnit::new_from_optional_i64_amount( + amount_captured, + ), ..item.data }) } diff --git a/crates/router/src/connector/cryptopay/transformers.rs b/crates/router/src/connector/cryptopay/transformers.rs index b8f398a0d96..233ddca3d1b 100644 --- a/crates/router/src/connector/cryptopay/transformers.rs +++ b/crates/router/src/connector/cryptopay/transformers.rs @@ -211,7 +211,9 @@ impl Ok(Self { status, response, - amount_captured, + amount_captured: api_models::payments::MinorUnit::new_from_optional_i64_amount( + amount_captured, + ), ..item.data }) } diff --git a/crates/router/src/connector/noon/transformers.rs b/crates/router/src/connector/noon/transformers.rs index 8fd148864f5..de20f37cf37 100644 --- a/crates/router/src/connector/noon/transformers.rs +++ b/crates/router/src/connector/noon/transformers.rs @@ -378,7 +378,10 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for NoonPaymentsRequest { )) | Some(hyperswitch_domain_models::mandates::MandateDataType::MultiUse(Some( mandate, - ))) => conn_utils::to_currency_base_unit(mandate.amount, mandate.currency), + ))) => conn_utils::to_currency_base_unit( + mandate.amount.get_amount_as_i64(), + mandate.currency, + ), Some(hyperswitch_domain_models::mandates::MandateDataType::MultiUse(None)) => { Err(errors::ConnectorError::MissingRequiredField { field_name: diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index 21b0f04af86..50307f03c8f 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -1800,7 +1800,7 @@ impl TryFrom> .or(Some(item.response.id)), incremental_authorization_allowed: None, }), - amount_captured: Some(amount_captured), + amount_captured: Some(api_models::payments::MinorUnit::new(amount_captured)), ..item.data }) } diff --git a/crates/router/src/connector/payu/transformers.rs b/crates/router/src/connector/payu/transformers.rs index 575f199b730..3bc6303a77e 100644 --- a/crates/router/src/connector/payu/transformers.rs +++ b/crates/router/src/connector/payu/transformers.rs @@ -485,12 +485,12 @@ impl .or(Some(order.order_id.clone())), incremental_authorization_allowed: None, }), - amount_captured: Some( + amount_captured: Some(api_models::payments::MinorUnit::new( order .total_amount .parse::() .change_context(errors::ConnectorError::ResponseDeserializationFailed)?, - ), + )), ..item.data }) } diff --git a/crates/router/src/connector/square/transformers.rs b/crates/router/src/connector/square/transformers.rs index 318e33978cc..6fd8ba2abbd 100644 --- a/crates/router/src/connector/square/transformers.rs +++ b/crates/router/src/connector/square/transformers.rs @@ -385,7 +385,9 @@ impl connector_response_reference_id: item.response.payment.reference_id, incremental_authorization_allowed: None, }), - amount_captured, + amount_captured: api_models::payments::MinorUnit::new_from_optional_i64_amount( + amount_captured, + ), ..item.data }) } diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 6932f6b7495..1f9f4c5371e 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -2524,7 +2524,9 @@ impl // statement_descriptor_suffix: item.response.statement_descriptor_suffix.map(|x| x.as_str()), // three_ds_form, response, - amount_captured: item.response.amount_received, + amount_captured: api_models::payments::MinorUnit::new_from_optional_i64_amount( + item.response.amount_received, + ), connector_response: connector_response_data, ..item.data }) @@ -2697,7 +2699,9 @@ impl Ok(Self { status: enums::AttemptStatus::from(item.response.status.to_owned()), response, - amount_captured: item.response.amount_received, + amount_captured: api_models::payments::MinorUnit::new_from_optional_i64_amount( + item.response.amount_received, + ), connector_response: connector_response_data, ..item.data }) diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 2cb3aa436e4..2287e8fc4bd 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use api_models::payouts::PayoutVendorAccountDetails; use api_models::{ enums::{CanadaStatesAbbreviation, UsStatesAbbreviation}, - payments::{self, OrderDetailsWithAmount}, + payments::{self, MinorUnit, OrderDetailsWithAmount}, }; use base64::Engine; use common_utils::{ @@ -130,7 +130,12 @@ where { match self.status { enums::AttemptStatus::Voided => { - if payment_data.payment_intent.amount_captured > Some(0) { + if payment_data + .payment_intent + .amount_captured + .unwrap_or_default() + .is_greater_than(MinorUnit::new(0)) + { enums::AttemptStatus::PartialCharged } else { self.status @@ -140,7 +145,9 @@ where let captured_amount = types::Capturable::get_captured_amount(&self.request, payment_data); let total_capturable_amount = payment_data.payment_attempt.get_total_amount(); - if Some(total_capturable_amount) == captured_amount { + if total_capturable_amount + .is_equal(MinorUnit::new(captured_amount.unwrap_or_default())) + { enums::AttemptStatus::Charged } else if captured_amount.is_some() { enums::AttemptStatus::PartialCharged @@ -673,23 +680,27 @@ impl PaymentsAuthorizeRequestData for types::PaymentsAuthorizeData { fn get_original_amount(&self) -> i64 { self.surcharge_details .as_ref() - .map(|surcharge_details| surcharge_details.original_amount) + .map(|surcharge_details| surcharge_details.original_amount.get_amount_as_i64()) .unwrap_or(self.amount) } fn get_surcharge_amount(&self) -> Option { self.surcharge_details .as_ref() - .map(|surcharge_details| surcharge_details.surcharge_amount) + .map(|surcharge_details| surcharge_details.surcharge_amount.get_amount_as_i64()) } fn get_tax_on_surcharge_amount(&self) -> Option { - self.surcharge_details - .as_ref() - .map(|surcharge_details| surcharge_details.tax_on_surcharge_amount) + self.surcharge_details.as_ref().map(|surcharge_details| { + surcharge_details + .tax_on_surcharge_amount + .get_amount_as_i64() + }) } fn get_total_surcharge_amount(&self) -> Option { - self.surcharge_details - .as_ref() - .map(|surcharge_details| surcharge_details.get_total_surcharge_amount()) + self.surcharge_details.as_ref().map(|surcharge_details| { + surcharge_details + .get_total_surcharge_amount() + .get_amount_as_i64() + }) } fn is_customer_initiated_mandate_payment(&self) -> bool { diff --git a/crates/router/src/core/authentication.rs b/crates/router/src/core/authentication.rs index f9161f2ccc6..ac5bb4099bf 100644 --- a/crates/router/src/core/authentication.rs +++ b/crates/router/src/core/authentication.rs @@ -31,7 +31,7 @@ pub async fn perform_authentication( browser_details: Option, business_profile: core_types::storage::BusinessProfile, merchant_connector_account: payments_core::helpers::MerchantConnectorAccountType, - amount: Option, + amount: api_models::payments::MinorUnit, currency: Option, message_category: api::authentication::MessageCategory, device_channel: payments::DeviceChannel, diff --git a/crates/router/src/core/authentication/transformers.rs b/crates/router/src/core/authentication/transformers.rs index d4cad2fbedb..312db2d84fe 100644 --- a/crates/router/src/core/authentication/transformers.rs +++ b/crates/router/src/core/authentication/transformers.rs @@ -32,7 +32,7 @@ pub fn construct_authentication_router_data( billing_address: api_models::payments::Address, shipping_address: Option, browser_details: Option, - amount: Option, + amount: api_models::payments::MinorUnit, currency: Option, message_category: types::api::authentication::MessageCategory, device_channel: payments::DeviceChannel, @@ -61,7 +61,7 @@ pub fn construct_authentication_router_data( billing_address, shipping_address, browser_details, - amount, + amount: Some(amount.get_amount_as_i64()), currency, message_category, device_channel, diff --git a/crates/router/src/core/fraud_check.rs b/crates/router/src/core/fraud_check.rs index 5e03033977e..ce758abf497 100644 --- a/crates/router/src/core/fraud_check.rs +++ b/crates/router/src/core/fraud_check.rs @@ -706,7 +706,7 @@ pub fn is_operation_allowed(operation: &Op) -> bool { impl From for PaymentDetails { fn from(payment_data: PaymentToFrmData) -> Self { Self { - amount: payment_data.amount.into(), + amount: api_models::payments::MinorUnit::from(payment_data.amount).get_amount_as_i64(), currency: payment_data.payment_attempt.currency, payment_method: payment_data.payment_attempt.payment_method, payment_method_type: payment_data.payment_attempt.payment_method_type, 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 58e82ec21c7..01676cfd6d4 100644 --- a/crates/router/src/core/fraud_check/flows/checkout_flow.rs +++ b/crates/router/src/core/fraud_check/flows/checkout_flow.rs @@ -69,7 +69,7 @@ impl ConstructFlowSpecificData( amount_captured: payment_intent.amount_captured, payment_method_status: None, request: FraudCheckFulfillmentData { - amount: payment_attempt.amount, + amount: payment_attempt.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 ad74f7f7027..b854a333770 100644 --- a/crates/router/src/core/fraud_check/flows/record_return.rs +++ b/crates/router/src/core/fraud_check/flows/record_return.rs @@ -67,7 +67,7 @@ impl ConstructFlowSpecificData bool { - let amount = payment_intent.amount; + let amount = payment_intent.amount.get_amount_as_i64(); (pm.maximum_amount.map_or(true, |amt| amount <= amt.into()) && pm.minimum_amount.map_or(true, |amt| amount >= amt.into())) - || payment_intent.amount == 0 + || payment_intent.amount.get_amount_as_i64() == 0 } async fn filter_payment_mandate_based( diff --git a/crates/router/src/core/payment_methods/surcharge_decision_configs.rs b/crates/router/src/core/payment_methods/surcharge_decision_configs.rs index e89fb22e879..9b9e501d474 100644 --- a/crates/router/src/core/payment_methods/surcharge_decision_configs.rs +++ b/crates/router/src/core/payment_methods/surcharge_decision_configs.rs @@ -2,7 +2,9 @@ use std::sync::Arc; use api_models::{ payment_methods::SurchargeDetailsResponse, - payments, routing, + payments, + payments::MinorUnit, + routing, surcharge_decision_configs::{self, SurchargeDecisionConfigs, SurchargeDecisionManagerRecord}, }; use common_utils::{ext_traits::StringExt, static_cache::StaticCache, types as common_utils_types}; @@ -353,7 +355,7 @@ fn get_surcharge_details_from_surcharge_output( let surcharge_amount = match surcharge_details.surcharge.clone() { surcharge_decision_configs::SurchargeOutput::Fixed { amount } => amount, surcharge_decision_configs::SurchargeOutput::Rate(percentage) => percentage - .apply_and_ceil_result(payment_attempt.amount) + .apply_and_ceil_result(payment_attempt.amount.get_amount_as_i64()) .change_context(ConfigError::DslExecutionError) .attach_printable("Failed to Calculate surcharge amount by applying percentage")?, }; @@ -379,9 +381,11 @@ 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, + surcharge_amount: MinorUnit::new(surcharge_amount), + tax_on_surcharge_amount: MinorUnit::new(tax_on_surcharge_amount), + final_amount: MinorUnit::new( + payment_attempt.amount.get_amount_as_i64() + surcharge_amount + tax_on_surcharge_amount, + ), }) } diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 815c604a0e3..02e298562a3 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -685,13 +685,15 @@ where O: Send + Clone + Sync, { if let Some(surcharge_amount) = payment_data.payment_attempt.surcharge_amount { - let tax_on_surcharge_amount = payment_data.payment_attempt.tax_amount.unwrap_or(0); - let final_amount = - payment_data.payment_attempt.amount + surcharge_amount + tax_on_surcharge_amount; + let tax_on_surcharge_amount = payment_data.payment_attempt.tax_amount.unwrap_or_default(); + let final_amount = payment_data + .payment_attempt + .amount + .add(surcharge_amount.add(tax_on_surcharge_amount)); Ok(Some(api::SessionSurchargeDetails::PreDetermined( types::SurchargeDetails { original_amount: payment_data.payment_attempt.amount, - surcharge: Surcharge::Fixed(surcharge_amount), + surcharge: Surcharge::Fixed(surcharge_amount.get_amount_as_i64()), tax_on_surcharge: None, surcharge_amount, tax_on_surcharge_amount, @@ -3910,7 +3912,7 @@ pub async fn payment_external_authentication( .change_context(errors::ApiErrorResponse::InternalServerError) .attach_printable("'profile_id' not set in payment intent")?; let currency = payment_attempt.currency.get_required_value("currency")?; - let amount = payment_attempt.get_total_amount().into(); + let amount = payment_attempt.get_total_amount(); let shipping_address = helpers::create_or_find_address_for_payment_by_request( db, None, diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index d2a2896de8c..b5e4f38163d 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, str::FromStr}; use api_models::{ mandates::RecurringDetails, - payments::{CardToken, GetPaymentMethodType, RequestSurchargeDetails}, + payments::{CardToken, GetPaymentMethodType, MinorUnit, RequestSurchargeDetails}, }; use base64::Engine; use common_utils::{ @@ -598,7 +598,8 @@ pub async fn get_token_for_recurring_mandate( .await .flatten(); - let original_payment_authorized_amount = original_payment_intent.clone().map(|pi| pi.amount); + let original_payment_authorized_amount = + MinorUnit::get_optional_amount_as_i64(original_payment_intent.clone().map(|pi| pi.amount)); let original_payment_authorized_currency = original_payment_intent.clone().and_then(|pi| pi.currency); @@ -728,7 +729,11 @@ pub fn validate_request_amount_and_amount_to_capture( // then amount to be capture should be less than or equal to request amount let total_capturable_amount = amount_inner.get() + surcharge_details - .map(|surcharge_details| surcharge_details.get_total_surcharge_amount()) + .map(|surcharge_details| { + surcharge_details + .get_total_surcharge_amount() + .get_amount_as_i64() + }) .unwrap_or(0); utils::when(!amount_to_capture.le(&total_capturable_amount), || { Err(report!(errors::ApiErrorResponse::PreconditionFailed { @@ -764,31 +769,38 @@ pub fn validate_amount_to_capture_and_capture_method( if capture_method == api_enums::CaptureMethod::Automatic { let original_amount = request .amount - .map(|amount| amount.into()) + .map(|amount| api_models::payments::MinorUnit::from(amount)) .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(0) - + payment_attempt.tax_amount.unwrap_or(0) + payment_attempt + .surcharge_amount + .unwrap_or_default() + .add(payment_attempt.tax_amount.unwrap_or_default()) }) }) - .unwrap_or(0); + .unwrap_or_default(); let total_capturable_amount = - original_amount.map(|original_amount| original_amount + surcharge_amount); + original_amount.map(|original_amount| original_amount.add(surcharge_amount)); + let amount_to_capture = request .amount_to_capture .or(payment_attempt.and_then(|pa| pa.amount_to_capture)); + if let Some((total_capturable_amount, amount_to_capture)) = total_capturable_amount.zip(amount_to_capture) { - utils::when(amount_to_capture != total_capturable_amount, || { - Err(report!(errors::ApiErrorResponse::PreconditionFailed { + utils::when( + !amount_to_capture.is_not_equal(total_capturable_amount), + || { + Err(report!(errors::ApiErrorResponse::PreconditionFailed { message: "amount_to_capture must be equal to total_capturable_amount when capture_method = automatic".into() })) - }) + }, + ) } else { Ok(()) } @@ -1096,7 +1108,7 @@ fn validate_recurring_mandate(req: api::MandateValidationFields) -> RouterResult } pub fn verify_mandate_details( - request_amount: i64, + request_amount: MinorUnit, request_currency: api_enums::Currency, mandate: storage::Mandate, ) -> RouterResult<()> { @@ -1104,7 +1116,7 @@ pub fn verify_mandate_details( storage_enums::MandateType::SingleUse => utils::when( mandate .mandate_amount - .map(|mandate_amount| request_amount > mandate_amount) + .map(|mandate_amount| request_amount.get_amount_as_i64() > mandate_amount) .unwrap_or(true), || { Err(report!(errors::ApiErrorResponse::MandateValidationFailed { @@ -1116,7 +1128,8 @@ pub fn verify_mandate_details( mandate .mandate_amount .map(|mandate_amount| { - (mandate.amount_captured.unwrap_or(0) + request_amount) > mandate_amount + (mandate.amount_captured.unwrap_or(0) + request_amount.get_amount_as_i64()) + > mandate_amount }) .unwrap_or(false), || { @@ -2680,7 +2693,7 @@ pub fn generate_mandate( match data.mandate_type.get_required_value("mandate_type")? { hyperswitch_domain_models::mandates::MandateDataType::SingleUse(data) => { new_mandate - .set_mandate_amount(Some(data.amount)) + .set_mandate_amount(Some(data.amount.get_amount_as_i64())) .set_mandate_currency(Some(data.currency)) .set_mandate_type(storage_enums::MandateType::SingleUse) .to_owned() @@ -2689,7 +2702,7 @@ pub fn generate_mandate( hyperswitch_domain_models::mandates::MandateDataType::MultiUse(op_data) => { match op_data { Some(data) => new_mandate - .set_mandate_amount(Some(data.amount)) + .set_mandate_amount(Some(data.amount.get_amount_as_i64())) .set_mandate_currency(Some(data.currency)) .set_start_date(data.start_date) .set_end_date(data.end_date), diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index d4c3f0acad7..a8a85eb5b00 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -78,8 +78,10 @@ impl helpers::validate_status_with_capture_method(payment_intent.status, capture_method)?; helpers::validate_amount_to_capture( - payment_attempt.amount_capturable, - request.amount_to_capture, + payment_attempt.amount_capturable.get_amount_as_i64(), + request + .amount_to_capture + .map(|capture_amount| capture_amount.get_amount_as_i64()), )?; helpers::validate_capture_method(capture_method)?; @@ -90,8 +92,8 @@ impl .get_required_value("amount_to_capture")?; helpers::validate_amount_to_capture( - payment_attempt.amount_capturable, - Some(amount_to_capture), + payment_attempt.amount_capturable.get_amount_as_i64(), + Some(amount_to_capture.get_amount_as_i64()), )?; let previous_captures = db diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index 89c996236a3..fcebfdc9f47 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -78,7 +78,7 @@ impl if let Some(order_details) = &request.order_details { helpers::validate_order_details_amount( order_details.to_owned(), - payment_intent.amount, + payment_intent.amount.get_amount_as_i64(), false, )?; } diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index e770da70747..42b5651aa94 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -2,6 +2,7 @@ use std::marker::PhantomData; use api_models::{ enums::FrmSuggestion, mandates::RecurringDetails, payment_methods::PaymentMethodsData, + payments::MinorUnit, }; use async_trait::async_trait; use common_utils::ext_traits::{AsyncExt, Encode, ValueExt}; @@ -291,7 +292,7 @@ impl if let Some(order_details) = &request.order_details { helpers::validate_order_details_amount( order_details.to_owned(), - payment_intent.amount, + payment_intent.amount.get_amount_as_i64(), false, )?; } @@ -693,7 +694,7 @@ impl ValidateRequest 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 { - (Some( - storage::PaymentAttemptUpdate::IncrementalAuthorizationAmountUpdate { - amount: incremental_authorization_details.total_amount, - amount_capturable: incremental_authorization_details.total_amount, - }, - ), Some( - storage::PaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { - amount: incremental_authorization_details.total_amount, - }, - )) - } else { - (None, None) - } + 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: MinorUnit::new( + incremental_authorization_details.total_amount, + ), + amount_capturable: MinorUnit::new( + incremental_authorization_details.total_amount, + ), + }, + ), + Some( + storage::PaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { + amount: MinorUnit::new( + incremental_authorization_details.total_amount, + ), + }, + ), + ) + } 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 { payment_data.payment_attempt = db @@ -782,9 +793,11 @@ async fn payment_response_update_tracker( error_message: Some(Some(err.message)), error_code: Some(Some(err.code)), error_reason: Some(err.reason), - amount_capturable: router_data - .request - .get_amount_capturable(&payment_data, status), + amount_capturable: MinorUnit::new_from_optional_i64_amount( + router_data + .request + .get_amount_capturable(&payment_data, status), + ), updated_by: storage_scheme.to_string(), unified_code: option_gsm.clone().map(|gsm| gsm.unified_code), unified_message: option_gsm.map(|gsm| gsm.unified_message), @@ -927,9 +940,12 @@ async fn payment_response_update_tracker( connector: None, connector_transaction_id: connector_transaction_id.clone(), authentication_type: None, - amount_capturable: router_data - .request - .get_amount_capturable(&payment_data, updated_attempt_status), + amount_capturable: MinorUnit::new_from_optional_i64_amount( + router_data.request.get_amount_capturable( + &payment_data, + updated_attempt_status, + ), + ), payment_method_id, mandate_id: payment_data.payment_attempt.mandate_id.clone(), connector_metadata, @@ -1017,7 +1033,7 @@ async fn payment_response_update_tracker( payment_attempt_update = Some(storage::PaymentAttemptUpdate::AmountToCaptureUpdate { status: multiple_capture_data.get_attempt_status(authorized_amount), amount_capturable: authorized_amount - - multiple_capture_data.get_total_blocked_amount(), + .substract(multiple_capture_data.get_total_blocked_amount()), updated_by: storage_scheme.to_string(), }); Some(multiple_capture_data) @@ -1157,7 +1173,7 @@ async fn payment_response_update_tracker( payments::tokenization::update_connector_mandate_details_in_payment_method( payment_method.clone(), payment_method.payment_method_type, - Some(payment_data.payment_attempt.amount), + Some(payment_data.payment_attempt.amount.get_amount_as_i64()), payment_data.payment_attempt.currency, payment_data.payment_attempt.merchant_connector_id.clone(), connector_mandate_id, @@ -1358,10 +1374,10 @@ fn get_capture_update_for_unmapped_capture_responses( fn get_total_amount_captured( request: &T, - amount_captured: Option, + amount_captured: Option, router_data_status: enums::AttemptStatus, payment_data: &PaymentData, -) -> Option { +) -> Option { match &payment_data.multiple_capture_data { Some(multiple_capture_data) => { //multiple capture @@ -1369,7 +1385,8 @@ fn get_total_amount_captured( } None => { //Non multiple capture - let amount = request.get_captured_amount(payment_data); + let amount = + MinorUnit::new_from_optional_i64_amount(request.get_captured_amount(payment_data)); amount_captured.or_else(|| { if router_data_status == enums::AttemptStatus::Charged { amount diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 0aaa6006052..5b50fe11a7d 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -1,7 +1,9 @@ use std::marker::PhantomData; use api_models::{ - enums::FrmSuggestion, mandates::RecurringDetails, payments::RequestSurchargeDetails, + enums::FrmSuggestion, + mandates::RecurringDetails, + payments::{MinorUnit, RequestSurchargeDetails}, }; use async_trait::async_trait; use common_utils::ext_traits::{AsyncExt, Encode, ValueExt}; @@ -66,7 +68,7 @@ impl if let Some(order_details) = &request.order_details { helpers::validate_order_details_amount( order_details.to_owned(), - payment_intent.amount, + payment_intent.amount.get_amount_as_i64(), false, )?; } @@ -153,7 +155,7 @@ impl helpers::validate_request_amount_and_amount_to_capture( request.amount, - request.amount_to_capture, + MinorUnit::get_optional_amount_as_i64(request.amount_to_capture), request .surcharge_details .or(payment_attempt.get_surcharge_details()), @@ -341,11 +343,11 @@ impl .as_ref() .map(RequestSurchargeDetails::get_total_surcharge_amount) .or(payment_attempt.get_total_surcharge_amount()); - (amount + surcharge_amount.unwrap_or(0)).into() + MinorUnit::from(amount.add(surcharge_amount.unwrap_or_default())) }; - (Box::new(operations::PaymentConfirm), amount) + (Box::new(operations::PaymentConfirm), amount.into()) } else { - (Box::new(self), amount) + (Box::new(self), amount.into()) }; payment_intent.status = match request.payment_method_data.as_ref() { @@ -693,7 +695,6 @@ impl let order_details = payment_data.payment_intent.order_details.clone(); let metadata = payment_data.payment_intent.metadata.clone(); let session_expiry = payment_data.payment_intent.session_expiry; - payment_data.payment_intent = state .store .update_payment_intent( @@ -766,7 +767,7 @@ impl ValidateRequest })? } - if request.amount < payment_intent.amount { + if request.amount.is_greater_than(payment_intent.amount) { Err(errors::ApiErrorResponse::PreconditionFailed { message: "Amount should be greater than original authorized amount".to_owned(), })? @@ -146,8 +146,8 @@ impl frm_message: None, payment_link_data: None, incremental_authorization_details: Some(IncrementalAuthorizationDetails { - additional_amount: request.amount - amount, - total_amount: request.amount, + additional_amount: request.amount.substract(amount).get_amount_as_i64(), + total_amount: request.amount.get_amount_as_i64(), reason: request.reason.clone(), authorization_id: None, }), @@ -221,7 +221,7 @@ impl error_code: None, error_message: None, connector_authorization_id: None, - previously_authorized_amount: payment_data.payment_intent.amount, + previously_authorized_amount: payment_data.payment_intent.amount.get_amount_as_i64(), }; let authorization = db .store diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index 58c58ffaef8..446490d66ba 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -1,5 +1,6 @@ use std::{str::FromStr, vec::IntoIter}; +use api_models::payments::MinorUnit; use common_utils::ext_traits::Encode; use diesel_models::enums as storage_enums; use error_stack::{report, ResultExt}; @@ -395,7 +396,7 @@ where error_message: None, error_reason: None, amount_capturable: if router_data.status.is_terminal_status() { - Some(0) + Some(MinorUnit::new(0)) } else { None }, @@ -426,7 +427,7 @@ where error_message: Some(Some(error_response.message.clone())), status: storage_enums::AttemptStatus::Failure, error_reason: Some(error_response.reason.clone()), - amount_capturable: Some(0), + amount_capturable: Some(MinorUnit::new(0)), updated_by: storage_scheme.to_string(), unified_code: option_gsm.clone().map(|gsm| gsm.unified_code), unified_message: option_gsm.map(|gsm| gsm.unified_message), diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index ff7303c900d..d623d90ca73 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -211,7 +211,7 @@ where }; let payment_input = dsl_inputs::PaymentInput { - amount: payment_data.payment_intent.amount, + amount: payment_data.payment_intent.amount.get_amount_as_i64(), card_bin: payment_data .payment_method_data .as_ref() @@ -889,7 +889,7 @@ pub async fn perform_session_flow_routing( }; let payment_input = dsl_inputs::PaymentInput { - amount: session_input.payment_intent.amount, + amount: session_input.payment_intent.amount.get_amount_as_i64(), currency: session_input .payment_intent .currency @@ -1134,7 +1134,7 @@ pub fn make_dsl_input_for_surcharge( payment_type: None, }; let payment_input = dsl_inputs::PaymentInput { - amount: payment_attempt.amount, + amount: payment_attempt.amount.get_amount_as_i64(), // 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 d459f632d8f..0ac31a59a30 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -1,6 +1,8 @@ use std::{fmt::Debug, marker::PhantomData, str::FromStr}; -use api_models::payments::{FrmMessage, GetAddressFromPaymentMethodData, RequestSurchargeDetails}; +use api_models::payments::{ + FrmMessage, GetAddressFromPaymentMethodData, MinorUnit, RequestSurchargeDetails, +}; #[cfg(feature = "payouts")] use api_models::payouts::PayoutAttemptResponse; use common_enums::RequestIncrementalAuthorization; @@ -370,7 +372,7 @@ where .as_ref() .get_required_value("currency")?; let amount = currency - .to_currency_base_unit(payment_attempt.amount) + .to_currency_base_unit(payment_attempt.amount.get_amount_as_i64()) .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "amount", })?; @@ -1164,7 +1166,7 @@ impl TryFrom> for types::PaymentsAuthoriz statement_descriptor_suffix: payment_data.payment_intent.statement_descriptor_suffix, statement_descriptor: payment_data.payment_intent.statement_descriptor_name, capture_method: payment_data.payment_attempt.capture_method, - amount, + amount: amount.get_amount_as_i64(), currency: payment_data.currency, browser_info, email: payment_data.email, @@ -1307,7 +1309,7 @@ impl TryFrom> for types::PaymentsCaptureD api::GetToken::Connector, payment_data.payment_attempt.merchant_connector_id.clone(), )?; - let amount_to_capture: i64 = payment_data + let amount_to_capture = payment_data .payment_attempt .amount_to_capture .map_or(payment_data.amount.into(), |capture_amount| capture_amount); @@ -1320,15 +1322,15 @@ impl TryFrom> for types::PaymentsCaptureD .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "browser_info", })?; - + let amount = MinorUnit::from(payment_data.amount); Ok(Self { - amount_to_capture, + amount_to_capture: amount_to_capture.get_amount_as_i64(), // This should be removed once we start moving to connector module currency: payment_data.currency, connector_transaction_id: connector .connector .connector_transaction_id(payment_data.payment_attempt.clone())? .ok_or(errors::ApiErrorResponse::ResourceIdNotFound)?, - payment_amount: payment_data.amount.into(), + payment_amount: amount.get_amount_as_i64(), // This should be removed once we start moving to connector module connector_meta: payment_data.payment_attempt.connector_metadata, multiple_capture_data: match payment_data.multiple_capture_data { Some(multiple_capture_data) => Some(MultipleCaptureRequestData { @@ -1366,8 +1368,9 @@ impl TryFrom> for types::PaymentsCancelDa .change_context(errors::ApiErrorResponse::InvalidDataValue { field_name: "browser_info", })?; + let amount = MinorUnit::from(payment_data.amount); Ok(Self { - amount: Some(payment_data.amount.into()), + amount: Some(amount.get_amount_as_i64()), // This should be removed once we start moving to connector module currency: Some(payment_data.currency), connector_transaction_id: connector .connector @@ -1386,8 +1389,9 @@ 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); Ok(Self { - amount: Some(payment_data.amount.into()), + amount: Some(amount.get_amount_as_i64()), //need to change after we move to connector module currency: Some(payment_data.currency), }) } @@ -1398,8 +1402,9 @@ 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); Ok(Self { - amount: Some(payment_data.amount.into()), + amount: Some(amount.get_amount_as_i64()), //need to change after we move to connector module currency: Some(payment_data.currency), }) } @@ -1435,7 +1440,7 @@ impl TryFrom> for types::PaymentsSessionD .unwrap_or(payment_data.amount.into()); Ok(Self { - amount, + amount: amount.get_amount_as_i64(), //need to change once we move to connector module currency: payment_data.currency, country: payment_data.address.get_payment_method_billing().and_then( |billing_address| { @@ -1483,11 +1488,11 @@ impl TryFrom> for types::SetupMandateRequ .as_ref() .map(|customer| customer.clone().into_inner()) }); - + let amount = MinorUnit::from(payment_data.amount); Ok(Self { currency: payment_data.currency, confirm: true, - amount: Some(payment_data.amount.into()), + amount: Some(amount.get_amount_as_i64()), //need to change once we move to connector module payment_method_data: From::from( payment_data .payment_method_data @@ -1599,7 +1604,7 @@ impl TryFrom> for types::CompleteAuthoriz confirm: payment_data.payment_attempt.confirm, statement_descriptor_suffix: payment_data.payment_intent.statement_descriptor_suffix, capture_method: payment_data.payment_attempt.capture_method, - amount, + amount: amount.get_amount_as_i64(), // need to change once we move to connector module currency: payment_data.currency, browser_info, email: payment_data.email, @@ -1676,7 +1681,7 @@ impl TryFrom> for types::PaymentsPreProce payment_method_data: payment_method_data.map(From::from), email: payment_data.email, currency: Some(payment_data.currency), - amount: Some(amount), + amount: Some(amount.get_amount_as_i64()), // need to change this once we move to connector module payment_method_type: payment_data.payment_attempt.payment_method_type, setup_mandate_details: payment_data.setup_mandate, capture_method: payment_data.payment_attempt.capture_method, diff --git a/crates/router/src/core/payments/types.rs b/crates/router/src/core/payments/types.rs index b297470bce8..30d6b1ddce9 100644 --- a/crates/router/src/core/payments/types.rs +++ b/crates/router/src/core/payments/types.rs @@ -1,6 +1,9 @@ use std::{collections::HashMap, num::TryFromIntError}; -use api_models::{payment_methods::SurchargeDetailsResponse, payments::RequestSurchargeDetails}; +use api_models::{ + payment_methods::SurchargeDetailsResponse, + payments::{MinorUnit, RequestSurchargeDetails}, +}; use common_utils::{ consts, errors::CustomResult, @@ -80,8 +83,8 @@ impl MultipleCaptureData { .and_modify(|capture| *capture = updated_capture.clone()); } } - pub fn get_total_blocked_amount(&self) -> i64 { - self.all_captures.iter().fold(0, |accumulator, capture| { + pub fn get_total_blocked_amount(&self) -> MinorUnit { + MinorUnit::new(self.all_captures.iter().fold(0, |accumulator, capture| { accumulator + match capture.1.status { storage_enums::CaptureStatus::Charged @@ -89,10 +92,10 @@ impl MultipleCaptureData { storage_enums::CaptureStatus::Started | storage_enums::CaptureStatus::Failed => 0, } - }) + })) } - pub fn get_total_charged_amount(&self) -> i64 { - self.all_captures.iter().fold(0, |accumulator, capture| { + pub fn get_total_charged_amount(&self) -> MinorUnit { + MinorUnit::new(self.all_captures.iter().fold(0, |accumulator, capture| { accumulator + match capture.1.status { storage_enums::CaptureStatus::Charged => capture.1.amount, @@ -100,7 +103,7 @@ impl MultipleCaptureData { | storage_enums::CaptureStatus::Started | storage_enums::CaptureStatus::Failed => 0, } - }) + })) } pub fn get_captures_count(&self) -> RouterResult { i16::try_from(self.all_captures.len()) @@ -123,9 +126,9 @@ impl MultipleCaptureData { accumulator }) } - pub fn get_attempt_status(&self, authorized_amount: i64) -> storage_enums::AttemptStatus { + pub fn get_attempt_status(&self, authorized_amount: MinorUnit) -> storage_enums::AttemptStatus { let total_captured_amount = self.get_total_charged_amount(); - if authorized_amount == total_captured_amount { + if authorized_amount.is_equal(total_captured_amount) { return storage_enums::AttemptStatus::Charged; } let status_count_map = self.get_status_count(); @@ -182,18 +185,18 @@ impl MultipleCaptureData { #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] pub struct SurchargeDetails { /// original_amount - pub original_amount: i64, + pub original_amount: MinorUnit, /// surcharge value pub surcharge: common_types::Surcharge, /// tax on surcharge value pub tax_on_surcharge: Option>, /// surcharge amount for this payment - pub surcharge_amount: i64, + pub surcharge_amount: MinorUnit, /// tax on surcharge amount for this payment - pub tax_on_surcharge_amount: i64, + pub tax_on_surcharge_amount: MinorUnit, /// sum of original amount, - pub final_amount: i64, + pub final_amount: MinorUnit, } impl From<(&RequestSurchargeDetails, &PaymentAttempt)> for SurchargeDetails { @@ -201,14 +204,20 @@ impl From<(&RequestSurchargeDetails, &PaymentAttempt)> for SurchargeDetails { (request_surcharge_details, payment_attempt): (&RequestSurchargeDetails, &PaymentAttempt), ) -> Self { let surcharge_amount = request_surcharge_details.surcharge_amount; - let tax_on_surcharge_amount = request_surcharge_details.tax_amount.unwrap_or(0); + let tax_on_surcharge_amount = request_surcharge_details.tax_amount.unwrap_or_default(); Self { original_amount: payment_attempt.amount, - surcharge: common_types::Surcharge::Fixed(request_surcharge_details.surcharge_amount), + surcharge: common_types::Surcharge::Fixed( + request_surcharge_details + .surcharge_amount + .get_amount_as_i64(), + ), // need to check this tax_on_surcharge: None, surcharge_amount, tax_on_surcharge_amount, - final_amount: payment_attempt.amount + surcharge_amount + tax_on_surcharge_amount, + final_amount: payment_attempt + .amount + .add(surcharge_amount.add(tax_on_surcharge_amount)), } } } @@ -219,14 +228,20 @@ impl ForeignTryFrom<(&SurchargeDetails, &PaymentAttempt)> for SurchargeDetailsRe (surcharge_details, payment_attempt): (&SurchargeDetails, &PaymentAttempt), ) -> Result { let currency = payment_attempt.currency.unwrap_or_default(); - let display_surcharge_amount = - currency.to_currency_base_unit_asf64(surcharge_details.surcharge_amount)?; - let display_tax_on_surcharge_amount = - currency.to_currency_base_unit_asf64(surcharge_details.tax_on_surcharge_amount)?; - let display_final_amount = - currency.to_currency_base_unit_asf64(surcharge_details.final_amount)?; + let display_surcharge_amount = currency + .to_currency_base_unit_asf64(surcharge_details.surcharge_amount.get_amount_as_i64())?; + let display_tax_on_surcharge_amount = currency.to_currency_base_unit_asf64( + surcharge_details + .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, + (surcharge_details + .surcharge_amount + .add(surcharge_details.tax_on_surcharge_amount)) + .get_amount_as_i64(), )?; Ok(Self { surcharge: surcharge_details.surcharge.clone().into(), @@ -244,11 +259,16 @@ impl SurchargeDetails { &self, request_surcharge_details: RequestSurchargeDetails, ) -> bool { - request_surcharge_details.surcharge_amount == self.surcharge_amount - && request_surcharge_details.tax_amount.unwrap_or(0) == self.tax_on_surcharge_amount + request_surcharge_details + .surcharge_amount + .is_equal(self.surcharge_amount) + && request_surcharge_details + .tax_amount + .unwrap_or_default() + .is_equal(self.tax_on_surcharge_amount) } - pub fn get_total_surcharge_amount(&self) -> i64 { - self.surcharge_amount + self.tax_on_surcharge_amount + pub fn get_total_surcharge_amount(&self) -> MinorUnit { + self.surcharge_amount.add(self.tax_on_surcharge_amount) } } diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 25f61919207..1871acd246b 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -368,8 +368,10 @@ pub async fn payouts_update_core( // Update DB with new data let payouts = payout_data.payouts.to_owned(); + let amount = api_models::payments::MinorUnit::from(req.amount.unwrap_or(api::Amount::Zero)) + .get_amount_as_i64(); let updated_payouts = storage::PayoutsUpdate::Update { - amount: req.amount.unwrap_or(payouts.amount.into()).into(), + amount, destination_currency: req.currency.unwrap_or(payouts.destination_currency), source_currency: req.currency.unwrap_or(payouts.source_currency), description: req.description.clone().or(payouts.description.clone()), @@ -1964,14 +1966,15 @@ pub async fn payout_create_db_entries( } else { None }; - + let amount = api_models::payments::MinorUnit::from(req.amount.unwrap_or(api::Amount::Zero)) + .get_amount_as_i64(); let payouts_req = storage::PayoutsNew { payout_id: payout_id.to_string(), merchant_id: merchant_id.to_string(), customer_id: customer_id.to_owned(), address_id: address_id.to_owned(), payout_type, - amount: req.amount.unwrap_or(api::Amount::Zero).into(), + amount, destination_currency: currency, source_currency: currency, description: req.description.to_owned(), diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index 2d6cac3f6e0..82db07c4a51 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -66,7 +66,9 @@ pub async fn refund_create_core( // Amount is not passed in request refer from payment intent. amount = req .amount - .or(payment_intent.amount_captured) + .or(payment_intent + .amount_captured + .map(|capture_amount| capture_amount.get_amount_as_i64())) .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable("amount captured is none in a successful payment")?; @@ -165,7 +167,7 @@ pub async fn trigger_refund_to_gateway( &routed_through, merchant_account, key_store, - (payment_attempt.amount, currency), + (payment_attempt.amount.get_amount_as_i64(), currency), payment_intent, payment_attempt, refund, @@ -444,7 +446,7 @@ pub async fn sync_refund_with_gateway( &connector_id, merchant_account, key_store, - (payment_attempt.amount, currency), + (payment_attempt.amount.get_amount_as_i64(), currency), payment_intent, payment_attempt, refund, @@ -622,8 +624,12 @@ pub async fn validate_and_create_refund( .amount_captured .unwrap_or(payment_attempt.amount); - validator::validate_refund_amount(total_amount_captured, &all_refunds, refund_amount) - .change_context(errors::ApiErrorResponse::RefundAmountExceedsPaymentAmount)?; + validator::validate_refund_amount( + total_amount_captured.get_amount_as_i64(), + &all_refunds, + refund_amount, + ) + .change_context(errors::ApiErrorResponse::RefundAmountExceedsPaymentAmount)?; validator::validate_maximum_refund_against_payment_attempt( &all_refunds, @@ -646,7 +652,7 @@ pub async fn validate_and_create_refund( .set_connector_transaction_id(connecter_transaction_id.to_string()) .set_connector(connector) .set_refund_type(req.refund_type.unwrap_or_default().foreign_into()) - .set_total_amount(payment_attempt.amount) + .set_total_amount(payment_attempt.amount.get_amount_as_i64()) .set_refund_amount(refund_amount) .set_currency(currency) .set_created_at(Some(common_utils::date_time::now())) diff --git a/crates/router/src/routes/currency.rs b/crates/router/src/routes/currency.rs index e80bd53d8df..15684e6ae88 100644 --- a/crates/router/src/routes/currency.rs +++ b/crates/router/src/routes/currency.rs @@ -31,7 +31,7 @@ pub async fn convert_forex( params: web::Query, ) -> HttpResponse { let flow = Flow::RetrieveForexFlow; - let amount = ¶ms.amount; + let amount = params.amount; let to_currency = ¶ms.to_currency; let from_currency = ¶ms.from_currency; Box::pin(api::server_wrap( @@ -42,7 +42,7 @@ pub async fn convert_forex( |state, _, _, _| { currency::convert_forex( state, - *amount, + amount.get_amount_as_i64(), to_currency.to_string(), from_currency.to_string(), ) diff --git a/crates/router/src/services/kafka/payment_attempt.rs b/crates/router/src/services/kafka/payment_attempt.rs index 9f442876fab..e9eab66e475 100644 --- a/crates/router/src/services/kafka/payment_attempt.rs +++ b/crates/router/src/services/kafka/payment_attempt.rs @@ -1,4 +1,5 @@ // use diesel_models::enums::MandateDetails; +use api_models::payments::MinorUnit; use diesel_models::enums as storage_enums; use hyperswitch_domain_models::{ mandates::MandateDetails, payments::payment_attempt::PaymentAttempt, @@ -60,14 +61,14 @@ impl<'a> KafkaPaymentAttempt<'a> { merchant_id: &attempt.merchant_id, attempt_id: &attempt.attempt_id, status: attempt.status, - amount: attempt.amount, + amount: attempt.amount.get_amount_as_i64(), 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, + offer_amount: MinorUnit::get_optional_amount_as_i64(attempt.offer_amount), + surcharge_amount: MinorUnit::get_optional_amount_as_i64(attempt.surcharge_amount), + tax_amount: MinorUnit::get_optional_amount_as_i64(attempt.tax_amount), payment_method_id: attempt.payment_method_id.as_ref(), payment_method: attempt.payment_method, connector_transaction_id: attempt.connector_transaction_id.as_ref(), @@ -79,7 +80,7 @@ impl<'a> KafkaPaymentAttempt<'a> { modified_at: attempt.modified_at.assume_utc(), last_synced: attempt.last_synced.map(|i| i.assume_utc()), cancellation_reason: attempt.cancellation_reason.as_ref(), - amount_to_capture: attempt.amount_to_capture, + amount_to_capture: MinorUnit::get_optional_amount_as_i64(attempt.amount_to_capture), mandate_id: attempt.mandate_id.as_ref(), browser_info: attempt.browser_info.as_ref().map(|v| v.to_string()), error_code: attempt.error_code.as_ref(), @@ -89,9 +90,9 @@ impl<'a> KafkaPaymentAttempt<'a> { payment_method_data: attempt.payment_method_data.as_ref().map(|v| v.to_string()), error_reason: attempt.error_reason.as_ref(), multiple_capture_count: attempt.multiple_capture_count, - amount_capturable: attempt.amount_capturable, + amount_capturable: attempt.amount_capturable.get_amount_as_i64(), merchant_connector_id: attempt.merchant_connector_id.as_ref(), - net_amount: attempt.net_amount, + net_amount: attempt.net_amount.get_amount_as_i64(), 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_intent.rs b/crates/router/src/services/kafka/payment_intent.rs index 2edd0d49ccc..6cdcbb1c478 100644 --- a/crates/router/src/services/kafka/payment_intent.rs +++ b/crates/router/src/services/kafka/payment_intent.rs @@ -1,3 +1,4 @@ +use api_models::payments::MinorUnit; use diesel_models::enums as storage_enums; use hyperswitch_domain_models::payments::PaymentIntent; use time::OffsetDateTime; @@ -7,9 +8,9 @@ pub struct KafkaPaymentIntent<'a> { pub payment_id: &'a String, pub merchant_id: &'a String, pub status: storage_enums::IntentStatus, - pub amount: i64, + pub amount: MinorUnit, pub currency: Option, - pub amount_captured: Option, + pub amount_captured: Option, pub customer_id: Option<&'a String>, pub description: Option<&'a String>, pub return_url: Option<&'a String>, diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index bffa3eaf8f8..3811be91a0a 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -18,6 +18,7 @@ pub mod transformers; use std::{collections::HashMap, marker::PhantomData}; +use api_models::payments::MinorUnit; pub use api_models::{enums::Connector, mandates}; #[cfg(feature = "payouts")] pub use api_models::{enums::PayoutConnectors, payouts as payout_types}; @@ -284,7 +285,7 @@ pub struct RouterData { pub address: PaymentAddress, pub auth_type: storage_enums::AuthenticationType, pub connector_meta_data: Option, - pub amount_captured: Option, + pub amount_captured: Option, pub access_token: Option, pub session_token: Option, pub reference_id: Option, @@ -679,7 +680,7 @@ impl Capturable for PaymentsAuthorizeData { let final_amount = self .surcharge_details .as_ref() - .map(|surcharge_details| surcharge_details.final_amount); + .map(|surcharge_details| surcharge_details.final_amount.get_amount_as_i64()); final_amount.or(Some(self.amount)) } @@ -712,7 +713,7 @@ impl Capturable for PaymentsAuthorizeData { | common_enums::IntentStatus::PartiallyCapturedAndCapturable => None, } }, - common_enums::CaptureMethod::Manual => Some(payment_data.payment_attempt.get_total_amount()), + common_enums::CaptureMethod::Manual => Some(payment_data.payment_attempt.get_total_amount().get_amount_as_i64()), // In case of manual multiple, amount capturable must be inferred from all captures. common_enums::CaptureMethod::ManualMultiple | // Scheduled capture is not supported as of now @@ -789,7 +790,7 @@ impl Capturable for CompleteAuthorizeData { | common_enums::IntentStatus::PartiallyCapturedAndCapturable => None, } }, - common_enums::CaptureMethod::Manual => Some(payment_data.payment_attempt.get_total_amount()), + common_enums::CaptureMethod::Manual => Some(payment_data.payment_attempt.get_total_amount().get_amount_as_i64()), // In case of manual multiple, amount capturable must be inferred from all captures. common_enums::CaptureMethod::ManualMultiple | // Scheduled capture is not supported as of now @@ -804,7 +805,7 @@ impl Capturable for PaymentsCancelData { F: Clone, { // return previously captured amount - payment_data.payment_intent.amount_captured + MinorUnit::get_optional_amount_as_i64(payment_data.payment_intent.amount_captured) } fn get_amount_capturable( &self, @@ -850,10 +851,12 @@ impl Capturable for PaymentsSyncData { where F: Clone, { - payment_data - .payment_attempt - .amount_to_capture - .or_else(|| Some(payment_data.payment_attempt.get_total_amount())) + MinorUnit::get_optional_amount_as_i64( + payment_data + .payment_attempt + .amount_to_capture + .or_else(|| Some(payment_data.payment_attempt.get_total_amount())), + ) } fn get_amount_capturable( &self, @@ -1439,7 +1442,7 @@ impl Default for ErrorResponse { impl From<&&mut PaymentsAuthorizeRouterData> for AuthorizeSessionTokenData { fn from(data: &&mut PaymentsAuthorizeRouterData) -> Self { Self { - amount_to_capture: data.amount_captured, + amount_to_capture: MinorUnit::get_optional_amount_as_i64(data.amount_captured), currency: data.request.currency, connector_transaction_id: data.payment_id.clone(), amount: Some(data.request.amount), diff --git a/crates/router/src/types/api/payment_link.rs b/crates/router/src/types/api/payment_link.rs index 85cb539d411..ba1c99e003f 100644 --- a/crates/router/src/types/api/payment_link.rs +++ b/crates/router/src/types/api/payment_link.rs @@ -23,7 +23,7 @@ impl PaymentLinkResponseExt for RetrievePaymentLinkResponse { Ok(Self { link_to_pay: payment_link.link_to_pay, payment_link_id: payment_link.payment_link_id, - amount: payment_link.amount, + amount: api_models::payments::MinorUnit::new(payment_link.amount), description: payment_link.description, created_at: payment_link.created_at, merchant_id: payment_link.merchant_id, diff --git a/crates/router/src/types/storage/payment_attempt.rs b/crates/router/src/types/storage/payment_attempt.rs index 41e1aae635d..2b987c86660 100644 --- a/crates/router/src/types/storage/payment_attempt.rs +++ b/crates/router/src/types/storage/payment_attempt.rs @@ -1,3 +1,4 @@ +use api_models::payments::MinorUnit; use diesel_models::{capture::CaptureNew, enums}; use error_stack::ResultExt; pub use hyperswitch_domain_models::payments::payment_attempt::{ @@ -10,19 +11,19 @@ use crate::{ pub trait PaymentAttemptExt { fn make_new_capture( &self, - capture_amount: i64, + capture_amount: MinorUnit, capture_status: enums::CaptureStatus, ) -> RouterResult; fn get_next_capture_id(&self) -> String; - fn get_total_amount(&self) -> i64; + fn get_total_amount(&self) -> MinorUnit; fn get_surcharge_details(&self) -> Option; } impl PaymentAttemptExt for PaymentAttempt { fn make_new_capture( &self, - capture_amount: i64, + capture_amount: MinorUnit, capture_status: enums::CaptureStatus, ) -> RouterResult { let capture_sequence = self.multiple_capture_count.unwrap_or_default() + 1; @@ -32,7 +33,7 @@ impl PaymentAttemptExt for PaymentAttempt { merchant_id: self.merchant_id.clone(), capture_id: self.get_next_capture_id(), status: capture_status, - amount: capture_amount, + amount: capture_amount.get_amount_as_i64(), currency: self.currency, connector: self .connector @@ -66,8 +67,12 @@ impl PaymentAttemptExt for PaymentAttempt { } }) } - fn get_total_amount(&self) -> i64 { - self.amount + self.surcharge_amount.unwrap_or(0) + self.tax_amount.unwrap_or(0) + fn get_total_amount(&self) -> MinorUnit { + self.amount.add( + self.surcharge_amount + .unwrap_or_default() + .add(self.tax_amount.unwrap_or_default()), + ) } } diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index ef12e32d57c..1577d117242 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -1,7 +1,7 @@ // use actix_web::HttpMessage; use actix_web::http::header::HeaderMap; use api_models::{ - enums as api_enums, gsm as gsm_api_types, payment_methods, payments, + enums as api_enums, gsm as gsm_api_types, payment_methods, payments, payments::MinorUnit, routing::ConnectorSelection, }; use common_utils::{ @@ -305,7 +305,7 @@ impl ForeignTryFrom for common_enums::RoutableConnectors { impl ForeignFrom for api_models::payments::MandateAmountData { fn foreign_from(from: storage_enums::MandateAmountData) -> Self { Self { - amount: from.amount, + amount: MinorUnit::new(from.amount), currency: from.currency, start_date: from.start_date, end_date: from.end_date, @@ -374,7 +374,7 @@ impl ForeignFrom impl ForeignFrom for storage_enums::MandateAmountData { fn foreign_from(from: api_models::payments::MandateAmountData) -> Self { Self { - amount: from.amount, + amount: from.amount.get_amount_as_i64(), currency: from.currency, start_date: from.start_date, end_date: from.end_date, @@ -772,7 +772,7 @@ impl ForeignFrom for payments::IncrementalAuthorizationR fn foreign_from(authorization: storage::Authorization) -> Self { Self { authorization_id: authorization.authorization_id, - amount: authorization.amount, + amount: MinorUnit::new(authorization.amount), status: authorization.status, error_code: authorization.error_code, error_message: authorization.error_message, @@ -934,7 +934,7 @@ impl ForeignFrom for api_models::payments::CaptureResponse { Self { capture_id: capture.capture_id, status: capture.status, - amount: capture.amount, + amount: MinorUnit::new(capture.amount), currency: capture.currency, connector: capture.connector, authorized_attempt_id: capture.authorized_attempt_id, @@ -1088,7 +1088,7 @@ impl payment_link_id: payment_link_config.payment_link_id, merchant_id: payment_link_config.merchant_id, link_to_pay: payment_link_config.link_to_pay, - amount: payment_link_config.amount, + amount: MinorUnit::new(payment_link_config.amount), created_at: payment_link_config.created_at, expiry: payment_link_config.fulfilment_time, description: payment_link_config.description, diff --git a/crates/router/src/utils/user/sample_data.rs b/crates/router/src/utils/user/sample_data.rs index 2216cb10554..e3adbc99584 100644 --- a/crates/router/src/utils/user/sample_data.rs +++ b/crates/router/src/utils/user/sample_data.rs @@ -174,7 +174,7 @@ pub async fn generate_sample_data( true => common_enums::IntentStatus::Failed, _ => common_enums::IntentStatus::Succeeded, }, - amount: amount * 100, + amount: api_models::payments::MinorUnit::new(amount * 100), currency: Some( *currency_vec .get((num - 1) % currency_vec_len) @@ -192,7 +192,9 @@ pub async fn generate_sample_data( ), attempt_count: 1, customer_id: Some("hs-dashboard-user".to_string()), - amount_captured: Some(amount * 100), + amount_captured: api_models::payments::MinorUnit::optional_new_from_i64_amount( + amount * 100, + ), profile_id: Some(profile_id.clone()), return_url: Default::default(), metadata: Default::default(), diff --git a/crates/router/src/workflows/payment_sync.rs b/crates/router/src/workflows/payment_sync.rs index 5dbfff8342e..7da1a82a9e8 100644 --- a/crates/router/src/workflows/payment_sync.rs +++ b/crates/router/src/workflows/payment_sync.rs @@ -133,7 +133,7 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow { error_reason: Some(Some( consts::REQUEST_TIMEOUT_ERROR_MESSAGE_FROM_PSYNC.to_string(), )), - amount_capturable: Some(0), + amount_capturable: api_models::payments::MinorUnit::optional_new_from_i64_amount(0), updated_by: merchant_account.storage_scheme.to_string(), unified_code: None, unified_message: None, diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index 4308e463b0c..3f01efa10b0 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -1,4 +1,7 @@ -use api_models::enums::{AuthenticationType, Connector, PaymentMethod, PaymentMethodType}; +use api_models::{ + enums::{AuthenticationType, Connector, PaymentMethod, PaymentMethodType}, + payments::MinorUnit, +}; use common_utils::{errors::CustomResult, fallback_reverse_lookup_not_found}; use diesel_models::{ enums::{ @@ -1046,7 +1049,7 @@ impl DataModelExt for MandateAmountData { fn to_storage_model(self) -> Self::StorageModel { DieselMandateAmountData { - amount: self.amount, + amount: self.amount.get_amount_as_i64(), currency: self.currency, start_date: self.start_date, end_date: self.end_date, @@ -1056,7 +1059,7 @@ impl DataModelExt for MandateAmountData { fn from_storage_model(storage_model: Self::StorageModel) -> Self { Self { - amount: storage_model.amount, + amount: MinorUnit::new(storage_model.amount), currency: storage_model.currency, start_date: storage_model.start_date, end_date: storage_model.end_date, @@ -1114,15 +1117,19 @@ 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.amount.get_amount_as_i64(), + net_amount: Some(self.net_amount.get_amount_as_i64()), 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, + offer_amount: self + .offer_amount + .map(|offer_amt| offer_amt.get_amount_as_i64()), + surcharge_amount: self + .surcharge_amount + .map(|surcharge_amt| surcharge_amt.get_amount_as_i64()), + tax_amount: self.tax_amount.map(|tax_amt| tax_amt.get_amount_as_i64()), payment_method_id: self.payment_method_id, payment_method: self.payment_method, connector_transaction_id: self.connector_transaction_id, @@ -1134,7 +1141,9 @@ impl DataModelExt for PaymentAttempt { modified_at: self.modified_at, last_synced: self.last_synced, cancellation_reason: self.cancellation_reason, - amount_to_capture: self.amount_to_capture, + amount_to_capture: self + .amount_to_capture + .map(|capture_amt| capture_amt.get_amount_as_i64()), mandate_id: self.mandate_id, browser_info: self.browser_info, error_code: self.error_code, @@ -1150,7 +1159,7 @@ impl DataModelExt for PaymentAttempt { error_reason: self.error_reason, multiple_capture_count: self.multiple_capture_count, connector_response_reference_id: self.connector_response_reference_id, - amount_capturable: self.amount_capturable, + amount_capturable: self.amount_capturable.get_amount_as_i64(), updated_by: self.updated_by, authentication_data: self.authentication_data, encoded_data: self.encoded_data, @@ -1169,20 +1178,26 @@ impl DataModelExt for PaymentAttempt { fn from_storage_model(storage_model: Self::StorageModel) -> Self { Self { - net_amount: storage_model.get_or_calculate_net_amount(), + net_amount: MinorUnit::new(storage_model.get_or_calculate_net_amount()), id: storage_model.id, 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, + amount: MinorUnit::new(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, + offer_amount: storage_model + .offer_amount + .map(|offer_amount| MinorUnit::new(offer_amount)), + surcharge_amount: storage_model + .surcharge_amount + .map(|surcharge_amount| MinorUnit::new(surcharge_amount)), + tax_amount: storage_model + .tax_amount + .map(|tax_amt| MinorUnit::new(tax_amt)), payment_method_id: storage_model.payment_method_id, payment_method: storage_model.payment_method, connector_transaction_id: storage_model.connector_transaction_id, @@ -1194,7 +1209,9 @@ impl DataModelExt for PaymentAttempt { modified_at: storage_model.modified_at, last_synced: storage_model.last_synced, cancellation_reason: storage_model.cancellation_reason, - amount_to_capture: storage_model.amount_to_capture, + amount_to_capture: storage_model + .amount_to_capture + .map(|capture_amt| MinorUnit::new(capture_amt)), mandate_id: storage_model.mandate_id, browser_info: storage_model.browser_info, error_code: storage_model.error_code, @@ -1212,7 +1229,7 @@ impl DataModelExt for PaymentAttempt { error_reason: storage_model.error_reason, multiple_capture_count: storage_model.multiple_capture_count, connector_response_reference_id: storage_model.connector_response_reference_id, - amount_capturable: storage_model.amount_capturable, + amount_capturable: MinorUnit::new(storage_model.amount_capturable), updated_by: storage_model.updated_by, authentication_data: storage_model.authentication_data, encoded_data: storage_model.encoded_data, @@ -1237,19 +1254,23 @@ 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_amount_as_i64()), payment_id: self.payment_id, merchant_id: self.merchant_id, attempt_id: self.attempt_id, status: self.status, - amount: self.amount, + amount: self.amount.get_amount_as_i64(), 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, + offer_amount: self + .offer_amount + .map(|offer_amt| offer_amt.get_amount_as_i64()), + surcharge_amount: self + .surcharge_amount + .map(|surcharge_amt| surcharge_amt.get_amount_as_i64()), + tax_amount: self.tax_amount.map(|tax_amt| tax_amt.get_amount_as_i64()), payment_method_id: self.payment_method_id, payment_method: self.payment_method, capture_method: self.capture_method, @@ -1260,7 +1281,9 @@ impl DataModelExt for PaymentAttemptNew { modified_at: self.modified_at, last_synced: self.last_synced, cancellation_reason: self.cancellation_reason, - amount_to_capture: self.amount_to_capture, + amount_to_capture: self + .amount_to_capture + .map(|capture_amt| capture_amt.get_amount_as_i64()), mandate_id: self.mandate_id, browser_info: self.browser_info, payment_token: self.payment_token, @@ -1276,7 +1299,7 @@ impl DataModelExt for PaymentAttemptNew { error_reason: self.error_reason, connector_response_reference_id: self.connector_response_reference_id, multiple_capture_count: self.multiple_capture_count, - amount_capturable: self.amount_capturable, + amount_capturable: self.amount_capturable.get_amount_as_i64(), updated_by: self.updated_by, authentication_data: self.authentication_data, encoded_data: self.encoded_data, @@ -1295,19 +1318,25 @@ impl DataModelExt for PaymentAttemptNew { fn from_storage_model(storage_model: Self::StorageModel) -> Self { Self { - net_amount: storage_model.get_or_calculate_net_amount(), + net_amount: MinorUnit::new(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, status: storage_model.status, - amount: storage_model.amount, + amount: MinorUnit::new(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, + offer_amount: storage_model + .offer_amount + .map(|offer_amount| MinorUnit::new(offer_amount)), + surcharge_amount: storage_model + .surcharge_amount + .map(|surcharge_amount| MinorUnit::new(surcharge_amount)), + tax_amount: storage_model + .tax_amount + .map(|tax_amount| MinorUnit::new(tax_amount)), payment_method_id: storage_model.payment_method_id, payment_method: storage_model.payment_method, capture_method: storage_model.capture_method, @@ -1318,7 +1347,9 @@ impl DataModelExt for PaymentAttemptNew { modified_at: storage_model.modified_at, last_synced: storage_model.last_synced, cancellation_reason: storage_model.cancellation_reason, - amount_to_capture: storage_model.amount_to_capture, + amount_to_capture: storage_model + .amount_to_capture + .map(|amount_to_capture| MinorUnit::new(amount_to_capture)), mandate_id: storage_model.mandate_id, browser_info: storage_model.browser_info, payment_token: storage_model.payment_token, @@ -1336,7 +1367,7 @@ impl DataModelExt for PaymentAttemptNew { error_reason: storage_model.error_reason, connector_response_reference_id: storage_model.connector_response_reference_id, multiple_capture_count: storage_model.multiple_capture_count, - amount_capturable: storage_model.amount_capturable, + amount_capturable: MinorUnit::new(storage_model.amount_capturable), updated_by: storage_model.updated_by, authentication_data: storage_model.authentication_data, encoded_data: storage_model.encoded_data, @@ -1379,7 +1410,7 @@ impl DataModelExt for PaymentAttemptUpdate { fingerprint_id, updated_by, } => DieselPaymentAttemptUpdate::Update { - amount, + amount: amount.get_amount_as_i64(), currency, status, authentication_type, @@ -1389,10 +1420,12 @@ impl DataModelExt for PaymentAttemptUpdate { payment_method_type, payment_experience, business_sub_label, - amount_to_capture, + amount_to_capture: amount_to_capture + .map(|capture_amt| capture_amt.get_amount_as_i64()), capture_method, - surcharge_amount, - tax_amount, + surcharge_amount: surcharge_amount + .map(|surcharge_amt| surcharge_amt.get_amount_as_i64()), + tax_amount: tax_amount.map(|tax_amt| tax_amt.get_amount_as_i64()), fingerprint_id, updated_by, }, @@ -1409,9 +1442,11 @@ impl DataModelExt for PaymentAttemptUpdate { payment_token, connector, straight_through_algorithm, - amount_capturable, - surcharge_amount, - tax_amount, + amount_capturable: amount_capturable + .map(|amount_capturable| amount_capturable.get_amount_as_i64()), + surcharge_amount: surcharge_amount + .map(|surcharge_amt| surcharge_amt.get_amount_as_i64()), + tax_amount: tax_amount.map(|tax_amt| tax_amt.get_amount_as_i64()), updated_by, merchant_connector_id, }, @@ -1469,7 +1504,7 @@ impl DataModelExt for PaymentAttemptUpdate { authentication_id, payment_method_billing_address_id, } => DieselPaymentAttemptUpdate::ConfirmUpdate { - amount, + amount: amount.get_amount_as_i64(), currency, status, authentication_type, @@ -1485,9 +1520,11 @@ impl DataModelExt for PaymentAttemptUpdate { straight_through_algorithm, error_code, error_message, - amount_capturable, - surcharge_amount, - tax_amount, + amount_capturable: amount_capturable + .map(|capture_amt| capture_amt.get_amount_as_i64()), + surcharge_amount: surcharge_amount + .map(|surcharge_amt| surcharge_amt.get_amount_as_i64()), + tax_amount: tax_amount.map(|tax_amt| tax_amt.get_amount_as_i64()), fingerprint_id, updated_by, merchant_connector_id: connector_id, @@ -1539,7 +1576,8 @@ impl DataModelExt for PaymentAttemptUpdate { error_message, error_reason, connector_response_reference_id, - amount_capturable, + amount_capturable: amount_capturable + .map(|capture_amt| capture_amt.get_amount_as_i64()), updated_by, authentication_data, encoded_data, @@ -1589,7 +1627,8 @@ impl DataModelExt for PaymentAttemptUpdate { error_code, error_message, error_reason, - amount_capturable, + amount_capturable: amount_capturable + .map(|capture_amt| capture_amt.get_amount_as_i64()), updated_by, unified_code, unified_message, @@ -1603,7 +1642,8 @@ impl DataModelExt for PaymentAttemptUpdate { } => DieselPaymentAttemptUpdate::CaptureUpdate { multiple_capture_count, updated_by, - amount_to_capture, + amount_to_capture: amount_to_capture + .map(|capture_amt| capture_amt.get_amount_as_i64()), }, Self::PreprocessingUpdate { status, @@ -1639,7 +1679,7 @@ impl DataModelExt for PaymentAttemptUpdate { updated_by, } => DieselPaymentAttemptUpdate::AmountToCaptureUpdate { status, - amount_capturable, + amount_capturable: amount_capturable.get_amount_as_i64(), updated_by, }, Self::ConnectorResponse { @@ -1659,8 +1699,8 @@ impl DataModelExt for PaymentAttemptUpdate { amount, amount_capturable, } => DieselPaymentAttemptUpdate::IncrementalAuthorizationAmountUpdate { - amount, - amount_capturable, + amount: amount.get_amount_as_i64(), + amount_capturable: amount_capturable.get_amount_as_i64(), }, Self::AuthenticationUpdate { status, @@ -1698,7 +1738,7 @@ impl DataModelExt for PaymentAttemptUpdate { fingerprint_id, updated_by, } => Self::Update { - amount, + amount: MinorUnit::new(amount), currency, status, authentication_type, @@ -1708,10 +1748,11 @@ impl DataModelExt for PaymentAttemptUpdate { payment_method_type, payment_experience, business_sub_label, - amount_to_capture, + amount_to_capture: amount_to_capture.map(|capture_amt| MinorUnit::new(capture_amt)), capture_method, - surcharge_amount, - tax_amount, + surcharge_amount: surcharge_amount + .map(|surcharge_amt| MinorUnit::new(surcharge_amt)), + tax_amount: tax_amount.map(|tax_amt| MinorUnit::new(tax_amt)), fingerprint_id, updated_by, }, @@ -1728,9 +1769,10 @@ impl DataModelExt for PaymentAttemptUpdate { payment_token, connector, straight_through_algorithm, - amount_capturable, - surcharge_amount, - tax_amount, + amount_capturable: amount_capturable.map(|capture_amt| MinorUnit::new(capture_amt)), + surcharge_amount: surcharge_amount + .map(|surcharge_amt| MinorUnit::new(surcharge_amt)), + tax_amount: tax_amount.map(|tax_amt| MinorUnit::new(tax_amt)), updated_by, merchant_connector_id: connector_id, }, @@ -1770,7 +1812,7 @@ impl DataModelExt for PaymentAttemptUpdate { authentication_id, payment_method_billing_address_id, } => Self::ConfirmUpdate { - amount, + amount: MinorUnit::new(amount), currency, status, authentication_type, @@ -1786,9 +1828,10 @@ impl DataModelExt for PaymentAttemptUpdate { straight_through_algorithm, error_code, error_message, - amount_capturable, - surcharge_amount, - tax_amount, + amount_capturable: amount_capturable.map(|capture_amt| MinorUnit::new(capture_amt)), + surcharge_amount: surcharge_amount + .map(|surcharge_amt| MinorUnit::new(surcharge_amt)), + tax_amount: tax_amount.map(|tax_amt| MinorUnit::new(tax_amt)), fingerprint_id, updated_by, merchant_connector_id: connector_id, @@ -1858,7 +1901,7 @@ impl DataModelExt for PaymentAttemptUpdate { error_message, error_reason, connector_response_reference_id, - amount_capturable, + amount_capturable: amount_capturable.map(|capture_amt| MinorUnit::new(capture_amt)), updated_by, authentication_data, encoded_data, @@ -1908,7 +1951,7 @@ impl DataModelExt for PaymentAttemptUpdate { error_code, error_message, error_reason, - amount_capturable, + amount_capturable: amount_capturable.map(|capture_amt| MinorUnit::new(capture_amt)), updated_by, unified_code, unified_message, @@ -1920,7 +1963,7 @@ impl DataModelExt for PaymentAttemptUpdate { multiple_capture_count, updated_by, } => Self::CaptureUpdate { - amount_to_capture, + amount_to_capture: amount_to_capture.map(|capture_amt| MinorUnit::new(capture_amt)), multiple_capture_count, updated_by, }, @@ -1958,7 +2001,7 @@ impl DataModelExt for PaymentAttemptUpdate { updated_by, } => Self::AmountToCaptureUpdate { status, - amount_capturable, + amount_capturable: MinorUnit::new(amount_capturable), updated_by, }, DieselPaymentAttemptUpdate::ConnectorResponse { @@ -1978,8 +2021,8 @@ impl DataModelExt for PaymentAttemptUpdate { amount, amount_capturable, } => Self::IncrementalAuthorizationAmountUpdate { - amount, - amount_capturable, + amount: MinorUnit::new(amount), + amount_capturable: MinorUnit::new(amount_capturable), }, DieselPaymentAttemptUpdate::AuthenticationUpdate { status, diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index fcc4ec63ff2..e418847b163 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -1,5 +1,6 @@ #[cfg(feature = "olap")] use api_models::payments::AmountFilter; +use api_models::payments::MinorUnit; #[cfg(feature = "olap")] use async_bb8_diesel::{AsyncConnection, AsyncRunQueryDsl}; #[cfg(feature = "olap")] @@ -801,9 +802,9 @@ impl DataModelExt for PaymentIntentNew { payment_id: self.payment_id, merchant_id: self.merchant_id, status: self.status, - amount: self.amount, + amount: self.amount.get_amount_as_i64(), currency: self.currency, - amount_captured: self.amount_captured, + amount_captured: MinorUnit::get_optional_amount_as_i64(self.amount_captured), customer_id: self.customer_id, description: self.description, return_url: self.return_url, @@ -847,9 +848,9 @@ impl DataModelExt for PaymentIntentNew { payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, status: storage_model.status, - amount: storage_model.amount, + amount: MinorUnit::new(storage_model.amount), currency: storage_model.currency, - amount_captured: storage_model.amount_captured, + amount_captured: MinorUnit::new_from_optional_i64_amount(storage_model.amount_captured), customer_id: storage_model.customer_id, description: storage_model.description, return_url: storage_model.return_url, @@ -899,9 +900,11 @@ impl DataModelExt for PaymentIntent { payment_id: self.payment_id, merchant_id: self.merchant_id, status: self.status, - amount: self.amount, + amount: self.amount.get_amount_as_i64(), currency: self.currency, - amount_captured: self.amount_captured, + amount_captured: self + .amount_captured + .map(|capture_amt| capture_amt.get_amount_as_i64()), customer_id: self.customer_id, description: self.description, return_url: self.return_url, @@ -946,9 +949,11 @@ impl DataModelExt for PaymentIntent { payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, status: storage_model.status, - amount: storage_model.amount, + amount: MinorUnit::new(storage_model.amount), currency: storage_model.currency, - amount_captured: storage_model.amount_captured, + amount_captured: storage_model + .amount_captured + .map(|capture_amt| MinorUnit::new(capture_amt)), customer_id: storage_model.customer_id, description: storage_model.description, return_url: storage_model.return_url, @@ -1003,7 +1008,7 @@ impl DataModelExt for PaymentIntentUpdate { incremental_authorization_allowed, } => DieselPaymentIntentUpdate::ResponseUpdate { status, - amount_captured, + amount_captured: MinorUnit::get_optional_amount_as_i64(amount_captured), fingerprint_id, return_url, updated_by, @@ -1073,7 +1078,7 @@ impl DataModelExt for PaymentIntentUpdate { session_expiry, request_external_three_ds_authentication, } => DieselPaymentIntentUpdate::Update { - amount, + amount: amount.get_amount_as_i64(), currency, setup_future_usage, status, @@ -1140,7 +1145,9 @@ impl DataModelExt for PaymentIntentUpdate { updated_by, }, Self::IncrementalAuthorizationAmountUpdate { amount } => { - DieselPaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { amount } + DieselPaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { + amount: amount.get_amount_as_i64(), + } } Self::AuthorizationCountUpdate { authorization_count, From a1bb647e907987f5735a5e90986788e24425a909 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 11:22:10 +0000 Subject: [PATCH 02/82] chore: run formatter --- .../payments/operations/payment_response.rs | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index f1ba7100874..e1b3ba0bdb0 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -256,16 +256,15 @@ 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: MinorUnit::new( @@ -284,13 +283,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 { payment_data.payment_attempt = db From f6c49462048015350488a88300bce196d1b4aac2 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 13 May 2024 17:43:01 +0530 Subject: [PATCH 03/82] refactor(router): fixed clippy issue --- crates/api_models/src/payments.rs | 28 ++++----- crates/router/src/core/payments/helpers.rs | 8 +-- .../payments/operations/payment_response.rs | 31 +++++----- .../payments/operations/payment_update.rs | 4 +- crates/router/src/types/api/payments.rs | 2 +- crates/router/tests/payments.rs | 12 ++-- crates/router/tests/payments2.rs | 12 ++-- .../src/payments/payment_attempt.rs | 59 +++++++------------ .../src/payments/payment_intent.rs | 4 +- 9 files changed, 69 insertions(+), 91 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 6efca674287..a03dfe5980c 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -699,12 +699,12 @@ impl MinorUnit { self.0 } - pub fn add(&self, a2: MinorUnit) -> Self { - MinorUnit::new(self.get_amount_as_i64() + a2.get_amount_as_i64()) + pub fn add(&self, a2: Self) -> Self { + Self::new(self.get_amount_as_i64() + a2.get_amount_as_i64()) } - pub fn substract(&self, a2: MinorUnit) -> Self { - MinorUnit::new(self.get_amount_as_i64() - a2.get_amount_as_i64()) + pub fn substract(&self, a2: Self) -> Self { + Self::new(self.get_amount_as_i64() - a2.get_amount_as_i64()) } pub fn get_optional_amount_as_i64(optional_amount: Option) -> Option { @@ -712,25 +712,25 @@ impl MinorUnit { } pub fn new(value: i64) -> Self { - MinorUnit(value) + Self(value) } pub fn optional_new_from_i64_amount(value: i64) -> Option { - Some(MinorUnit(value)) + Some(Self(value)) } pub fn new_from_optional_i64_amount(value: Option) -> Option { - value.map(|amount| MinorUnit(amount)) + value.map(Self) } - pub fn is_equal(&self, a2: MinorUnit) -> bool { + pub fn is_equal(&self, a2: Self) -> bool { self.get_amount_as_i64() == a2.get_amount_as_i64() } - pub fn is_not_equal(&self, a2: MinorUnit) -> bool { + pub fn is_not_equal(&self, a2: Self) -> bool { !self.is_equal(a2) } - pub fn is_greater_than(&self, a2: MinorUnit) -> bool { + pub fn is_greater_than(&self, a2: Self) -> bool { self.get_amount_as_i64() > a2.get_amount_as_i64() } } @@ -745,8 +745,8 @@ pub enum Amount { impl From for MinorUnit { fn from(amount: Amount) -> Self { match amount { - Amount::Value(val) => MinorUnit::new(val.get()), - Amount::Zero => MinorUnit::new(0), + Amount::Value(val) => Self::new(val.get()), + Amount::Zero => Self::new(0), } } } @@ -760,8 +760,8 @@ impl fmt::Display for MinorUnit { impl From for Amount { fn from(minor_unit: MinorUnit) -> Self { match minor_unit.0 { - 0 => Amount::Zero, - val => NonZeroI64::new(val).map_or(Self::Zero, Amount::Value), + 0 => Self::Zero, + val => NonZeroI64::new(val).map_or(Self::Zero, Self::Value), } } } diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index b5e4f38163d..7c5b5b3114d 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -769,7 +769,7 @@ pub fn validate_amount_to_capture_and_capture_method( if capture_method == api_enums::CaptureMethod::Automatic { let original_amount = request .amount - .map(|amount| api_models::payments::MinorUnit::from(amount)) + .map(MinorUnit::from) .or(payment_attempt.map(|payment_attempt| payment_attempt.amount)); let surcharge_amount = request .surcharge_details @@ -2915,7 +2915,7 @@ mod tests { payment_id: "23".to_string(), merchant_id: "22".to_string(), status: storage_enums::IntentStatus::RequiresCapture, - amount: 200, + amount: MinorUnit::new(200), currency: None, amount_captured: None, customer_id: None, @@ -2973,7 +2973,7 @@ mod tests { payment_id: "23".to_string(), merchant_id: "22".to_string(), status: storage_enums::IntentStatus::RequiresCapture, - amount: 200, + amount: MinorUnit::new(200), currency: None, amount_captured: None, customer_id: None, @@ -3030,7 +3030,7 @@ mod tests { payment_id: "23".to_string(), merchant_id: "22".to_string(), status: storage_enums::IntentStatus::RequiresCapture, - amount: 200, + amount: MinorUnit::new(200), currency: None, amount_captured: None, customer_id: None, diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index f1ba7100874..e1b3ba0bdb0 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -256,16 +256,15 @@ 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: MinorUnit::new( @@ -284,13 +283,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 { payment_data.payment_attempt = db diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 5b50fe11a7d..f5afcad81ed 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -343,11 +343,11 @@ impl .as_ref() .map(RequestSurchargeDetails::get_total_surcharge_amount) .or(payment_attempt.get_total_surcharge_amount()); - MinorUnit::from(amount.add(surcharge_amount.unwrap_or_default())) + amount.add(surcharge_amount.unwrap_or_default()) }; (Box::new(operations::PaymentConfirm), amount.into()) } else { - (Box::new(self), amount.into()) + (Box::new(self), amount) }; payment_intent.status = match request.payment_method_data.as_ref() { diff --git a/crates/router/src/types/api/payments.rs b/crates/router/src/types/api/payments.rs index e36c68c27d5..182f895a1b1 100644 --- a/crates/router/src/types/api/payments.rs +++ b/crates/router/src/types/api/payments.rs @@ -259,7 +259,7 @@ mod payments_test { #[allow(dead_code)] fn payments_request() -> PaymentsRequest { PaymentsRequest { - amount: Some(Amount::from(200)), + amount: Some(Amount::from(api_models::payments::MinorUnit::new(200))), payment_method_data: Some(PaymentMethodDataRequest { payment_method_data: Some(PaymentMethodData::Card(card())), billing: None, diff --git a/crates/router/tests/payments.rs b/crates/router/tests/payments.rs index 646a11d4cdd..2b2472643e0 100644 --- a/crates/router/tests/payments.rs +++ b/crates/router/tests/payments.rs @@ -303,10 +303,10 @@ async fn payments_create_core() { "pay_mbabizu24mvu3mela5njyhpit10".to_string(), )), merchant_id: Some("jarnura".to_string()), - amount: Some(6540.into()), + amount: Some(api_models::payments::MinorUnit::new(6540).into()), currency: Some(api_enums::Currency::USD), capture_method: Some(api_enums::CaptureMethod::Automatic), - amount_to_capture: Some(6540), + amount_to_capture: Some(api_models::payments::MinorUnit::new(6540)), capture_on: Some(datetime!(2022-09-10 11:12)), confirm: Some(true), customer_id: None, @@ -351,7 +351,7 @@ async fn payments_create_core() { let expected_response = api::PaymentsResponse { payment_id: Some("pay_mbabizu24mvu3mela5njyhpit10".to_string()), status: api_enums::IntentStatus::Succeeded, - amount: 6540, + amount: api_models::payments::MinorUnit::new(6540), amount_capturable: None, amount_received: None, client_secret: None, @@ -487,10 +487,10 @@ async fn payments_create_core_adyen_no_redirect() { let req = api::PaymentsRequest { payment_id: Some(api::PaymentIdType::PaymentIntentId(payment_id.clone())), merchant_id: Some(merchant_id.clone()), - amount: Some(6540.into()), + amount: Some(api_models::payments::MinorUnit::new(6540).into()), currency: Some(api_enums::Currency::USD), capture_method: Some(api_enums::CaptureMethod::Automatic), - amount_to_capture: Some(6540), + amount_to_capture: Some(api_models::payments::MinorUnit::new(6540)), capture_on: Some(datetime!(2022-09-10 10:11:12)), confirm: Some(true), customer_id: Some(customer_id), @@ -534,7 +534,7 @@ async fn payments_create_core_adyen_no_redirect() { api::PaymentsResponse { payment_id: Some(payment_id.clone()), status: api_enums::IntentStatus::Processing, - amount: 6540, + amount: api_models::payments::MinorUnit::new(6540), amount_capturable: None, amount_received: None, client_secret: None, diff --git a/crates/router/tests/payments2.rs b/crates/router/tests/payments2.rs index 9b622d11fd1..ea1d69c8d96 100644 --- a/crates/router/tests/payments2.rs +++ b/crates/router/tests/payments2.rs @@ -63,10 +63,10 @@ async fn payments_create_core() { "pay_mbabizu24mvu3mela5njyhpit10".to_string(), )), merchant_id: Some("jarnura".to_string()), - amount: Some(6540.into()), + amount: Some(api_models::payments::MinorUnit::new(6540).into()), currency: Some(api_enums::Currency::USD), capture_method: Some(api_enums::CaptureMethod::Automatic), - amount_to_capture: Some(6540), + amount_to_capture: Some(api_models::payments::MinorUnit::new(6540)), capture_on: Some(datetime!(2022-09-10 10:11:12)), confirm: Some(true), customer_id: None, @@ -111,7 +111,7 @@ async fn payments_create_core() { let expected_response = api::PaymentsResponse { payment_id: Some("pay_mbabizu24mvu3mela5njyhpit10".to_string()), status: api_enums::IntentStatus::Succeeded, - amount: 6540, + amount: api_models::payments::MinorUnit::new(6540), amount_capturable: None, amount_received: None, client_secret: None, @@ -254,10 +254,10 @@ async fn payments_create_core_adyen_no_redirect() { let req = api::PaymentsRequest { payment_id: Some(api::PaymentIdType::PaymentIntentId(payment_id.clone())), merchant_id: Some(merchant_id.clone()), - amount: Some(6540.into()), + amount: Some(api_models::payments::MinorUnit::new(6540).into()), currency: Some(api_enums::Currency::USD), capture_method: Some(api_enums::CaptureMethod::Automatic), - amount_to_capture: Some(6540), + amount_to_capture: Some(api_models::payments::MinorUnit::new(6540)), capture_on: Some(datetime!(2022-09-10 10:11:12)), confirm: Some(true), customer_id: Some(customer_id), @@ -302,7 +302,7 @@ async fn payments_create_core_adyen_no_redirect() { api::PaymentsResponse { payment_id: Some(payment_id.clone()), status: api_enums::IntentStatus::Processing, - amount: 6540, + amount: api_models::payments::MinorUnit::new(6540), amount_capturable: None, amount_received: None, client_secret: None, diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index 3f01efa10b0..dc18766872d 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -1189,15 +1189,9 @@ impl DataModelExt for PaymentAttempt { save_to_locker: storage_model.save_to_locker, connector: storage_model.connector, error_message: storage_model.error_message, - offer_amount: storage_model - .offer_amount - .map(|offer_amount| MinorUnit::new(offer_amount)), - surcharge_amount: storage_model - .surcharge_amount - .map(|surcharge_amount| MinorUnit::new(surcharge_amount)), - tax_amount: storage_model - .tax_amount - .map(|tax_amt| MinorUnit::new(tax_amt)), + offer_amount: storage_model.offer_amount.map(MinorUnit::new), + surcharge_amount: storage_model.surcharge_amount.map(MinorUnit::new), + tax_amount: storage_model.tax_amount.map(MinorUnit::new), payment_method_id: storage_model.payment_method_id, payment_method: storage_model.payment_method, connector_transaction_id: storage_model.connector_transaction_id, @@ -1209,9 +1203,7 @@ impl DataModelExt for PaymentAttempt { modified_at: storage_model.modified_at, last_synced: storage_model.last_synced, cancellation_reason: storage_model.cancellation_reason, - amount_to_capture: storage_model - .amount_to_capture - .map(|capture_amt| MinorUnit::new(capture_amt)), + amount_to_capture: storage_model.amount_to_capture.map(MinorUnit::new), mandate_id: storage_model.mandate_id, browser_info: storage_model.browser_info, error_code: storage_model.error_code, @@ -1328,15 +1320,9 @@ impl DataModelExt for PaymentAttemptNew { save_to_locker: storage_model.save_to_locker, connector: storage_model.connector, error_message: storage_model.error_message, - offer_amount: storage_model - .offer_amount - .map(|offer_amount| MinorUnit::new(offer_amount)), - surcharge_amount: storage_model - .surcharge_amount - .map(|surcharge_amount| MinorUnit::new(surcharge_amount)), - tax_amount: storage_model - .tax_amount - .map(|tax_amount| MinorUnit::new(tax_amount)), + offer_amount: storage_model.offer_amount.map(MinorUnit::new), + surcharge_amount: storage_model.surcharge_amount.map(MinorUnit::new), + tax_amount: storage_model.tax_amount.map(MinorUnit::new), payment_method_id: storage_model.payment_method_id, payment_method: storage_model.payment_method, capture_method: storage_model.capture_method, @@ -1347,9 +1333,7 @@ impl DataModelExt for PaymentAttemptNew { modified_at: storage_model.modified_at, last_synced: storage_model.last_synced, cancellation_reason: storage_model.cancellation_reason, - amount_to_capture: storage_model - .amount_to_capture - .map(|amount_to_capture| MinorUnit::new(amount_to_capture)), + amount_to_capture: storage_model.amount_to_capture.map(MinorUnit::new), mandate_id: storage_model.mandate_id, browser_info: storage_model.browser_info, payment_token: storage_model.payment_token, @@ -1748,11 +1732,10 @@ impl DataModelExt for PaymentAttemptUpdate { payment_method_type, payment_experience, business_sub_label, - amount_to_capture: amount_to_capture.map(|capture_amt| MinorUnit::new(capture_amt)), + amount_to_capture: amount_to_capture.map(MinorUnit::new), capture_method, - surcharge_amount: surcharge_amount - .map(|surcharge_amt| MinorUnit::new(surcharge_amt)), - tax_amount: tax_amount.map(|tax_amt| MinorUnit::new(tax_amt)), + surcharge_amount: surcharge_amount.map(MinorUnit::new), + tax_amount: tax_amount.map(MinorUnit::new), fingerprint_id, updated_by, }, @@ -1769,10 +1752,9 @@ impl DataModelExt for PaymentAttemptUpdate { payment_token, connector, straight_through_algorithm, - amount_capturable: amount_capturable.map(|capture_amt| MinorUnit::new(capture_amt)), - surcharge_amount: surcharge_amount - .map(|surcharge_amt| MinorUnit::new(surcharge_amt)), - tax_amount: tax_amount.map(|tax_amt| MinorUnit::new(tax_amt)), + amount_capturable: amount_capturable.map(MinorUnit::new), + surcharge_amount: surcharge_amount.map(MinorUnit::new), + tax_amount: tax_amount.map(MinorUnit::new), updated_by, merchant_connector_id: connector_id, }, @@ -1828,10 +1810,9 @@ impl DataModelExt for PaymentAttemptUpdate { straight_through_algorithm, error_code, error_message, - amount_capturable: amount_capturable.map(|capture_amt| MinorUnit::new(capture_amt)), - surcharge_amount: surcharge_amount - .map(|surcharge_amt| MinorUnit::new(surcharge_amt)), - tax_amount: tax_amount.map(|tax_amt| MinorUnit::new(tax_amt)), + amount_capturable: amount_capturable.map(MinorUnit::new), + surcharge_amount: surcharge_amount.map(MinorUnit::new), + tax_amount: tax_amount.map(MinorUnit::new), fingerprint_id, updated_by, merchant_connector_id: connector_id, @@ -1901,7 +1882,7 @@ impl DataModelExt for PaymentAttemptUpdate { error_message, error_reason, connector_response_reference_id, - amount_capturable: amount_capturable.map(|capture_amt| MinorUnit::new(capture_amt)), + amount_capturable: amount_capturable.map(MinorUnit::new), updated_by, authentication_data, encoded_data, @@ -1951,7 +1932,7 @@ impl DataModelExt for PaymentAttemptUpdate { error_code, error_message, error_reason, - amount_capturable: amount_capturable.map(|capture_amt| MinorUnit::new(capture_amt)), + amount_capturable: amount_capturable.map(MinorUnit::new), updated_by, unified_code, unified_message, @@ -1963,7 +1944,7 @@ impl DataModelExt for PaymentAttemptUpdate { multiple_capture_count, updated_by, } => Self::CaptureUpdate { - amount_to_capture: amount_to_capture.map(|capture_amt| MinorUnit::new(capture_amt)), + amount_to_capture: amount_to_capture.map(MinorUnit::new), multiple_capture_count, updated_by, }, diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index e418847b163..d64bf787f93 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -951,9 +951,7 @@ impl DataModelExt for PaymentIntent { status: storage_model.status, amount: MinorUnit::new(storage_model.amount), currency: storage_model.currency, - amount_captured: storage_model - .amount_captured - .map(|capture_amt| MinorUnit::new(capture_amt)), + amount_captured: storage_model.amount_captured.map(MinorUnit::new), customer_id: storage_model.customer_id, description: storage_model.description, return_url: storage_model.return_url, From 61850dc3266a423b2be80747497152107df3c70f Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 13 May 2024 17:48:14 +0530 Subject: [PATCH 04/82] refactor(router): fixed openapi specs --- openapi/openapi_spec.json | 108 ++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 58 deletions(-) diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 586fd1c1115..e15b1cc84fe 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -6818,9 +6818,7 @@ "$ref": "#/components/schemas/CaptureStatus" }, "amount": { - "type": "integer", - "format": "int64", - "description": "The capture amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc.," + "$ref": "#/components/schemas/MinorUnit" }, "currency": { "allOf": [ @@ -9820,9 +9818,7 @@ "description": "The unique identifier of authorization" }, "amount": { - "type": "integer", - "format": "int64", - "description": "Amount the authorization has been made for" + "$ref": "#/components/schemas/MinorUnit" }, "status": { "$ref": "#/components/schemas/AuthorizationStatus" @@ -9974,10 +9970,7 @@ ], "properties": { "amount": { - "type": "integer", - "format": "int64", - "description": "The maximum amount to be debited for the mandate transaction", - "example": 6540 + "$ref": "#/components/schemas/MinorUnit" }, "currency": { "$ref": "#/components/schemas/Currency" @@ -12103,9 +12096,7 @@ "$ref": "#/components/schemas/AttemptStatus" }, "amount": { - "type": "integer", - "format": "int64", - "description": "The payment attempt amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc.," + "$ref": "#/components/schemas/MinorUnit" }, "currency": { "allOf": [ @@ -13262,9 +13253,11 @@ "nullable": true }, "amount_to_capture": { - "type": "integer", - "format": "int64", - "description": "The Amount to be captured/ debited from the user's payment method.", + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], "nullable": true }, "refund_uncaptured_amount": { @@ -13312,10 +13305,11 @@ "nullable": true }, "amount_to_capture": { - "type": "integer", - "format": "int64", - "description": "The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount.", - "example": 6540, + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], "nullable": true }, "payment_id": { @@ -13691,10 +13685,11 @@ "$ref": "#/components/schemas/Currency" }, "amount_to_capture": { - "type": "integer", - "format": "int64", - "description": "The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount.", - "example": 6540, + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], "nullable": true }, "payment_id": { @@ -14182,10 +14177,11 @@ "nullable": true }, "amount_to_capture": { - "type": "integer", - "format": "int64", - "description": "The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount.", - "example": 6540, + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], "nullable": true }, "payment_id": { @@ -14612,32 +14608,26 @@ "default": "requires_confirmation" }, "amount": { - "type": "integer", - "format": "int64", - "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 + "$ref": "#/components/schemas/MinorUnit" }, "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 + "$ref": "#/components/schemas/MinorUnit" }, "amount_capturable": { - "type": "integer", - "format": "int64", - "description": "The maximum amount that could be captured from the payment", - "example": 6540, - "nullable": true, - "minimum": 100 + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true }, "amount_received": { - "type": "integer", - "format": "int64", - "description": "The amount which is already captured from the payment", - "example": 6540, - "nullable": true, - "minimum": 100 + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true }, "connector": { "type": "string", @@ -15251,10 +15241,11 @@ "nullable": true }, "amount_to_capture": { - "type": "integer", - "format": "int64", - "description": "The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount.", - "example": 6540, + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], "nullable": true }, "payment_id": { @@ -17034,12 +17025,14 @@ ], "properties": { "surcharge_amount": { - "type": "integer", - "format": "int64" + "$ref": "#/components/schemas/MinorUnit" }, "tax_amount": { - "type": "integer", - "format": "int64", + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], "nullable": true } } @@ -17153,8 +17146,7 @@ "type": "string" }, "amount": { - "type": "integer", - "format": "int64" + "$ref": "#/components/schemas/MinorUnit" }, "created_at": { "type": "string", From 6103485ef9670e01cab4796c9b8979582b26d66c Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 13 May 2024 18:09:44 +0530 Subject: [PATCH 05/82] refactor(router): fixed capture amount unequal bug --- crates/api_models/src/payments.rs | 2 +- crates/router/src/core/payments/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index a03dfe5980c..d381828ffe4 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -223,7 +223,7 @@ pub struct PaymentsRequest { pub currency: Option, /// The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount. - #[schema(example = 6540)] + #[schema(value_type = Option, example = 6540)] pub amount_to_capture: Option, /// Unique identifier for the payment. This ensures idempotency for multiple payments diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 7c5b5b3114d..63618080acd 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -794,7 +794,7 @@ pub fn validate_amount_to_capture_and_capture_method( total_capturable_amount.zip(amount_to_capture) { utils::when( - !amount_to_capture.is_not_equal(total_capturable_amount), + amount_to_capture.is_not_equal(total_capturable_amount), || { Err(report!(errors::ApiErrorResponse::PreconditionFailed { message: "amount_to_capture must be equal to total_capturable_amount when capture_method = automatic".into() From a9941324fbc89cc3002c1272d3e9d44c480bd8ff Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 13 May 2024 18:18:08 +0530 Subject: [PATCH 06/82] refactor(router): fixed open-api issue --- crates/api_models/src/payments.rs | 2 +- openapi/openapi_spec.json | 36 ++++++++++++++----------------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 7791970ae94..665f8c103aa 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -223,7 +223,7 @@ pub struct PaymentsRequest { pub currency: Option, /// The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount. - #[schema(value_type = Option, example = 6540)] + #[schema(value_type = Option, example = 6540)] pub amount_to_capture: Option, /// Unique identifier for the payment. This ensures idempotency for multiple payments diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index a9fa8c23a95..a5054cd2dcc 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -13371,11 +13371,10 @@ "nullable": true }, "amount_to_capture": { - "allOf": [ - { - "$ref": "#/components/schemas/MinorUnit" - } - ], + "type": "integer", + "format": "int64", + "description": "The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount.", + "example": 6540, "nullable": true }, "payment_id": { @@ -13751,11 +13750,10 @@ "$ref": "#/components/schemas/Currency" }, "amount_to_capture": { - "allOf": [ - { - "$ref": "#/components/schemas/MinorUnit" - } - ], + "type": "integer", + "format": "int64", + "description": "The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount.", + "example": 6540, "nullable": true }, "payment_id": { @@ -14243,11 +14241,10 @@ "nullable": true }, "amount_to_capture": { - "allOf": [ - { - "$ref": "#/components/schemas/MinorUnit" - } - ], + "type": "integer", + "format": "int64", + "description": "The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount.", + "example": 6540, "nullable": true }, "payment_id": { @@ -15307,11 +15304,10 @@ "nullable": true }, "amount_to_capture": { - "allOf": [ - { - "$ref": "#/components/schemas/MinorUnit" - } - ], + "type": "integer", + "format": "int64", + "description": "The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount.", + "example": 6540, "nullable": true }, "payment_id": { From 02a70482ff51f7b1e1e006eee18aa75408c4d595 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Tue, 14 May 2024 19:26:37 +0530 Subject: [PATCH 07/82] refactor(router): addressed pr comments --- crates/api_models/src/currency.rs | 4 +- crates/api_models/src/payment_methods.rs | 4 +- crates/api_models/src/payments.rs | 53 +------- crates/common_utils/src/types.rs | 113 +++++++++++++++++- crates/diesel_models/src/payment_intent.rs | 20 ++-- .../hyperswitch_domain_models/src/mandates.rs | 4 +- .../hyperswitch_domain_models/src/payments.rs | 3 +- .../src/payments/payment_attempt.rs | 3 +- .../src/payments/payment_intent.rs | 2 +- .../stripe/payment_intents/types.rs | 3 +- .../src/connector/adyen/transformers.rs | 2 +- .../src/connector/checkout/transformers.rs | 2 +- .../src/connector/cryptopay/transformers.rs | 2 +- .../src/connector/paypal/transformers.rs | 2 +- .../router/src/connector/payu/transformers.rs | 2 +- .../src/connector/square/transformers.rs | 2 +- .../src/connector/stripe/transformers.rs | 4 +- crates/router/src/connector/utils.rs | 3 +- crates/router/src/core/authentication.rs | 2 +- .../src/core/authentication/transformers.rs | 2 +- crates/router/src/core/fraud_check.rs | 2 +- .../surcharge_decision_configs.rs | 10 +- crates/router/src/core/payments/helpers.rs | 3 +- .../payments/operations/payment_create.rs | 12 +- .../payments/operations/payment_response.rs | 3 +- .../payments/operations/payment_update.rs | 9 +- crates/router/src/core/payments/retry.rs | 3 +- .../router/src/core/payments/transformers.rs | 6 +- crates/router/src/core/payments/types.rs | 28 ++--- crates/router/src/core/payouts.rs | 4 +- .../src/services/kafka/payment_attempt.rs | 2 +- .../src/services/kafka/payment_intent.rs | 2 +- crates/router/src/types.rs | 3 +- crates/router/src/types/api/payment_link.rs | 2 +- .../src/types/storage/payment_attempt.rs | 2 +- crates/router/src/types/transformers.rs | 3 +- crates/router/src/utils/user/sample_data.rs | 4 +- crates/router/src/workflows/payment_sync.rs | 2 +- .../src/payments/payment_attempt.rs | 7 +- .../src/payments/payment_intent.rs | 27 ++--- 40 files changed, 208 insertions(+), 158 deletions(-) diff --git a/crates/api_models/src/currency.rs b/crates/api_models/src/currency.rs index 32140e4c6d7..608e4c7a6bc 100644 --- a/crates/api_models/src/currency.rs +++ b/crates/api_models/src/currency.rs @@ -1,6 +1,4 @@ -use common_utils::events::ApiEventMetric; - -use crate::payments::MinorUnit; +use common_utils::{events::ApiEventMetric, types::MinorUnit}; /// QueryParams to be send to convert the amount -> from_currency -> to_currency #[derive(Debug, serde::Deserialize)] diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index c1c463d1279..591b5255999 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -5,7 +5,7 @@ use common_utils::{ consts::SURCHARGE_PERCENTAGE_PRECISION_LENGTH, crypto::OptionalEncryptableName, pii, - types::{Percentage, Surcharge}, + types::{MinorUnit, Percentage, Surcharge}, }; use serde::de; use utoipa::{schema, ToSchema}; @@ -14,7 +14,7 @@ use utoipa::{schema, ToSchema}; use crate::payouts; use crate::{ admin, enums as api_enums, - payments::{self, BankCodeResponse, MinorUnit}, + payments::{self, BankCodeResponse}, }; #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)] diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 665f8c103aa..055e4eb23da 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -10,6 +10,7 @@ use common_utils::{ crypto, ext_traits::{ConfigExt, Encode}, pii::{self, Email}, + types::MinorUnit, }; use masking::{PeekInterface, Secret}; use router_derive::Setter; @@ -691,50 +692,6 @@ impl PaymentsRequest { } } -#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)] -pub struct MinorUnit(i64); - -impl MinorUnit { - pub fn get_amount_as_i64(&self) -> i64 { - self.0 - } - - pub fn add(&self, a2: Self) -> Self { - Self::new(self.get_amount_as_i64() + a2.get_amount_as_i64()) - } - - pub fn substract(&self, a2: Self) -> Self { - Self::new(self.get_amount_as_i64() - a2.get_amount_as_i64()) - } - - pub fn get_optional_amount_as_i64(optional_amount: Option) -> Option { - optional_amount.map(|amount| amount.get_amount_as_i64()) - } - - pub fn new(value: i64) -> Self { - Self(value) - } - pub fn optional_new_from_i64_amount(value: i64) -> Option { - Some(Self(value)) - } - - pub fn new_from_optional_i64_amount(value: Option) -> Option { - value.map(Self) - } - - pub fn is_equal(&self, a2: Self) -> bool { - self.get_amount_as_i64() == a2.get_amount_as_i64() - } - - pub fn is_not_equal(&self, a2: Self) -> bool { - !self.is_equal(a2) - } - - pub fn is_greater_than(&self, a2: Self) -> bool { - self.get_amount_as_i64() > a2.get_amount_as_i64() - } -} - #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)] pub enum Amount { Value(NonZeroI64), @@ -751,15 +708,9 @@ impl From for MinorUnit { } } -impl fmt::Display for MinorUnit { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - impl From for Amount { fn from(minor_unit: MinorUnit) -> Self { - match minor_unit.0 { + match minor_unit.get_amount_as_i64() { 0 => Self::Zero, val => NonZeroI64::new(val).map_or(Self::Zero, Self::Value), } diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index b15a519caad..96f57eb150e 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -1,12 +1,14 @@ //! Types that can be used in other crates -use std::{fmt::Display, str::FromStr}; +use std::{fmt::Display, primitive::i64, str::FromStr}; use diesel::{ backend::Backend, + deserialize, deserialize::FromSql, serialize::{Output, ToSql}, + sql_types, sql_types::Jsonb, - AsExpression, FromSqlRow, + AsExpression, FromSqlRow, Queryable, }; use error_stack::{report, ResultExt}; use semver::Version; @@ -212,3 +214,110 @@ where >::to_sql(&value, &mut out.reborrow()) } } + +/// This Unit struct represents MinorUnit in which core amount works +#[derive( + Default, Debug, serde::Deserialize, AsExpression, serde::Serialize, Clone, Copy, PartialEq, Eq, +)] +#[diesel(sql_type = diesel::sql_types::BigInt)] +pub struct MinorUnit(i64); //core + +impl MinorUnit { + /// gets amount as i64 value + pub fn get_amount_as_i64(&self) -> i64 { + // will be removed in future + self.0 + } + + /// checks if the amount is zero value + pub fn is_zero(&self) -> bool { + self.0 == 0 + } + + /// adds two minor unit amout + pub fn add(&self, a2: Self) -> Self { + Self::new(self.0 + a2.0) + } + + /// substract two minor unit amount + pub fn substract(&self, a2: Self) -> Self { + Self::new(self.0 - a2.0) + } + + /// gets optional amount from minor unit + pub fn get_optional_amount_as_i64(optional_amount: Option) -> Option { + // remove in future + optional_amount.map(|amount| amount.0) + } + + /// forms a new minor unit from amount + pub fn new(value: i64) -> Self { + // remove in future + Self(value) + } + + /// gets optional minor unit from amount + pub fn optional_new_from_i64_amount(value: i64) -> Option { + Some(Self(value)) + } + + /// forms a new optional minor unit from optional amount + pub fn new_from_optional_i64_amount(value: Option) -> Option { + // remove in future + value.map(Self) + } + + /// checks if both the values are equal + pub fn is_equal(&self, a2: Self) -> bool { + self.0 == a2.0 + } + + /// checks if both the values are not equal + pub fn is_not_equal(&self, a2: Self) -> bool { + !self.is_equal(a2) + } + + /// checks if one value is greater than the other + pub fn is_greater_than(&self, a2: Self) -> bool { + self.0 > a2.0 + } +} + +impl Display for MinorUnit { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl FromSql for MinorUnit +where + DB: Backend, + i64: FromSql, +{ + fn from_sql(value: DB::RawValue<'_>) -> deserialize::Result { + let val = i64::from_sql(value)?; + Ok(Self(val)) + } +} + +impl ToSql for MinorUnit +where + DB: Backend, + i64: ToSql, +{ + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result { + self.0.to_sql(out) + } +} + +impl Queryable for MinorUnit +where + DB: Backend, + Self: FromSql, +{ + type Row = Self; + + fn build(row: Self::Row) -> deserialize::Result { + Ok(row) + } +} diff --git a/crates/diesel_models/src/payment_intent.rs b/crates/diesel_models/src/payment_intent.rs index ee6e3960b73..2682890753b 100644 --- a/crates/diesel_models/src/payment_intent.rs +++ b/crates/diesel_models/src/payment_intent.rs @@ -1,5 +1,5 @@ use common_enums::RequestIncrementalAuthorization; -use common_utils::pii; +use common_utils::{pii, types::MinorUnit}; use diesel::{AsChangeset, Identifiable, Insertable, Queryable}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; @@ -13,9 +13,9 @@ pub struct PaymentIntent { pub payment_id: String, pub merchant_id: String, pub status: storage_enums::IntentStatus, - pub amount: i64, + pub amount: MinorUnit, pub currency: Option, - pub amount_captured: Option, + pub amount_captured: Option, pub customer_id: Option, pub description: Option, pub return_url: Option, @@ -68,9 +68,9 @@ pub struct PaymentIntentNew { pub payment_id: String, pub merchant_id: String, pub status: storage_enums::IntentStatus, - pub amount: i64, + pub amount: MinorUnit, pub currency: Option, - pub amount_captured: Option, + pub amount_captured: Option, pub customer_id: Option, pub description: Option, pub return_url: Option, @@ -117,7 +117,7 @@ pub struct PaymentIntentNew { pub enum PaymentIntentUpdate { ResponseUpdate { status: storage_enums::IntentStatus, - amount_captured: Option, + amount_captured: Option, fingerprint_id: Option, return_url: Option, updated_by: String, @@ -147,7 +147,7 @@ pub enum PaymentIntentUpdate { incremental_authorization_allowed: Option, }, Update { - amount: i64, + amount: MinorUnit, currency: storage_enums::Currency, setup_future_usage: Option, status: storage_enums::IntentStatus, @@ -194,7 +194,7 @@ pub enum PaymentIntentUpdate { updated_by: String, }, IncrementalAuthorizationAmountUpdate { - amount: i64, + amount: MinorUnit, }, AuthorizationCountUpdate { authorization_count: i32, @@ -204,10 +204,10 @@ pub enum PaymentIntentUpdate { #[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)] #[diesel(table_name = payment_intent)] pub struct PaymentIntentUpdateInternal { - pub amount: Option, + pub amount: Option, pub currency: Option, pub status: Option, - pub amount_captured: Option, + pub amount_captured: Option, pub customer_id: Option, pub return_url: Option, pub setup_future_usage: Option, diff --git a/crates/hyperswitch_domain_models/src/mandates.rs b/crates/hyperswitch_domain_models/src/mandates.rs index 46d8684d162..d9080d6dc91 100644 --- a/crates/hyperswitch_domain_models/src/mandates.rs +++ b/crates/hyperswitch_domain_models/src/mandates.rs @@ -1,10 +1,10 @@ use api_models::payments::{ AcceptanceType as ApiAcceptanceType, CustomerAcceptance as ApiCustomerAcceptance, MandateAmountData as ApiMandateAmountData, MandateData as ApiMandateData, MandateType, - MinorUnit, OnlineMandate as ApiOnlineMandate, + OnlineMandate as ApiOnlineMandate, }; use common_enums::Currency; -use common_utils::{date_time, errors::ParsingError, pii}; +use common_utils::{date_time, errors::ParsingError, pii, types::MinorUnit}; use error_stack::ResultExt; use masking::{PeekInterface, Secret}; use time::PrimitiveDateTime; diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs index 4788c957b77..cf37210ab3b 100644 --- a/crates/hyperswitch_domain_models/src/payments.rs +++ b/crates/hyperswitch_domain_models/src/payments.rs @@ -1,5 +1,4 @@ -use api_models::payments::MinorUnit; -use common_utils::pii; +use common_utils::{self, pii, types::MinorUnit}; use time::PrimitiveDateTime; pub mod payment_attempt; diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index c60a24ce7ba..feb9cfa7cb3 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -1,5 +1,6 @@ -use api_models::{enums::Connector, payments::MinorUnit}; +use api_models::enums::Connector; use common_enums as storage_enums; +use common_utils::types::MinorUnit; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs index b144271b76a..d40d60b5ae0 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -1,8 +1,8 @@ -use api_models::payments::MinorUnit; use common_enums as storage_enums; use common_utils::{ consts::{PAYMENTS_LIST_MAX_LIMIT_V1, PAYMENTS_LIST_MAX_LIMIT_V2}, pii, + types::MinorUnit, }; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; diff --git a/crates/router/src/compatibility/stripe/payment_intents/types.rs b/crates/router/src/compatibility/stripe/payment_intents/types.rs index 292d99483b6..7c0d649f7a2 100644 --- a/crates/router/src/compatibility/stripe/payment_intents/types.rs +++ b/crates/router/src/compatibility/stripe/payment_intents/types.rs @@ -1,11 +1,12 @@ use std::str::FromStr; -use api_models::{payments, payments::MinorUnit}; +use api_models::payments; use common_utils::{ crypto::Encryptable, date_time, ext_traits::StringExt, pii::{IpAddress, SecretSerdeValue, UpiVpaMaskingStrategy}, + types::MinorUnit, }; use error_stack::ResultExt; use serde::{Deserialize, Serialize}; diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index 394c9af0313..9e89a81a080 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -3926,7 +3926,7 @@ impl TryFrom> connector_response_reference_id: Some(item.response.reference), incremental_authorization_allowed: None, }), - amount_captured: Some(api_models::payments::MinorUnit::new(0)), + amount_captured: Some(common_utils::types::MinorUnit::new(0)), ..item.data }) } diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index 03841a9433b..7b5c1e1f489 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -910,7 +910,7 @@ impl TryFrom> incremental_authorization_allowed: None, }), status, - amount_captured: api_models::payments::MinorUnit::new_from_optional_i64_amount( + amount_captured: common_utils::types::MinorUnit::new_from_optional_i64_amount( amount_captured, ), ..item.data diff --git a/crates/router/src/connector/cryptopay/transformers.rs b/crates/router/src/connector/cryptopay/transformers.rs index 8293608282a..fdd9ede2986 100644 --- a/crates/router/src/connector/cryptopay/transformers.rs +++ b/crates/router/src/connector/cryptopay/transformers.rs @@ -204,7 +204,7 @@ impl Ok(Self { status, response, - amount_captured: api_models::payments::MinorUnit::new_from_optional_i64_amount( + amount_captured: common_utils::types::MinorUnit::new_from_optional_i64_amount( amount_captured, ), ..item.data diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index fee3f3afe46..f62542f1587 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -1795,7 +1795,7 @@ impl TryFrom> .or(Some(item.response.id)), incremental_authorization_allowed: None, }), - amount_captured: Some(api_models::payments::MinorUnit::new(amount_captured)), + amount_captured: Some(common_utils::types::MinorUnit::new(amount_captured)), ..item.data }) } diff --git a/crates/router/src/connector/payu/transformers.rs b/crates/router/src/connector/payu/transformers.rs index 3bc6303a77e..3e24b128f8b 100644 --- a/crates/router/src/connector/payu/transformers.rs +++ b/crates/router/src/connector/payu/transformers.rs @@ -485,7 +485,7 @@ impl .or(Some(order.order_id.clone())), incremental_authorization_allowed: None, }), - amount_captured: Some(api_models::payments::MinorUnit::new( + amount_captured: Some(common_utils::types::MinorUnit::new( order .total_amount .parse::() diff --git a/crates/router/src/connector/square/transformers.rs b/crates/router/src/connector/square/transformers.rs index d3535102ac1..fe62ff50b24 100644 --- a/crates/router/src/connector/square/transformers.rs +++ b/crates/router/src/connector/square/transformers.rs @@ -382,7 +382,7 @@ impl connector_response_reference_id: item.response.payment.reference_id, incremental_authorization_allowed: None, }), - amount_captured: api_models::payments::MinorUnit::new_from_optional_i64_amount( + amount_captured: common_utils::types::MinorUnit::new_from_optional_i64_amount( amount_captured, ), ..item.data diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 3b3e42a6074..2b4163239d4 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -2461,7 +2461,7 @@ impl // statement_descriptor_suffix: item.response.statement_descriptor_suffix.map(|x| x.as_str()), // three_ds_form, response, - amount_captured: api_models::payments::MinorUnit::new_from_optional_i64_amount( + amount_captured: common_utils::types::MinorUnit::new_from_optional_i64_amount( item.response.amount_received, ), connector_response: connector_response_data, @@ -2636,7 +2636,7 @@ impl Ok(Self { status: enums::AttemptStatus::from(item.response.status.to_owned()), response, - amount_captured: api_models::payments::MinorUnit::new_from_optional_i64_amount( + amount_captured: common_utils::types::MinorUnit::new_from_optional_i64_amount( item.response.amount_received, ), connector_response: connector_response_data, diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 6fefcc1174f..5e05c6e4890 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -4,13 +4,14 @@ use std::collections::{HashMap, HashSet}; use api_models::payouts::{self, PayoutVendorAccountDetails}; use api_models::{ enums::{CanadaStatesAbbreviation, UsStatesAbbreviation}, - payments::{self, MinorUnit, OrderDetailsWithAmount}, + payments::{self, OrderDetailsWithAmount}, }; use base64::Engine; use common_utils::{ date_time, errors::ReportSwitchExt, pii::{self, Email, IpAddress}, + types::MinorUnit, }; use diesel_models::enums; use error_stack::{report, ResultExt}; diff --git a/crates/router/src/core/authentication.rs b/crates/router/src/core/authentication.rs index f218ddecb9b..cbd312c94ed 100644 --- a/crates/router/src/core/authentication.rs +++ b/crates/router/src/core/authentication.rs @@ -28,7 +28,7 @@ pub async fn perform_authentication( browser_details: Option, business_profile: storage::BusinessProfile, merchant_connector_account: payments_core::helpers::MerchantConnectorAccountType, - amount: api_models::payments::MinorUnit, + amount: common_utils::types::MinorUnit, currency: Option, message_category: api::authentication::MessageCategory, device_channel: payments::DeviceChannel, diff --git a/crates/router/src/core/authentication/transformers.rs b/crates/router/src/core/authentication/transformers.rs index 222852f2a17..c005a8de3af 100644 --- a/crates/router/src/core/authentication/transformers.rs +++ b/crates/router/src/core/authentication/transformers.rs @@ -32,7 +32,7 @@ pub fn construct_authentication_router_data( billing_address: payments::Address, shipping_address: Option, browser_details: Option, - amount: api_models::payments::MinorUnit, + amount: common_utils::types::MinorUnit, currency: Option, message_category: types::api::authentication::MessageCategory, device_channel: payments::DeviceChannel, diff --git a/crates/router/src/core/fraud_check.rs b/crates/router/src/core/fraud_check.rs index 4a92026bab6..3bc6988deb4 100644 --- a/crates/router/src/core/fraud_check.rs +++ b/crates/router/src/core/fraud_check.rs @@ -706,7 +706,7 @@ pub fn is_operation_allowed(operation: &Op) -> bool { impl From for PaymentDetails { fn from(payment_data: PaymentToFrmData) -> Self { Self { - amount: api_models::payments::MinorUnit::from(payment_data.amount).get_amount_as_i64(), + amount: common_utils::types::MinorUnit::from(payment_data.amount).get_amount_as_i64(), currency: payment_data.payment_attempt.currency, payment_method: payment_data.payment_attempt.payment_method, payment_method_type: payment_data.payment_attempt.payment_method_type, diff --git a/crates/router/src/core/payment_methods/surcharge_decision_configs.rs b/crates/router/src/core/payment_methods/surcharge_decision_configs.rs index 9b9e501d474..aa01613a206 100644 --- a/crates/router/src/core/payment_methods/surcharge_decision_configs.rs +++ b/crates/router/src/core/payment_methods/surcharge_decision_configs.rs @@ -2,9 +2,7 @@ use std::sync::Arc; use api_models::{ payment_methods::SurchargeDetailsResponse, - payments, - payments::MinorUnit, - routing, + payments, routing, surcharge_decision_configs::{self, SurchargeDecisionConfigs, SurchargeDecisionManagerRecord}, }; use common_utils::{ext_traits::StringExt, static_cache::StaticCache, types as common_utils_types}; @@ -381,9 +379,9 @@ fn get_surcharge_details_from_surcharge_output( } }, tax_on_surcharge: surcharge_details.tax_on_surcharge, - surcharge_amount: MinorUnit::new(surcharge_amount), - tax_on_surcharge_amount: MinorUnit::new(tax_on_surcharge_amount), - final_amount: MinorUnit::new( + surcharge_amount: common_utils_types::MinorUnit::new(surcharge_amount), + tax_on_surcharge_amount: common_utils_types::MinorUnit::new(tax_on_surcharge_amount), + final_amount: common_utils_types::MinorUnit::new( payment_attempt.amount.get_amount_as_i64() + surcharge_amount + tax_on_surcharge_amount, ), }) diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index e0ffcdca40d..9e129ddfde2 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -2,12 +2,13 @@ use std::{borrow::Cow, str::FromStr}; use api_models::{ mandates::RecurringDetails, - payments::{CardToken, GetPaymentMethodType, MinorUnit, RequestSurchargeDetails}, + payments::{CardToken, GetPaymentMethodType, RequestSurchargeDetails}, }; use base64::Engine; use common_utils::{ ext_traits::{AsyncExt, ByteSliceExt, Encode, ValueExt}, fp_utils, generate_id, pii, + types::MinorUnit, }; use diesel_models::enums; // TODO : Evaluate all the helper functions () diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index 531f1f0c44d..d83ad611ab9 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -2,10 +2,12 @@ use std::marker::PhantomData; use api_models::{ enums::FrmSuggestion, mandates::RecurringDetails, payment_methods::PaymentMethodsData, - payments::MinorUnit, }; use async_trait::async_trait; -use common_utils::ext_traits::{AsyncExt, Encode, ValueExt}; +use common_utils::{ + ext_traits::{AsyncExt, Encode, ValueExt}, + types::MinorUnit, +}; use diesel_models::{ephemeral_key, PaymentMethod}; use error_stack::{self, ResultExt}; use hyperswitch_domain_models::{ @@ -889,7 +891,7 @@ impl PaymentCreate { attempt_id, status, currency, - amount: api_models::payments::MinorUnit::from(amount), + amount: common_utils::types::MinorUnit::from(amount), payment_method, capture_method: request.capture_method, capture_on: request.capture_on, @@ -1007,7 +1009,7 @@ impl PaymentCreate { payment_id: payment_id.to_string(), merchant_id: merchant_account.merchant_id.to_string(), status, - amount: api_models::payments::MinorUnit::from(amount), + amount: common_utils::types::MinorUnit::from(amount), currency, description: request.description.clone(), created_at, @@ -1119,7 +1121,7 @@ async fn create_payment_link( payment_id: payment_id.clone(), merchant_id: merchant_id.clone(), link_to_pay: payment_link.clone(), - amount: api_models::payments::MinorUnit::from(amount).get_amount_as_i64(), + amount: common_utils::types::MinorUnit::from(amount).get_amount_as_i64(), currency: request.currency, created_at, last_modified_at, diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 91c64d99a91..3e1e25a089f 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1,9 +1,8 @@ use std::collections::HashMap; -use api_models::payments::MinorUnit; use async_trait::async_trait; use common_enums::AuthorizationStatus; -use common_utils::ext_traits::Encode; +use common_utils::{ext_traits::Encode, types::MinorUnit}; use error_stack::{report, ResultExt}; use futures::FutureExt; use hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt; diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index c99eab5df6d..3fa5b6dff85 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -1,12 +1,13 @@ use std::marker::PhantomData; use api_models::{ - enums::FrmSuggestion, - mandates::RecurringDetails, - payments::{MinorUnit, RequestSurchargeDetails}, + enums::FrmSuggestion, mandates::RecurringDetails, payments::RequestSurchargeDetails, }; use async_trait::async_trait; -use common_utils::ext_traits::{AsyncExt, Encode, ValueExt}; +use common_utils::{ + ext_traits::{AsyncExt, Encode, ValueExt}, + types::MinorUnit, +}; use error_stack::{report, ResultExt}; use router_derive::PaymentOperation; use router_env::{instrument, tracing}; diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index 446490d66ba..5df7a08f370 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -1,7 +1,6 @@ use std::{str::FromStr, vec::IntoIter}; -use api_models::payments::MinorUnit; -use common_utils::ext_traits::Encode; +use common_utils::{ext_traits::Encode, types::MinorUnit}; use diesel_models::enums as storage_enums; use error_stack::{report, ResultExt}; use router_env::{ diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index bfbb5391290..271e1b869f4 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -1,12 +1,10 @@ use std::{fmt::Debug, marker::PhantomData, str::FromStr}; -use api_models::payments::{ - FrmMessage, GetAddressFromPaymentMethodData, MinorUnit, RequestSurchargeDetails, -}; +use api_models::payments::{FrmMessage, GetAddressFromPaymentMethodData, RequestSurchargeDetails}; #[cfg(feature = "payouts")] use api_models::payouts::PayoutAttemptResponse; use common_enums::RequestIncrementalAuthorization; -use common_utils::{consts::X_HS_LATENCY, fp_utils}; +use common_utils::{consts::X_HS_LATENCY, fp_utils, types::MinorUnit}; use diesel_models::ephemeral_key; use error_stack::{report, ResultExt}; use masking::Maskable; diff --git a/crates/router/src/core/payments/types.rs b/crates/router/src/core/payments/types.rs index 30d6b1ddce9..d15698b4b5c 100644 --- a/crates/router/src/core/payments/types.rs +++ b/crates/router/src/core/payments/types.rs @@ -1,9 +1,6 @@ use std::{collections::HashMap, num::TryFromIntError}; -use api_models::{ - payment_methods::SurchargeDetailsResponse, - payments::{MinorUnit, RequestSurchargeDetails}, -}; +use api_models::{payment_methods::SurchargeDetailsResponse, payments::RequestSurchargeDetails}; use common_utils::{ consts, errors::CustomResult, @@ -83,8 +80,8 @@ impl MultipleCaptureData { .and_modify(|capture| *capture = updated_capture.clone()); } } - pub fn get_total_blocked_amount(&self) -> MinorUnit { - MinorUnit::new(self.all_captures.iter().fold(0, |accumulator, capture| { + pub fn get_total_blocked_amount(&self) -> common_types::MinorUnit { + common_types::MinorUnit::new(self.all_captures.iter().fold(0, |accumulator, capture| { accumulator + match capture.1.status { storage_enums::CaptureStatus::Charged @@ -94,8 +91,8 @@ impl MultipleCaptureData { } })) } - pub fn get_total_charged_amount(&self) -> MinorUnit { - MinorUnit::new(self.all_captures.iter().fold(0, |accumulator, capture| { + pub fn get_total_charged_amount(&self) -> common_types::MinorUnit { + common_types::MinorUnit::new(self.all_captures.iter().fold(0, |accumulator, capture| { accumulator + match capture.1.status { storage_enums::CaptureStatus::Charged => capture.1.amount, @@ -126,7 +123,10 @@ impl MultipleCaptureData { accumulator }) } - pub fn get_attempt_status(&self, authorized_amount: MinorUnit) -> storage_enums::AttemptStatus { + pub fn get_attempt_status( + &self, + authorized_amount: common_types::MinorUnit, + ) -> storage_enums::AttemptStatus { let total_captured_amount = self.get_total_charged_amount(); if authorized_amount.is_equal(total_captured_amount) { return storage_enums::AttemptStatus::Charged; @@ -185,18 +185,18 @@ impl MultipleCaptureData { #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] pub struct SurchargeDetails { /// original_amount - pub original_amount: MinorUnit, + pub original_amount: common_types::MinorUnit, /// surcharge value pub surcharge: common_types::Surcharge, /// tax on surcharge value pub tax_on_surcharge: Option>, /// surcharge amount for this payment - pub surcharge_amount: MinorUnit, + pub surcharge_amount: common_types::MinorUnit, /// tax on surcharge amount for this payment - pub tax_on_surcharge_amount: MinorUnit, + pub tax_on_surcharge_amount: common_types::MinorUnit, /// sum of original amount, - pub final_amount: MinorUnit, + pub final_amount: common_types::MinorUnit, } impl From<(&RequestSurchargeDetails, &PaymentAttempt)> for SurchargeDetails { @@ -267,7 +267,7 @@ impl SurchargeDetails { .unwrap_or_default() .is_equal(self.tax_on_surcharge_amount) } - pub fn get_total_surcharge_amount(&self) -> MinorUnit { + pub fn get_total_surcharge_amount(&self) -> common_types::MinorUnit { self.surcharge_amount.add(self.tax_on_surcharge_amount) } } diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 1871acd246b..04a4f2dcc9a 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -368,7 +368,7 @@ pub async fn payouts_update_core( // Update DB with new data let payouts = payout_data.payouts.to_owned(); - let amount = api_models::payments::MinorUnit::from(req.amount.unwrap_or(api::Amount::Zero)) + let amount = common_utils::types::MinorUnit::from(req.amount.unwrap_or(api::Amount::Zero)) .get_amount_as_i64(); let updated_payouts = storage::PayoutsUpdate::Update { amount, @@ -1966,7 +1966,7 @@ pub async fn payout_create_db_entries( } else { None }; - let amount = api_models::payments::MinorUnit::from(req.amount.unwrap_or(api::Amount::Zero)) + let amount = common_utils::types::MinorUnit::from(req.amount.unwrap_or(api::Amount::Zero)) .get_amount_as_i64(); let payouts_req = storage::PayoutsNew { payout_id: payout_id.to_string(), diff --git a/crates/router/src/services/kafka/payment_attempt.rs b/crates/router/src/services/kafka/payment_attempt.rs index e9eab66e475..f5a8c153bc3 100644 --- a/crates/router/src/services/kafka/payment_attempt.rs +++ b/crates/router/src/services/kafka/payment_attempt.rs @@ -1,5 +1,5 @@ // use diesel_models::enums::MandateDetails; -use api_models::payments::MinorUnit; +use common_utils::types::MinorUnit; use diesel_models::enums as storage_enums; use hyperswitch_domain_models::{ mandates::MandateDetails, payments::payment_attempt::PaymentAttempt, diff --git a/crates/router/src/services/kafka/payment_intent.rs b/crates/router/src/services/kafka/payment_intent.rs index 6cdcbb1c478..ad61e102955 100644 --- a/crates/router/src/services/kafka/payment_intent.rs +++ b/crates/router/src/services/kafka/payment_intent.rs @@ -1,4 +1,4 @@ -use api_models::payments::MinorUnit; +use common_utils::types::MinorUnit; use diesel_models::enums as storage_enums; use hyperswitch_domain_models::payments::PaymentIntent; use time::OffsetDateTime; diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 3811be91a0a..c831045bc41 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -18,13 +18,12 @@ pub mod transformers; use std::{collections::HashMap, marker::PhantomData}; -use api_models::payments::MinorUnit; pub use api_models::{enums::Connector, mandates}; #[cfg(feature = "payouts")] pub use api_models::{enums::PayoutConnectors, payouts as payout_types}; use common_enums::MandateStatus; -pub use common_utils::request::RequestContent; use common_utils::{pii, pii::Email}; +pub use common_utils::{request::RequestContent, types::MinorUnit}; use error_stack::ResultExt; use hyperswitch_domain_models::mandates::{CustomerAcceptance, MandateData}; use masking::Secret; diff --git a/crates/router/src/types/api/payment_link.rs b/crates/router/src/types/api/payment_link.rs index ba1c99e003f..02e7a87ffc6 100644 --- a/crates/router/src/types/api/payment_link.rs +++ b/crates/router/src/types/api/payment_link.rs @@ -23,7 +23,7 @@ impl PaymentLinkResponseExt for RetrievePaymentLinkResponse { Ok(Self { link_to_pay: payment_link.link_to_pay, payment_link_id: payment_link.payment_link_id, - amount: api_models::payments::MinorUnit::new(payment_link.amount), + amount: common_utils::types::MinorUnit::new(payment_link.amount), description: payment_link.description, created_at: payment_link.created_at, merchant_id: payment_link.merchant_id, diff --git a/crates/router/src/types/storage/payment_attempt.rs b/crates/router/src/types/storage/payment_attempt.rs index 2b987c86660..5f8066bb815 100644 --- a/crates/router/src/types/storage/payment_attempt.rs +++ b/crates/router/src/types/storage/payment_attempt.rs @@ -1,4 +1,4 @@ -use api_models::payments::MinorUnit; +use common_utils::types::MinorUnit; use diesel_models::{capture::CaptureNew, enums}; use error_stack::ResultExt; pub use hyperswitch_domain_models::payments::payment_attempt::{ diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 4a526d5e65b..af65ba6caa9 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -1,7 +1,7 @@ // use actix_web::HttpMessage; use actix_web::http::header::HeaderMap; use api_models::{ - enums as api_enums, gsm as gsm_api_types, payment_methods, payments, payments::MinorUnit, + enums as api_enums, gsm as gsm_api_types, payment_methods, payments, routing::ConnectorSelection, }; use common_utils::{ @@ -10,6 +10,7 @@ use common_utils::{ ext_traits::{StringExt, ValueExt}, fp_utils::when, pii, + types::MinorUnit, }; use diesel_models::enums as storage_enums; use error_stack::{report, ResultExt}; diff --git a/crates/router/src/utils/user/sample_data.rs b/crates/router/src/utils/user/sample_data.rs index e3adbc99584..19ecc9a87bb 100644 --- a/crates/router/src/utils/user/sample_data.rs +++ b/crates/router/src/utils/user/sample_data.rs @@ -174,7 +174,7 @@ pub async fn generate_sample_data( true => common_enums::IntentStatus::Failed, _ => common_enums::IntentStatus::Succeeded, }, - amount: api_models::payments::MinorUnit::new(amount * 100), + amount: common_utils::types::MinorUnit::new(amount * 100), currency: Some( *currency_vec .get((num - 1) % currency_vec_len) @@ -192,7 +192,7 @@ pub async fn generate_sample_data( ), attempt_count: 1, customer_id: Some("hs-dashboard-user".to_string()), - amount_captured: api_models::payments::MinorUnit::optional_new_from_i64_amount( + amount_captured: common_utils::types::MinorUnit::optional_new_from_i64_amount( amount * 100, ), profile_id: Some(profile_id.clone()), diff --git a/crates/router/src/workflows/payment_sync.rs b/crates/router/src/workflows/payment_sync.rs index bc3255c914e..1ae01e6bec4 100644 --- a/crates/router/src/workflows/payment_sync.rs +++ b/crates/router/src/workflows/payment_sync.rs @@ -133,7 +133,7 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow { error_reason: Some(Some( consts::REQUEST_TIMEOUT_ERROR_MESSAGE_FROM_PSYNC.to_string(), )), - amount_capturable: api_models::payments::MinorUnit::optional_new_from_i64_amount(0), + amount_capturable: common_utils::types::MinorUnit::optional_new_from_i64_amount(0), updated_by: merchant_account.storage_scheme.to_string(), unified_code: None, unified_message: None, diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs index 454aa57b204..2da6fb94f5c 100644 --- a/crates/storage_impl/src/payments/payment_attempt.rs +++ b/crates/storage_impl/src/payments/payment_attempt.rs @@ -1,8 +1,5 @@ -use api_models::{ - enums::{AuthenticationType, Connector, PaymentMethod, PaymentMethodType}, - payments::MinorUnit, -}; -use common_utils::{errors::CustomResult, fallback_reverse_lookup_not_found}; +use api_models::enums::{AuthenticationType, Connector, PaymentMethod, PaymentMethodType}; +use common_utils::{errors::CustomResult, fallback_reverse_lookup_not_found, types::MinorUnit}; use diesel_models::{ enums::{ MandateAmountData as DieselMandateAmountData, MandateDataType as DieselMandateType, diff --git a/crates/storage_impl/src/payments/payment_intent.rs b/crates/storage_impl/src/payments/payment_intent.rs index d72aa20ec5f..7ead6cc935f 100644 --- a/crates/storage_impl/src/payments/payment_intent.rs +++ b/crates/storage_impl/src/payments/payment_intent.rs @@ -1,6 +1,5 @@ #[cfg(feature = "olap")] use api_models::payments::AmountFilter; -use api_models::payments::MinorUnit; #[cfg(feature = "olap")] use async_bb8_diesel::{AsyncConnection, AsyncRunQueryDsl}; #[cfg(feature = "olap")] @@ -800,9 +799,9 @@ impl DataModelExt for PaymentIntentNew { payment_id: self.payment_id, merchant_id: self.merchant_id, status: self.status, - amount: self.amount.get_amount_as_i64(), + amount: self.amount, currency: self.currency, - amount_captured: MinorUnit::get_optional_amount_as_i64(self.amount_captured), + amount_captured: self.amount_captured, customer_id: self.customer_id, description: self.description, return_url: self.return_url, @@ -846,9 +845,9 @@ impl DataModelExt for PaymentIntentNew { payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, status: storage_model.status, - amount: MinorUnit::new(storage_model.amount), + amount: storage_model.amount, currency: storage_model.currency, - amount_captured: MinorUnit::new_from_optional_i64_amount(storage_model.amount_captured), + amount_captured: storage_model.amount_captured, customer_id: storage_model.customer_id, description: storage_model.description, return_url: storage_model.return_url, @@ -898,11 +897,9 @@ impl DataModelExt for PaymentIntent { payment_id: self.payment_id, merchant_id: self.merchant_id, status: self.status, - amount: self.amount.get_amount_as_i64(), + amount: self.amount, currency: self.currency, - amount_captured: self - .amount_captured - .map(|capture_amt| capture_amt.get_amount_as_i64()), + amount_captured: self.amount_captured.map(|capture_amt| capture_amt), customer_id: self.customer_id, description: self.description, return_url: self.return_url, @@ -947,9 +944,9 @@ impl DataModelExt for PaymentIntent { payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, status: storage_model.status, - amount: MinorUnit::new(storage_model.amount), + amount: storage_model.amount, currency: storage_model.currency, - amount_captured: storage_model.amount_captured.map(MinorUnit::new), + amount_captured: storage_model.amount_captured, customer_id: storage_model.customer_id, description: storage_model.description, return_url: storage_model.return_url, @@ -1004,7 +1001,7 @@ impl DataModelExt for PaymentIntentUpdate { incremental_authorization_allowed, } => DieselPaymentIntentUpdate::ResponseUpdate { status, - amount_captured: MinorUnit::get_optional_amount_as_i64(amount_captured), + amount_captured, fingerprint_id, return_url, updated_by, @@ -1074,7 +1071,7 @@ impl DataModelExt for PaymentIntentUpdate { session_expiry, request_external_three_ds_authentication, } => DieselPaymentIntentUpdate::Update { - amount: amount.get_amount_as_i64(), + amount: amount, currency, setup_future_usage, status, @@ -1141,9 +1138,7 @@ impl DataModelExt for PaymentIntentUpdate { updated_by, }, Self::IncrementalAuthorizationAmountUpdate { amount } => { - DieselPaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { - amount: amount.get_amount_as_i64(), - } + DieselPaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { amount: amount } } Self::AuthorizationCountUpdate { authorization_count, From 9852bf4adec1ee11b914c5e95cab5e06a92b2b1c Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Wed, 15 May 2024 14:42:51 +0530 Subject: [PATCH 08/82] refactor(router): fixed spell check issue --- crates/common_utils/src/types.rs | 6 +++--- .../router/src/core/payments/operations/payment_response.rs | 2 +- .../operations/payments_incremental_authorization.rs | 2 +- crates/router/src/types/domain/address.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 96f57eb150e..49b1dcd95cf 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -234,13 +234,13 @@ impl MinorUnit { self.0 == 0 } - /// adds two minor unit amout + /// adds two minor unit amount pub fn add(&self, a2: Self) -> Self { Self::new(self.0 + a2.0) } - /// substract two minor unit amount - pub fn substract(&self, a2: Self) -> Self { + /// subtract two minor unit amount + pub fn subtract(&self, a2: Self) -> Self { Self::new(self.0 - a2.0) } diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 0abb03c3850..16e36933e2a 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1042,7 +1042,7 @@ async fn payment_response_update_tracker( payment_attempt_update = Some(storage::PaymentAttemptUpdate::AmountToCaptureUpdate { status: multiple_capture_data.get_attempt_status(authorized_amount), amount_capturable: authorized_amount - .substract(multiple_capture_data.get_total_blocked_amount()), + .subtract(multiple_capture_data.get_total_blocked_amount()), updated_by: storage_scheme.to_string(), }); Some(multiple_capture_data) 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 2cef24d9960..8a7ed5c8e2b 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -144,7 +144,7 @@ impl frm_message: None, payment_link_data: None, incremental_authorization_details: Some(IncrementalAuthorizationDetails { - additional_amount: request.amount.substract(amount).get_amount_as_i64(), + additional_amount: request.amount.subtract(amount).get_amount_as_i64(), total_amount: request.amount.get_amount_as_i64(), reason: request.reason.clone(), authorization_id: None, diff --git a/crates/router/src/types/domain/address.rs b/crates/router/src/types/domain/address.rs index 147c523e0b2..f2b110deb19 100644 --- a/crates/router/src/types/domain/address.rs +++ b/crates/router/src/types/domain/address.rs @@ -80,7 +80,7 @@ impl behaviour::Conversion for CustomerAddress { .customer_id .clone() .ok_or(ValidationError::MissingRequiredField { - field_name: "cutomer_id".to_string(), + field_name: "customer_id".to_string(), })?; let address = Address::convert_back(other, key).await?; From 41af58f49d5fd761589501f87d53716062d50d87 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Thu, 16 May 2024 15:36:05 +0530 Subject: [PATCH 09/82] refactor(router): resolved pr comments: --- crates/common_utils/src/types.rs | 5 +++++ crates/router/src/connector/utils.rs | 6 +++--- crates/router/src/core/authentication.rs | 2 +- crates/router/src/core/authentication/transformers.rs | 4 ++-- crates/router/src/core/payments.rs | 5 +++-- crates/router/src/core/payments/types.rs | 3 ++- crates/router/src/types/storage/payment_attempt.rs | 8 +++----- 7 files changed, 19 insertions(+), 14 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 49b1dcd95cf..b7b9e9341df 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -272,6 +272,11 @@ impl MinorUnit { self.0 == a2.0 } + /// checks if optional value is equal + pub fn is_equal_in_optional_value(&self, a2: Option) -> bool { + a2.is_some_and(|a2| a2.is_equal(*self)) // will remove in future + } + /// checks if both the values are not equal pub fn is_not_equal(&self, a2: Self) -> bool { !self.is_equal(a2) diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 09fa66ac3f0..6d8889a1667 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -151,9 +151,9 @@ where let captured_amount = types::Capturable::get_captured_amount(&self.request, payment_data); let total_capturable_amount = payment_data.payment_attempt.get_total_amount(); - if total_capturable_amount - .is_equal(MinorUnit::new(captured_amount.unwrap_or_default())) - { + if total_capturable_amount.is_equal_in_optional_value( + MinorUnit::new_from_optional_i64_amount(captured_amount), + ) { enums::AttemptStatus::Charged } else if captured_amount.is_some() { enums::AttemptStatus::PartialCharged diff --git a/crates/router/src/core/authentication.rs b/crates/router/src/core/authentication.rs index cbd312c94ed..1b050394b39 100644 --- a/crates/router/src/core/authentication.rs +++ b/crates/router/src/core/authentication.rs @@ -28,7 +28,7 @@ pub async fn perform_authentication( browser_details: Option, business_profile: storage::BusinessProfile, merchant_connector_account: payments_core::helpers::MerchantConnectorAccountType, - amount: common_utils::types::MinorUnit, + amount: Option, currency: Option, message_category: api::authentication::MessageCategory, device_channel: payments::DeviceChannel, diff --git a/crates/router/src/core/authentication/transformers.rs b/crates/router/src/core/authentication/transformers.rs index c005a8de3af..3c48b20ffa2 100644 --- a/crates/router/src/core/authentication/transformers.rs +++ b/crates/router/src/core/authentication/transformers.rs @@ -32,7 +32,7 @@ pub fn construct_authentication_router_data( billing_address: payments::Address, shipping_address: Option, browser_details: Option, - amount: common_utils::types::MinorUnit, + amount: Option, currency: Option, message_category: types::api::authentication::MessageCategory, device_channel: payments::DeviceChannel, @@ -61,7 +61,7 @@ pub fn construct_authentication_router_data( billing_address, shipping_address, browser_details, - amount: Some(amount.get_amount_as_i64()), + amount: amount.map(|amt| amt.get_amount_as_i64()), currency, message_category, device_channel, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index 596976f35c9..17e08ddf9ee 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -698,7 +698,8 @@ where let final_amount = payment_data .payment_attempt .amount - .add(surcharge_amount.add(tax_on_surcharge_amount)); + .add(surcharge_amount) + .add(tax_on_surcharge_amount); Ok(Some(api::SessionSurchargeDetails::PreDetermined( types::SurchargeDetails { original_amount: payment_data.payment_attempt.amount, @@ -3917,7 +3918,7 @@ pub async fn payment_external_authentication( browser_info, business_profile, merchant_connector_account, - amount, + Some(amount), Some(currency), authentication::MessageCategory::Payment, req.device_channel, diff --git a/crates/router/src/core/payments/types.rs b/crates/router/src/core/payments/types.rs index d15698b4b5c..e87e48f04b4 100644 --- a/crates/router/src/core/payments/types.rs +++ b/crates/router/src/core/payments/types.rs @@ -217,7 +217,8 @@ impl From<(&RequestSurchargeDetails, &PaymentAttempt)> for SurchargeDetails { tax_on_surcharge_amount, final_amount: payment_attempt .amount - .add(surcharge_amount.add(tax_on_surcharge_amount)), + .add(surcharge_amount) + .add(tax_on_surcharge_amount), } } } diff --git a/crates/router/src/types/storage/payment_attempt.rs b/crates/router/src/types/storage/payment_attempt.rs index 5f8066bb815..398bd25604e 100644 --- a/crates/router/src/types/storage/payment_attempt.rs +++ b/crates/router/src/types/storage/payment_attempt.rs @@ -68,11 +68,9 @@ impl PaymentAttemptExt for PaymentAttempt { }) } fn get_total_amount(&self) -> MinorUnit { - self.amount.add( - self.surcharge_amount - .unwrap_or_default() - .add(self.tax_amount.unwrap_or_default()), - ) + self.amount + .add(self.surcharge_amount.unwrap_or_default()) + .add(self.tax_amount.unwrap_or_default()) } } From 6e6726f342991af82e8a08d93da6ff50f83b424c Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 17 May 2024 16:12:35 +0530 Subject: [PATCH 10/82] refactor(router): resolved pr comments --- crates/api_models/src/payment_methods.rs | 2 +- crates/api_models/src/payments.rs | 13 +-- .../src/surcharge_decision_configs.rs | 8 +- crates/common_utils/src/errors.rs | 4 +- crates/common_utils/src/types.rs | 105 ++++++++---------- crates/diesel_models/src/authorization.rs | 9 +- crates/diesel_models/src/payment_link.rs | 5 +- .../src/payments/payment_attempt.rs | 18 ++- .../src/router_data.rs | 3 +- .../stripe/payment_intents/types.rs | 6 +- .../src/connector/adyen/transformers.rs | 2 +- .../src/connector/checkout/transformers.rs | 4 +- .../src/connector/cryptopay/transformers.rs | 4 +- .../src/connector/paypal/transformers.rs | 2 +- .../router/src/connector/payu/transformers.rs | 4 +- .../src/connector/square/transformers.rs | 4 +- .../src/connector/stripe/transformers.rs | 8 +- crates/router/src/connector/utils.rs | 11 +- .../fraud_check/flows/fulfillment_flow.rs | 4 +- .../surcharge_decision_configs.rs | 12 +- crates/router/src/core/payments.rs | 15 +-- crates/router/src/core/payments/helpers.rs | 34 +++--- .../payments/operations/payment_create.rs | 4 +- .../payments/operations/payment_response.rs | 41 +++---- .../payments/operations/payment_update.rs | 11 +- .../payments_incremental_authorization.rs | 8 +- .../router/src/core/payments/transformers.rs | 41 +++---- crates/router/src/core/payments/types.rs | 31 ++---- crates/router/src/core/payouts.rs | 8 +- crates/router/src/core/utils.rs | 20 +++- .../src/services/kafka/payment_attempt.rs | 28 ++--- crates/router/src/types.rs | 18 +-- crates/router/src/types/api/payment_link.rs | 2 +- .../src/types/storage/payment_attempt.rs | 4 +- crates/router/src/types/transformers.rs | 4 +- crates/router/src/utils/user/sample_data.rs | 4 +- crates/router/src/workflows/payment_sync.rs | 2 +- 37 files changed, 225 insertions(+), 278 deletions(-) diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 048b845d5a8..305aec5df48 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -492,7 +492,7 @@ pub struct SurchargeDetailsResponse { #[serde(rename_all = "snake_case", tag = "type", content = "value")] pub enum SurchargeResponse { /// Fixed Surcharge value - Fixed(i64), + Fixed(MinorUnit), /// Surcharge percentage Rate(SurchargePercentage), } diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index f7d8bcc1459..01521c65c8d 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -477,7 +477,7 @@ impl PaymentsRequest { .map(|surcharge_details| surcharge_details.get_total_surcharge_amount()) .unwrap_or_default(); self.amount - .map(|amount| MinorUnit::from(amount).add(surcharge_amount)) + .map(|amount| MinorUnit::from(amount) + surcharge_amount) } } #[derive( @@ -528,12 +528,11 @@ pub struct BrowserInformation { impl RequestSurchargeDetails { pub fn is_surcharge_zero(&self) -> bool { - self.surcharge_amount.get_amount_as_i64() == 0 - && self.tax_amount.unwrap_or_default().get_amount_as_i64() == 0 + self.surcharge_amount == MinorUnit::new(0) + && self.tax_amount.unwrap_or_default() == MinorUnit::new(0) } pub fn get_total_surcharge_amount(&self) -> MinorUnit { - self.surcharge_amount - .add(self.tax_amount.unwrap_or_default()) + self.surcharge_amount + self.tax_amount.unwrap_or_default() } } @@ -3505,7 +3504,7 @@ pub struct IncrementalAuthorizationResponse { /// Error message sent by the connector for authorization pub error_message: Option, /// Previously authorized amount for the payment - pub previously_authorized_amount: i64, + pub previously_authorized_amount: MinorUnit, } #[derive(Clone, Debug, serde::Serialize)] @@ -4343,7 +4342,7 @@ pub struct PaymentsIncrementalAuthorizationRequest { #[serde(skip)] pub payment_id: String, /// The total amount including previously authorized amount and additional amount - #[schema(value_type = i64, example = 6540)] + #[schema(value_type = MinorUnit, example = 6540)] pub amount: MinorUnit, /// Reason for incremental authorization pub reason: Option, diff --git a/crates/api_models/src/surcharge_decision_configs.rs b/crates/api_models/src/surcharge_decision_configs.rs index 0777bde85de..9c2d1ac26e8 100644 --- a/crates/api_models/src/surcharge_decision_configs.rs +++ b/crates/api_models/src/surcharge_decision_configs.rs @@ -1,4 +1,8 @@ -use common_utils::{consts::SURCHARGE_PERCENTAGE_PRECISION_LENGTH, events, types::Percentage}; +use common_utils::{ + consts::SURCHARGE_PERCENTAGE_PRECISION_LENGTH, + events, + types::{MinorUnit, Percentage}, +}; use euclid::frontend::{ ast::Program, dir::{DirKeyKind, EuclidDirFilter}, @@ -15,7 +19,7 @@ pub struct SurchargeDetailsOutput { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "snake_case", tag = "type", content = "value")] pub enum SurchargeOutput { - Fixed { amount: i64 }, + Fixed { amount: MinorUnit }, Rate(Percentage), } diff --git a/crates/common_utils/src/errors.rs b/crates/common_utils/src/errors.rs index 7f343065705..967580f0ae5 100644 --- a/crates/common_utils/src/errors.rs +++ b/crates/common_utils/src/errors.rs @@ -1,5 +1,7 @@ //! Errors and error specific types for universal use +use crate::types::MinorUnit; + /// Custom Result /// A custom datatype that wraps the error variant into a report, allowing /// error_stack::Report specific extendability @@ -89,7 +91,7 @@ pub enum PercentageError { /// percentage value percentage: f32, /// amount value - amount: i64, + amount: MinorUnit, }, } diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index b7b9e9341df..3d4691cc6c5 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -1,5 +1,10 @@ //! Types that can be used in other crates -use std::{fmt::Display, primitive::i64, str::FromStr}; +use std::{ + fmt::Display, + ops::{Add, Sub}, + primitive::i64, + str::FromStr, +}; use diesel::{ backend::Backend, @@ -54,13 +59,17 @@ impl Percentage { /// apply the percentage to amount and ceil the result #[allow(clippy::as_conversions)] - pub fn apply_and_ceil_result(&self, amount: i64) -> CustomResult { + pub fn apply_and_ceil_result( + &self, + amount: MinorUnit, + ) -> CustomResult { let max_amount = i64::MAX / 10000; + let amount = amount.0; if amount > max_amount { // value gets rounded off after i64::MAX/10000 Err(report!(PercentageError::UnableToApplyPercentage { percentage: self.percentage, - amount, + amount: MinorUnit::new(amount), })) .attach_printable(format!( "Cannot calculate percentage for amount greater than {}", @@ -69,9 +78,10 @@ impl Percentage { } else { let percentage_f64 = f64::from(self.percentage); let result = (amount as f64 * (percentage_f64 / 100.0)).ceil() as i64; - Ok(result) + Ok(MinorUnit::new(result)) } } + fn is_valid_string_value(value: &str) -> CustomResult { let float_value = Self::is_valid_float_string(value)?; Ok(Self::is_valid_range(float_value) && Self::is_valid_precision_length(value)) @@ -153,7 +163,7 @@ impl<'de, const PRECISION: u8> Deserialize<'de> for Percentage { #[serde(rename_all = "snake_case", tag = "type", content = "value")] pub enum Surcharge { /// Fixed Surcharge value - Fixed(i64), + Fixed(MinorUnit), /// Surcharge percentage Rate(Percentage<{ consts::SURCHARGE_PERCENTAGE_PRECISION_LENGTH }>), } @@ -217,10 +227,19 @@ where /// This Unit struct represents MinorUnit in which core amount works #[derive( - Default, Debug, serde::Deserialize, AsExpression, serde::Serialize, Clone, Copy, PartialEq, Eq, + Default, + Debug, + serde::Deserialize, + AsExpression, + serde::Serialize, + Clone, + Copy, + PartialEq, + Eq, + Hash, )] #[diesel(sql_type = diesel::sql_types::BigInt)] -pub struct MinorUnit(i64); //core +pub struct MinorUnit(i64); impl MinorUnit { /// gets amount as i64 value @@ -229,63 +248,11 @@ impl MinorUnit { self.0 } - /// checks if the amount is zero value - pub fn is_zero(&self) -> bool { - self.0 == 0 - } - - /// adds two minor unit amount - pub fn add(&self, a2: Self) -> Self { - Self::new(self.0 + a2.0) - } - - /// subtract two minor unit amount - pub fn subtract(&self, a2: Self) -> Self { - Self::new(self.0 - a2.0) - } - - /// gets optional amount from minor unit - pub fn get_optional_amount_as_i64(optional_amount: Option) -> Option { - // remove in future - optional_amount.map(|amount| amount.0) - } - /// forms a new minor unit from amount pub fn new(value: i64) -> Self { // remove in future Self(value) } - - /// gets optional minor unit from amount - pub fn optional_new_from_i64_amount(value: i64) -> Option { - Some(Self(value)) - } - - /// forms a new optional minor unit from optional amount - pub fn new_from_optional_i64_amount(value: Option) -> Option { - // remove in future - value.map(Self) - } - - /// checks if both the values are equal - pub fn is_equal(&self, a2: Self) -> bool { - self.0 == a2.0 - } - - /// checks if optional value is equal - pub fn is_equal_in_optional_value(&self, a2: Option) -> bool { - a2.is_some_and(|a2| a2.is_equal(*self)) // will remove in future - } - - /// checks if both the values are not equal - pub fn is_not_equal(&self, a2: Self) -> bool { - !self.is_equal(a2) - } - - /// checks if one value is greater than the other - pub fn is_greater_than(&self, a2: Self) -> bool { - self.0 > a2.0 - } } impl Display for MinorUnit { @@ -326,3 +293,23 @@ where Ok(row) } } + +impl Add for MinorUnit { + type Output = MinorUnit; + fn add(self, a2: MinorUnit) -> MinorUnit { + MinorUnit(self.0 + a2.0) + } +} + +impl Sub for MinorUnit { + type Output = MinorUnit; + fn sub(self, a2: MinorUnit) -> MinorUnit { + MinorUnit(self.0 - a2.0) + } +} + +impl PartialOrd for MinorUnit { + fn partial_cmp(&self, a2: &Self) -> Option { + Some(self.0.cmp(&a2.0)) + } +} diff --git a/crates/diesel_models/src/authorization.rs b/crates/diesel_models/src/authorization.rs index b6f75bbb9b7..a7f13821d89 100644 --- a/crates/diesel_models/src/authorization.rs +++ b/crates/diesel_models/src/authorization.rs @@ -1,3 +1,4 @@ +use common_utils::types::MinorUnit; use diesel::{AsChangeset, Identifiable, Insertable, Queryable}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; @@ -11,7 +12,7 @@ pub struct Authorization { pub authorization_id: String, pub merchant_id: String, pub payment_id: String, - pub amount: i64, + pub amount: MinorUnit, #[serde(with = "common_utils::custom_serde::iso8601")] pub created_at: PrimitiveDateTime, #[serde(with = "common_utils::custom_serde::iso8601")] @@ -20,7 +21,7 @@ pub struct Authorization { pub error_code: Option, pub error_message: Option, pub connector_authorization_id: Option, - pub previously_authorized_amount: i64, + pub previously_authorized_amount: MinorUnit, } #[derive(Clone, Debug, Insertable, router_derive::DebugAsDisplay, Serialize, Deserialize)] @@ -29,12 +30,12 @@ pub struct AuthorizationNew { pub authorization_id: String, pub merchant_id: String, pub payment_id: String, - pub amount: i64, + pub amount: MinorUnit, pub status: storage_enums::AuthorizationStatus, pub error_code: Option, pub error_message: Option, pub connector_authorization_id: Option, - pub previously_authorized_amount: i64, + pub previously_authorized_amount: MinorUnit, } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/crates/diesel_models/src/payment_link.rs b/crates/diesel_models/src/payment_link.rs index ed0e979d026..f4630c75d72 100644 --- a/crates/diesel_models/src/payment_link.rs +++ b/crates/diesel_models/src/payment_link.rs @@ -1,3 +1,4 @@ +use common_utils::types::MinorUnit; use diesel::{Identifiable, Insertable, Queryable}; use serde::{self, Deserialize, Serialize}; use time::PrimitiveDateTime; @@ -12,7 +13,7 @@ pub struct PaymentLink { pub payment_id: String, pub link_to_pay: String, pub merchant_id: String, - pub amount: i64, + pub amount: MinorUnit, pub currency: Option, #[serde(with = "common_utils::custom_serde::iso8601")] pub created_at: PrimitiveDateTime, @@ -42,7 +43,7 @@ pub struct PaymentLinkNew { pub payment_id: String, pub link_to_pay: String, pub merchant_id: String, - pub amount: i64, + pub amount: MinorUnit, pub currency: Option, #[serde(with = "common_utils::custom_serde::iso8601::option")] pub created_at: Option, diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index feb9cfa7cb3..4645ad9525d 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -171,16 +171,14 @@ pub struct PaymentAttempt { impl PaymentAttempt { pub fn get_total_amount(&self) -> MinorUnit { - self.amount.add( - self.surcharge_amount - .unwrap_or_default() - .add(self.tax_amount.unwrap_or_default()), - ) + self.amount + + self.surcharge_amount.unwrap_or_default() + + self.tax_amount.unwrap_or_default() } pub fn get_total_surcharge_amount(&self) -> Option { self.surcharge_amount - .map(|surcharge_amount| surcharge_amount.add(self.tax_amount.unwrap_or_default())) + .map(|surcharge_amount| surcharge_amount + self.tax_amount.unwrap_or_default()) } } @@ -260,11 +258,9 @@ pub struct PaymentAttemptNew { impl PaymentAttemptNew { /// returns amount + surcharge_amount + tax_amount pub fn calculate_net_amount(&self) -> MinorUnit { - self.amount.add( - self.surcharge_amount - .unwrap_or_default() - .add(self.tax_amount.unwrap_or_default()), - ) + self.amount + + self.surcharge_amount.unwrap_or_default() + + self.tax_amount.unwrap_or_default() } pub fn populate_derived_fields(self) -> Self { diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs index 247ae06987f..cbaaeeda42b 100644 --- a/crates/hyperswitch_domain_models/src/router_data.rs +++ b/crates/hyperswitch_domain_models/src/router_data.rs @@ -1,6 +1,5 @@ use std::{collections::HashMap, marker::PhantomData}; -use common_utils::types::MinorUnit; use masking::Secret; use crate::payment_address::PaymentAddress; @@ -22,7 +21,7 @@ pub struct RouterData { pub address: PaymentAddress, pub auth_type: common_enums::enums::AuthenticationType, pub connector_meta_data: Option, - pub amount_captured: Option, + pub amount_captured: Option, pub access_token: Option, pub session_token: Option, pub reference_id: Option, diff --git a/crates/router/src/compatibility/stripe/payment_intents/types.rs b/crates/router/src/compatibility/stripe/payment_intents/types.rs index 7c0d649f7a2..6ad596e171a 100644 --- a/crates/router/src/compatibility/stripe/payment_intents/types.rs +++ b/crates/router/src/compatibility/stripe/payment_intents/types.rs @@ -327,7 +327,7 @@ impl TryFrom for payments::PaymentsRequest { field_name: "currency", })?, capture_method: item.capture_method, - amount_to_capture: MinorUnit::new_from_optional_i64_amount(item.amount_capturable), + amount_to_capture: item.amount_capturable.map(|amt| MinorUnit::new(amt)), confirm: item.confirm, customer_id: item.customer, email: item.receipt_email, @@ -512,8 +512,8 @@ impl From for StripePaymentIntentResponse { id: resp.payment_id, status: StripePaymentStatus::from(resp.status), amount: resp.amount.get_amount_as_i64(), - amount_capturable: MinorUnit::get_optional_amount_as_i64(resp.amount_capturable), - amount_received: MinorUnit::get_optional_amount_as_i64(resp.amount_received), + amount_capturable: resp.amount_capturable.map(|amt| amt.get_amount_as_i64()), + amount_received: resp.amount_received.map(|amt| amt.get_amount_as_i64()), connector: resp.connector, client_secret: resp.client_secret, created: resp.created.map(|t| t.assume_utc().unix_timestamp()), diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index f17570fdf55..ab01f9e70ce 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -3926,7 +3926,7 @@ impl TryFrom> connector_response_reference_id: Some(item.response.reference), incremental_authorization_allowed: None, }), - amount_captured: Some(common_utils::types::MinorUnit::new(0)), + amount_captured: Some(0), ..item.data }) } diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index 1650629791e..ddf65d23aa4 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -910,9 +910,7 @@ impl TryFrom> incremental_authorization_allowed: None, }), status, - amount_captured: common_utils::types::MinorUnit::new_from_optional_i64_amount( - amount_captured, - ), + amount_captured, ..item.data }) } diff --git a/crates/router/src/connector/cryptopay/transformers.rs b/crates/router/src/connector/cryptopay/transformers.rs index 97a7de36b04..d9d164ac201 100644 --- a/crates/router/src/connector/cryptopay/transformers.rs +++ b/crates/router/src/connector/cryptopay/transformers.rs @@ -204,9 +204,7 @@ impl Ok(Self { status, response, - amount_captured: common_utils::types::MinorUnit::new_from_optional_i64_amount( - amount_captured, - ), + amount_captured, ..item.data }) } diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index f62542f1587..338b8c5ba4e 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -1795,7 +1795,7 @@ impl TryFrom> .or(Some(item.response.id)), incremental_authorization_allowed: None, }), - amount_captured: Some(common_utils::types::MinorUnit::new(amount_captured)), + amount_captured: Some(amount_captured), ..item.data }) } diff --git a/crates/router/src/connector/payu/transformers.rs b/crates/router/src/connector/payu/transformers.rs index 3e24b128f8b..575f199b730 100644 --- a/crates/router/src/connector/payu/transformers.rs +++ b/crates/router/src/connector/payu/transformers.rs @@ -485,12 +485,12 @@ impl .or(Some(order.order_id.clone())), incremental_authorization_allowed: None, }), - amount_captured: Some(common_utils::types::MinorUnit::new( + amount_captured: Some( order .total_amount .parse::() .change_context(errors::ConnectorError::ResponseDeserializationFailed)?, - )), + ), ..item.data }) } diff --git a/crates/router/src/connector/square/transformers.rs b/crates/router/src/connector/square/transformers.rs index 9792f5448a9..0de122d5da2 100644 --- a/crates/router/src/connector/square/transformers.rs +++ b/crates/router/src/connector/square/transformers.rs @@ -382,9 +382,7 @@ impl connector_response_reference_id: item.response.payment.reference_id, incremental_authorization_allowed: None, }), - amount_captured: common_utils::types::MinorUnit::new_from_optional_i64_amount( - amount_captured, - ), + amount_captured, ..item.data }) } diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 3d3be847bde..20c1b4e70f9 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -2461,9 +2461,7 @@ impl // statement_descriptor_suffix: item.response.statement_descriptor_suffix.map(|x| x.as_str()), // three_ds_form, response, - amount_captured: common_utils::types::MinorUnit::new_from_optional_i64_amount( - item.response.amount_received, - ), + amount_captured: item.response.amount_received, connector_response: connector_response_data, ..item.data }) @@ -2636,9 +2634,7 @@ impl Ok(Self { status: enums::AttemptStatus::from(item.response.status.to_owned()), response, - amount_captured: common_utils::types::MinorUnit::new_from_optional_i64_amount( - item.response.amount_received, - ), + amount_captured: item.response.amount_received, connector_response: connector_response_data, ..item.data }) diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 6d8889a1667..0a1411dcd27 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -136,12 +136,7 @@ where { match self.status { enums::AttemptStatus::Voided => { - if payment_data - .payment_intent - .amount_captured - .unwrap_or_default() - .is_greater_than(MinorUnit::new(0)) - { + if payment_data.payment_intent.amount_captured > Some(MinorUnit::new(0)) { enums::AttemptStatus::PartialCharged } else { self.status @@ -151,9 +146,7 @@ where let captured_amount = types::Capturable::get_captured_amount(&self.request, payment_data); let total_capturable_amount = payment_data.payment_attempt.get_total_amount(); - if total_capturable_amount.is_equal_in_optional_value( - MinorUnit::new_from_optional_i64_amount(captured_amount), - ) { + if Some(total_capturable_amount) == captured_amount.map(|amt| MinorUnit::new(amt)) { enums::AttemptStatus::Charged } else if captured_amount.is_some() { enums::AttemptStatus::PartialCharged diff --git a/crates/router/src/core/fraud_check/flows/fulfillment_flow.rs b/crates/router/src/core/fraud_check/flows/fulfillment_flow.rs index 2bd503a4642..1f4f2ccebee 100644 --- a/crates/router/src/core/fraud_check/flows/fulfillment_flow.rs +++ b/crates/router/src/core/fraud_check/flows/fulfillment_flow.rs @@ -72,7 +72,9 @@ pub async fn construct_fulfillment_router_data<'a>( address: PaymentAddress::default(), auth_type: payment_attempt.authentication_type.unwrap_or_default(), connector_meta_data: merchant_connector_account.get_metadata(), - amount_captured: payment_intent.amount_captured, + amount_captured: payment_intent + .amount_captured + .map(|amt| amt.get_amount_as_i64()), payment_method_status: None, request: FraudCheckFulfillmentData { amount: payment_attempt.amount.get_amount_as_i64(), diff --git a/crates/router/src/core/payment_methods/surcharge_decision_configs.rs b/crates/router/src/core/payment_methods/surcharge_decision_configs.rs index aa01613a206..88ae82cad33 100644 --- a/crates/router/src/core/payment_methods/surcharge_decision_configs.rs +++ b/crates/router/src/core/payment_methods/surcharge_decision_configs.rs @@ -353,7 +353,7 @@ fn get_surcharge_details_from_surcharge_output( let surcharge_amount = match surcharge_details.surcharge.clone() { surcharge_decision_configs::SurchargeOutput::Fixed { amount } => amount, surcharge_decision_configs::SurchargeOutput::Rate(percentage) => percentage - .apply_and_ceil_result(payment_attempt.amount.get_amount_as_i64()) + .apply_and_ceil_result(payment_attempt.amount) .change_context(ConfigError::DslExecutionError) .attach_printable("Failed to Calculate surcharge amount by applying percentage")?, }; @@ -367,7 +367,7 @@ fn get_surcharge_details_from_surcharge_output( .attach_printable("Failed to Calculate tax amount") }) .transpose()? - .unwrap_or(0); + .unwrap_or_default(); Ok(types::SurchargeDetails { original_amount: payment_attempt.amount, surcharge: match surcharge_details.surcharge { @@ -379,11 +379,9 @@ fn get_surcharge_details_from_surcharge_output( } }, tax_on_surcharge: surcharge_details.tax_on_surcharge, - surcharge_amount: common_utils_types::MinorUnit::new(surcharge_amount), - tax_on_surcharge_amount: common_utils_types::MinorUnit::new(tax_on_surcharge_amount), - final_amount: common_utils_types::MinorUnit::new( - payment_attempt.amount.get_amount_as_i64() + surcharge_amount + tax_on_surcharge_amount, - ), + 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 17e08ddf9ee..9db0c24d99e 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -27,7 +27,7 @@ use api_models::{ use common_utils::{ ext_traits::{AsyncExt, StringExt}, pii, - types::Surcharge, + types::{MinorUnit, Surcharge}, }; use diesel_models::{ephemeral_key, fraud_check::FraudCheck}; use error_stack::{report, ResultExt}; @@ -695,15 +695,12 @@ where { if let Some(surcharge_amount) = payment_data.payment_attempt.surcharge_amount { let tax_on_surcharge_amount = payment_data.payment_attempt.tax_amount.unwrap_or_default(); - let final_amount = payment_data - .payment_attempt - .amount - .add(surcharge_amount) - .add(tax_on_surcharge_amount); + let final_amount = + payment_data.payment_attempt.amount + surcharge_amount + tax_on_surcharge_amount; Ok(Some(api::SessionSurchargeDetails::PreDetermined( types::SurchargeDetails { original_amount: payment_data.payment_attempt.amount, - surcharge: Surcharge::Fixed(surcharge_amount.get_amount_as_i64()), + surcharge: Surcharge::Fixed(surcharge_amount), tax_on_surcharge: None, surcharge_amount, tax_on_surcharge_amount, @@ -2486,8 +2483,8 @@ impl EventInfo for PaymentEvent { #[derive(Debug, Default, Clone)] pub struct IncrementalAuthorizationDetails { - pub additional_amount: i64, - pub total_amount: i64, + pub additional_amount: MinorUnit, + pub total_amount: MinorUnit, pub reason: Option, pub authorization_id: Option, } diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 988c6bae38a..ab5a9b1da84 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -600,8 +600,9 @@ pub async fn get_token_for_recurring_mandate( .await .flatten(); - let original_payment_authorized_amount = - MinorUnit::get_optional_amount_as_i64(original_payment_intent.clone().map(|pi| pi.amount)); + let original_payment_authorized_amount = original_payment_intent + .clone() + .map(|pi| pi.amount.get_amount_as_i64()); let original_payment_authorized_currency = original_payment_intent.clone().and_then(|pi| pi.currency); @@ -718,7 +719,7 @@ pub fn validate_merchant_id( #[instrument(skip_all)] pub fn validate_request_amount_and_amount_to_capture( op_amount: Option, - op_amount_to_capture: Option, + op_amount_to_capture: Option, surcharge_details: Option, ) -> CustomResult<(), errors::ApiErrorResponse> { match (op_amount, op_amount_to_capture) { @@ -729,14 +730,10 @@ pub fn validate_request_amount_and_amount_to_capture( api::Amount::Value(amount_inner) => { // If both amount and amount to capture is present // then amount to be capture should be less than or equal to request amount - let total_capturable_amount = amount_inner.get() + let total_capturable_amount = MinorUnit::new(amount_inner.get()) + surcharge_details - .map(|surcharge_details| { - surcharge_details - .get_total_surcharge_amount() - .get_amount_as_i64() - }) - .unwrap_or(0); + .map(|surcharge_details| surcharge_details.get_total_surcharge_amount()) + .unwrap_or_default(); utils::when(!amount_to_capture.le(&total_capturable_amount), || { Err(report!(errors::ApiErrorResponse::PreconditionFailed { message: format!( @@ -778,15 +775,13 @@ pub fn validate_amount_to_capture_and_capture_method( .map(|surcharge_details| surcharge_details.get_total_surcharge_amount()) .or_else(|| { payment_attempt.map(|payment_attempt| { - payment_attempt - .surcharge_amount - .unwrap_or_default() - .add(payment_attempt.tax_amount.unwrap_or_default()) + 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.add(surcharge_amount)); + original_amount.map(|original_amount| original_amount + surcharge_amount); let amount_to_capture = request .amount_to_capture @@ -795,14 +790,11 @@ pub fn validate_amount_to_capture_and_capture_method( if let Some((total_capturable_amount, amount_to_capture)) = total_capturable_amount.zip(amount_to_capture) { - utils::when( - amount_to_capture.is_not_equal(total_capturable_amount), - || { - Err(report!(errors::ApiErrorResponse::PreconditionFailed { + utils::when(amount_to_capture != total_capturable_amount, || { + Err(report!(errors::ApiErrorResponse::PreconditionFailed { message: "amount_to_capture must be equal to total_capturable_amount when capture_method = automatic".into() })) - }, - ) + }) } else { Ok(()) } diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index e4693b946ff..2166a4aa4ed 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -684,7 +684,7 @@ impl ValidateRequest for PaymentCreate helpers::validate_request_amount_and_amount_to_capture( request.amount, - MinorUnit::get_optional_amount_as_i64(request.amount_to_capture), + request.amount_to_capture, request.surcharge_details, ) .change_context(errors::ApiErrorResponse::InvalidDataFormat { @@ -1109,7 +1109,7 @@ async fn create_payment_link( payment_id: payment_id.clone(), merchant_id: merchant_id.clone(), link_to_pay: payment_link.clone(), - amount: common_utils::types::MinorUnit::from(amount).get_amount_as_i64(), + amount: common_utils::types::MinorUnit::from(amount), currency: request.currency, created_at, last_modified_at, diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 16e36933e2a..02b5d8cbd71 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -269,19 +269,13 @@ impl PostUpdateTracker, types::PaymentsIncrementalAu ( Some( storage::PaymentAttemptUpdate::IncrementalAuthorizationAmountUpdate { - amount: MinorUnit::new( - incremental_authorization_details.total_amount, - ), - amount_capturable: MinorUnit::new( - incremental_authorization_details.total_amount, - ), + amount: incremental_authorization_details.total_amount, + amount_capturable: incremental_authorization_details.total_amount, }, ), Some( storage::PaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { - amount: MinorUnit::new( - incremental_authorization_details.total_amount, - ), + amount: incremental_authorization_details.total_amount, }, ), ) @@ -800,11 +794,10 @@ async fn payment_response_update_tracker( error_message: Some(Some(err.message)), error_code: Some(Some(err.code)), error_reason: Some(err.reason), - amount_capturable: MinorUnit::new_from_optional_i64_amount( - router_data - .request - .get_amount_capturable(&payment_data, status), - ), + amount_capturable: router_data + .request + .get_amount_capturable(&payment_data, status) + .map(|amt| MinorUnit::new(amt)), updated_by: storage_scheme.to_string(), unified_code: option_gsm.clone().map(|gsm| gsm.unified_code), unified_message: option_gsm.map(|gsm| gsm.unified_message), @@ -926,7 +919,6 @@ async fn payment_response_update_tracker( payment_data.payment_attempt.connector.clone(), payment_data.payment_attempt.merchant_id.clone(), ); - let (capture_updates, payment_attempt_update) = match payment_data .multiple_capture_data { @@ -949,12 +941,10 @@ async fn payment_response_update_tracker( connector: None, connector_transaction_id: connector_transaction_id.clone(), authentication_type: None, - amount_capturable: MinorUnit::new_from_optional_i64_amount( - router_data.request.get_amount_capturable( - &payment_data, - updated_attempt_status, - ), - ), + amount_capturable: router_data + .request + .get_amount_capturable(&payment_data, updated_attempt_status) + .map(|amt| MinorUnit::new(amt)), payment_method_id, mandate_id: payment_data.payment_attempt.mandate_id.clone(), connector_metadata, @@ -1042,7 +1032,7 @@ async fn payment_response_update_tracker( payment_attempt_update = Some(storage::PaymentAttemptUpdate::AmountToCaptureUpdate { status: multiple_capture_data.get_attempt_status(authorized_amount), amount_capturable: authorized_amount - .subtract(multiple_capture_data.get_total_blocked_amount()), + - multiple_capture_data.get_total_blocked_amount(), updated_by: storage_scheme.to_string(), }); Some(multiple_capture_data) @@ -1112,7 +1102,7 @@ async fn payment_response_update_tracker( let amount_captured = get_total_amount_captured( &router_data.request, - router_data.amount_captured, + router_data.amount_captured.map(|amt| MinorUnit::new(amt)), router_data.status, &payment_data, ); @@ -1378,8 +1368,9 @@ fn get_total_amount_captured( } None => { //Non multiple capture - let amount = - MinorUnit::new_from_optional_i64_amount(request.get_captured_amount(payment_data)); + let amount = request + .get_captured_amount(payment_data) + .map(|amt| MinorUnit::new(amt)); amount_captured.or_else(|| { if router_data_status == enums::AttemptStatus::Charged { amount diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index 0240d94fa93..21d94123dcf 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -4,10 +4,7 @@ use api_models::{ enums::FrmSuggestion, mandates::RecurringDetails, payments::RequestSurchargeDetails, }; use async_trait::async_trait; -use common_utils::{ - ext_traits::{AsyncExt, Encode, ValueExt}, - types::MinorUnit, -}; +use common_utils::ext_traits::{AsyncExt, Encode, ValueExt}; use error_stack::{report, ResultExt}; use router_derive::PaymentOperation; use router_env::{instrument, tracing}; @@ -148,7 +145,7 @@ impl GetTracker, api::PaymentsRequest> for Pa helpers::validate_request_amount_and_amount_to_capture( request.amount, - MinorUnit::get_optional_amount_as_i64(request.amount_to_capture), + request.amount_to_capture, request .surcharge_details .or(payment_attempt.get_surcharge_details()), @@ -339,7 +336,7 @@ impl GetTracker, api::PaymentsRequest> for Pa .as_ref() .map(RequestSurchargeDetails::get_total_surcharge_amount) .or(payment_attempt.get_total_surcharge_amount()); - amount.add(surcharge_amount.unwrap_or_default()) + amount + surcharge_amount.unwrap_or_default() }; (Box::new(operations::PaymentConfirm), amount.into()) } else { @@ -762,7 +759,7 @@ impl ValidateRequest for PaymentUpdate helpers::validate_request_amount_and_amount_to_capture( request.amount, - MinorUnit::get_optional_amount_as_i64(request.amount_to_capture), + request.amount_to_capture, request.surcharge_details, ) .change_context(errors::ApiErrorResponse::InvalidDataFormat { 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 8a7ed5c8e2b..01efc6a0886 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -75,7 +75,7 @@ impl })? } - if request.amount.is_greater_than(payment_intent.amount) { + if payment_intent.amount > request.amount { Err(errors::ApiErrorResponse::PreconditionFailed { message: "Amount should be greater than original authorized amount".to_owned(), })? @@ -144,8 +144,8 @@ impl frm_message: None, payment_link_data: None, incremental_authorization_details: Some(IncrementalAuthorizationDetails { - additional_amount: request.amount.subtract(amount).get_amount_as_i64(), - total_amount: request.amount.get_amount_as_i64(), + additional_amount: request.amount - amount, + total_amount: request.amount, reason: request.reason.clone(), authorization_id: None, }), @@ -218,7 +218,7 @@ impl UpdateTracker, PaymentsIncrementalAut error_code: None, error_message: None, connector_authorization_id: None, - previously_authorized_amount: payment_data.payment_intent.amount.get_amount_as_i64(), + previously_authorized_amount: payment_data.payment_intent.amount, }; let authorization = db .store diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 19a12e70a4a..989722fc812 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -151,7 +151,10 @@ where connector_meta_data: merchant_connector_account.get_metadata(), request: T::try_from(additional_data)?, response, - amount_captured: payment_data.payment_intent.amount_captured, + amount_captured: payment_data + .payment_intent + .amount_captured + .map(|amt| amt.get_amount_as_i64()), access_token: None, session_token: None, reference_id: None, @@ -1246,25 +1249,25 @@ impl TryFrom> api::GetToken::Connector, payment_data.payment_attempt.merchant_connector_id.clone(), )?; + let total_amount = payment_data + .incremental_authorization_details + .clone() + .map(|details| details.total_amount) + .ok_or( + report!(errors::ApiErrorResponse::InternalServerError) + .attach_printable("missing incremental_authorization_details in payment_data"), + )?; + let additional_amount = payment_data + .incremental_authorization_details + .clone() + .map(|details| details.additional_amount) + .ok_or( + report!(errors::ApiErrorResponse::InternalServerError) + .attach_printable("missing incremental_authorization_details in payment_data"), + )?; Ok(Self { - total_amount: payment_data - .incremental_authorization_details - .clone() - .map(|details| details.total_amount) - .ok_or( - report!(errors::ApiErrorResponse::InternalServerError).attach_printable( - "missing incremental_authorization_details in payment_data", - ), - )?, - additional_amount: payment_data - .incremental_authorization_details - .clone() - .map(|details| details.additional_amount) - .ok_or( - report!(errors::ApiErrorResponse::InternalServerError).attach_printable( - "missing incremental_authorization_details in payment_data", - ), - )?, + total_amount: total_amount.get_amount_as_i64(), + additional_amount: additional_amount.get_amount_as_i64(), reason: payment_data .incremental_authorization_details .and_then(|details| details.reason), diff --git a/crates/router/src/core/payments/types.rs b/crates/router/src/core/payments/types.rs index e87e48f04b4..3bc706f38e7 100644 --- a/crates/router/src/core/payments/types.rs +++ b/crates/router/src/core/payments/types.rs @@ -128,7 +128,7 @@ impl MultipleCaptureData { authorized_amount: common_types::MinorUnit, ) -> storage_enums::AttemptStatus { let total_captured_amount = self.get_total_charged_amount(); - if authorized_amount.is_equal(total_captured_amount) { + if authorized_amount == total_captured_amount { return storage_enums::AttemptStatus::Charged; } let status_count_map = self.get_status_count(); @@ -207,18 +207,11 @@ impl From<(&RequestSurchargeDetails, &PaymentAttempt)> for SurchargeDetails { let tax_on_surcharge_amount = request_surcharge_details.tax_amount.unwrap_or_default(); Self { original_amount: payment_attempt.amount, - surcharge: common_types::Surcharge::Fixed( - request_surcharge_details - .surcharge_amount - .get_amount_as_i64(), - ), // need to check this + surcharge: common_types::Surcharge::Fixed(request_surcharge_details.surcharge_amount), // need to check this tax_on_surcharge: None, surcharge_amount, tax_on_surcharge_amount, - final_amount: payment_attempt - .amount - .add(surcharge_amount) - .add(tax_on_surcharge_amount), + final_amount: payment_attempt.amount + surcharge_amount + tax_on_surcharge_amount, } } } @@ -239,10 +232,8 @@ impl ForeignTryFrom<(&SurchargeDetails, &PaymentAttempt)> for SurchargeDetailsRe 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 - .add(surcharge_details.tax_on_surcharge_amount)) - .get_amount_as_i64(), + (surcharge_details.surcharge_amount + surcharge_details.tax_on_surcharge_amount) + .get_amount_as_i64(), )?; Ok(Self { surcharge: surcharge_details.surcharge.clone().into(), @@ -260,16 +251,12 @@ impl SurchargeDetails { &self, request_surcharge_details: RequestSurchargeDetails, ) -> bool { - request_surcharge_details - .surcharge_amount - .is_equal(self.surcharge_amount) - && request_surcharge_details - .tax_amount - .unwrap_or_default() - .is_equal(self.tax_on_surcharge_amount) + request_surcharge_details.surcharge_amount == self.surcharge_amount + && request_surcharge_details.tax_amount.unwrap_or_default() + == self.tax_on_surcharge_amount } pub fn get_total_surcharge_amount(&self) -> common_types::MinorUnit { - self.surcharge_amount.add(self.tax_on_surcharge_amount) + self.surcharge_amount + self.tax_on_surcharge_amount } } diff --git a/crates/router/src/core/payouts.rs b/crates/router/src/core/payouts.rs index 04a4f2dcc9a..1170d2a25cb 100644 --- a/crates/router/src/core/payouts.rs +++ b/crates/router/src/core/payouts.rs @@ -6,7 +6,7 @@ pub mod validator; use std::vec::IntoIter; use api_models::enums as api_enums; -use common_utils::{consts, crypto::Encryptable, ext_traits::ValueExt, pii}; +use common_utils::{consts, crypto::Encryptable, ext_traits::ValueExt, pii, types::MinorUnit}; use diesel_models::enums as storage_enums; use error_stack::{report, ResultExt}; #[cfg(feature = "olap")] @@ -365,10 +365,9 @@ pub async fn payouts_update_core( ), })); } - // Update DB with new data let payouts = payout_data.payouts.to_owned(); - let amount = common_utils::types::MinorUnit::from(req.amount.unwrap_or(api::Amount::Zero)) + let amount = MinorUnit::from(req.amount.unwrap_or(MinorUnit::new(payouts.amount).into())) .get_amount_as_i64(); let updated_payouts = storage::PayoutsUpdate::Update { amount, @@ -1966,8 +1965,7 @@ pub async fn payout_create_db_entries( } else { None }; - let amount = common_utils::types::MinorUnit::from(req.amount.unwrap_or(api::Amount::Zero)) - .get_amount_as_i64(); + let amount = MinorUnit::from(req.amount.unwrap_or(api::Amount::Zero)).get_amount_as_i64(); let payouts_req = storage::PayoutsNew { payout_id: payout_id.to_string(), merchant_id: merchant_id.to_string(), diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index 65715464481..237d8b62237 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -315,7 +315,9 @@ pub async fn construct_refund_router_data<'a, F>( address: PaymentAddress::default(), auth_type: payment_attempt.authentication_type.unwrap_or_default(), connector_meta_data: merchant_connector_account.get_metadata(), - amount_captured: payment_intent.amount_captured, + amount_captured: payment_intent + .amount_captured + .map(|amt| amt.get_amount_as_i64()), payment_method_status: None, request: types::RefundsData { refund_id: refund.refund_id.clone(), @@ -559,7 +561,9 @@ pub async fn construct_accept_dispute_router_data<'a>( address: PaymentAddress::default(), auth_type: payment_attempt.authentication_type.unwrap_or_default(), connector_meta_data: merchant_connector_account.get_metadata(), - amount_captured: payment_intent.amount_captured, + amount_captured: payment_intent + .amount_captured + .map(|amt| amt.get_amount_as_i64()), payment_method_status: None, request: types::AcceptDisputeRequestData { dispute_id: dispute.dispute_id.clone(), @@ -653,7 +657,9 @@ pub async fn construct_submit_evidence_router_data<'a>( address: PaymentAddress::default(), auth_type: payment_attempt.authentication_type.unwrap_or_default(), connector_meta_data: merchant_connector_account.get_metadata(), - amount_captured: payment_intent.amount_captured, + amount_captured: payment_intent + .amount_captured + .map(|amt| amt.get_amount_as_i64()), request: submit_evidence_request_data, response: Err(ErrorResponse::default()), access_token: None, @@ -745,7 +751,9 @@ pub async fn construct_upload_file_router_data<'a>( address: PaymentAddress::default(), auth_type: payment_attempt.authentication_type.unwrap_or_default(), connector_meta_data: merchant_connector_account.get_metadata(), - amount_captured: payment_intent.amount_captured, + amount_captured: payment_intent + .amount_captured + .map(|amt| amt.get_amount_as_i64()), payment_method_status: None, request: types::UploadFileRequestData { file_key, @@ -841,7 +849,9 @@ pub async fn construct_defend_dispute_router_data<'a>( address: PaymentAddress::default(), auth_type: payment_attempt.authentication_type.unwrap_or_default(), connector_meta_data: merchant_connector_account.get_metadata(), - amount_captured: payment_intent.amount_captured, + amount_captured: payment_intent + .amount_captured + .map(|amt| amt.get_amount_as_i64()), payment_method_status: None, request: types::DefendDisputeRequestData { dispute_id: dispute.dispute_id.clone(), diff --git a/crates/router/src/services/kafka/payment_attempt.rs b/crates/router/src/services/kafka/payment_attempt.rs index f5a8c153bc3..dfa7da0d0a4 100644 --- a/crates/router/src/services/kafka/payment_attempt.rs +++ b/crates/router/src/services/kafka/payment_attempt.rs @@ -12,14 +12,14 @@ pub struct KafkaPaymentAttempt<'a> { pub merchant_id: &'a String, pub attempt_id: &'a String, pub status: storage_enums::AttemptStatus, - pub amount: i64, + pub amount: MinorUnit, pub currency: Option, pub save_to_locker: Option, pub connector: Option<&'a String>, pub error_message: Option<&'a String>, - pub offer_amount: Option, - pub surcharge_amount: Option, - pub tax_amount: Option, + pub offer_amount: Option, + pub surcharge_amount: Option, + pub tax_amount: Option, pub payment_method_id: Option<&'a String>, pub payment_method: Option, pub connector_transaction_id: Option<&'a String>, @@ -35,7 +35,7 @@ pub struct KafkaPaymentAttempt<'a> { #[serde(default, with = "time::serde::timestamp::option")] pub last_synced: Option, pub cancellation_reason: Option<&'a String>, - pub amount_to_capture: Option, + pub amount_to_capture: Option, pub mandate_id: Option<&'a String>, pub browser_info: Option, pub error_code: Option<&'a String>, @@ -46,9 +46,9 @@ pub struct KafkaPaymentAttempt<'a> { pub payment_method_data: Option, pub error_reason: Option<&'a String>, pub multiple_capture_count: Option, - pub amount_capturable: i64, + pub amount_capturable: MinorUnit, pub merchant_connector_id: Option<&'a String>, - pub net_amount: i64, + pub net_amount: MinorUnit, pub unified_code: Option<&'a String>, pub unified_message: Option<&'a String>, pub mandate_data: Option<&'a MandateDetails>, @@ -61,14 +61,14 @@ impl<'a> KafkaPaymentAttempt<'a> { merchant_id: &attempt.merchant_id, attempt_id: &attempt.attempt_id, status: attempt.status, - amount: attempt.amount.get_amount_as_i64(), + amount: attempt.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: MinorUnit::get_optional_amount_as_i64(attempt.offer_amount), - surcharge_amount: MinorUnit::get_optional_amount_as_i64(attempt.surcharge_amount), - tax_amount: MinorUnit::get_optional_amount_as_i64(attempt.tax_amount), + offer_amount: attempt.offer_amount, + surcharge_amount: attempt.surcharge_amount, + tax_amount: attempt.tax_amount, payment_method_id: attempt.payment_method_id.as_ref(), payment_method: attempt.payment_method, connector_transaction_id: attempt.connector_transaction_id.as_ref(), @@ -80,7 +80,7 @@ impl<'a> KafkaPaymentAttempt<'a> { modified_at: attempt.modified_at.assume_utc(), last_synced: attempt.last_synced.map(|i| i.assume_utc()), cancellation_reason: attempt.cancellation_reason.as_ref(), - amount_to_capture: MinorUnit::get_optional_amount_as_i64(attempt.amount_to_capture), + amount_to_capture: attempt.amount_to_capture, mandate_id: attempt.mandate_id.as_ref(), browser_info: attempt.browser_info.as_ref().map(|v| v.to_string()), error_code: attempt.error_code.as_ref(), @@ -90,9 +90,9 @@ impl<'a> KafkaPaymentAttempt<'a> { payment_method_data: attempt.payment_method_data.as_ref().map(|v| v.to_string()), error_reason: attempt.error_reason.as_ref(), multiple_capture_count: attempt.multiple_capture_count, - amount_capturable: attempt.amount_capturable.get_amount_as_i64(), + amount_capturable: attempt.amount_capturable, merchant_connector_id: attempt.merchant_connector_id.as_ref(), - net_amount: attempt.net_amount.get_amount_as_i64(), + net_amount: attempt.net_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 c11aaea0365..7363e92303a 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -693,7 +693,10 @@ impl Capturable for PaymentsCancelData { F: Clone, { // return previously captured amount - MinorUnit::get_optional_amount_as_i64(payment_data.payment_intent.amount_captured) + payment_data + .payment_intent + .amount_captured + .map(|amt| amt.get_amount_as_i64()) } fn get_amount_capturable( &self, @@ -739,12 +742,11 @@ impl Capturable for PaymentsSyncData { where F: Clone, { - MinorUnit::get_optional_amount_as_i64( - payment_data - .payment_attempt - .amount_to_capture - .or_else(|| Some(payment_data.payment_attempt.get_total_amount())), - ) + payment_data + .payment_attempt + .amount_to_capture + .or_else(|| Some(payment_data.payment_attempt.get_total_amount())) + .map(|amt| amt.get_amount_as_i64()) } fn get_amount_capturable( &self, @@ -1255,7 +1257,7 @@ impl From for ErrorResponse { impl From<&&mut PaymentsAuthorizeRouterData> for AuthorizeSessionTokenData { fn from(data: &&mut PaymentsAuthorizeRouterData) -> Self { Self { - amount_to_capture: MinorUnit::get_optional_amount_as_i64(data.amount_captured), + amount_to_capture: data.amount_captured, currency: data.request.currency, connector_transaction_id: data.payment_id.clone(), amount: Some(data.request.amount), diff --git a/crates/router/src/types/api/payment_link.rs b/crates/router/src/types/api/payment_link.rs index 02e7a87ffc6..85cb539d411 100644 --- a/crates/router/src/types/api/payment_link.rs +++ b/crates/router/src/types/api/payment_link.rs @@ -23,7 +23,7 @@ impl PaymentLinkResponseExt for RetrievePaymentLinkResponse { Ok(Self { link_to_pay: payment_link.link_to_pay, payment_link_id: payment_link.payment_link_id, - amount: common_utils::types::MinorUnit::new(payment_link.amount), + amount: payment_link.amount, description: payment_link.description, created_at: payment_link.created_at, merchant_id: payment_link.merchant_id, diff --git a/crates/router/src/types/storage/payment_attempt.rs b/crates/router/src/types/storage/payment_attempt.rs index 398bd25604e..2884f3423db 100644 --- a/crates/router/src/types/storage/payment_attempt.rs +++ b/crates/router/src/types/storage/payment_attempt.rs @@ -69,8 +69,8 @@ impl PaymentAttemptExt for PaymentAttempt { } fn get_total_amount(&self) -> MinorUnit { self.amount - .add(self.surcharge_amount.unwrap_or_default()) - .add(self.tax_amount.unwrap_or_default()) + + self.surcharge_amount.unwrap_or_default() + + self.tax_amount.unwrap_or_default() } } diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index af65ba6caa9..42ba7737572 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -777,7 +777,7 @@ impl ForeignFrom for payments::IncrementalAuthorizationR fn foreign_from(authorization: storage::Authorization) -> Self { Self { authorization_id: authorization.authorization_id, - amount: MinorUnit::new(authorization.amount), + amount: authorization.amount, status: authorization.status, error_code: authorization.error_code, error_message: authorization.error_message, @@ -1087,7 +1087,7 @@ impl ForeignFrom<(storage::PaymentLink, payments::PaymentLinkStatus)> payment_link_id: payment_link_config.payment_link_id, merchant_id: payment_link_config.merchant_id, link_to_pay: payment_link_config.link_to_pay, - amount: MinorUnit::new(payment_link_config.amount), + amount: payment_link_config.amount, created_at: payment_link_config.created_at, expiry: payment_link_config.fulfilment_time, description: payment_link_config.description, diff --git a/crates/router/src/utils/user/sample_data.rs b/crates/router/src/utils/user/sample_data.rs index 19ecc9a87bb..4fa544e7341 100644 --- a/crates/router/src/utils/user/sample_data.rs +++ b/crates/router/src/utils/user/sample_data.rs @@ -192,9 +192,7 @@ pub async fn generate_sample_data( ), attempt_count: 1, customer_id: Some("hs-dashboard-user".to_string()), - amount_captured: common_utils::types::MinorUnit::optional_new_from_i64_amount( - amount * 100, - ), + amount_captured: Some(common_utils::types::MinorUnit::new(amount * 100)), profile_id: Some(profile_id.clone()), return_url: Default::default(), metadata: Default::default(), diff --git a/crates/router/src/workflows/payment_sync.rs b/crates/router/src/workflows/payment_sync.rs index 1ce5b50f8e1..14f372789ed 100644 --- a/crates/router/src/workflows/payment_sync.rs +++ b/crates/router/src/workflows/payment_sync.rs @@ -127,7 +127,7 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow { error_reason: Some(Some( consts::REQUEST_TIMEOUT_ERROR_MESSAGE_FROM_PSYNC.to_string(), )), - amount_capturable: common_utils::types::MinorUnit::optional_new_from_i64_amount(0), + amount_capturable: Some(common_utils::types::MinorUnit::new(0)), updated_by: merchant_account.storage_scheme.to_string(), unified_code: None, unified_message: None, From 1b623a87723aafdb19141dbd477fc329be28efd1 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 17 May 2024 16:24:42 +0530 Subject: [PATCH 11/82] refactor(router): fixed clippy issue --- crates/common_utils/src/types.rs | 12 ++++++------ .../compatibility/stripe/payment_intents/types.rs | 2 +- crates/router/src/connector/utils.rs | 2 +- .../src/core/payments/operations/payment_response.rs | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 3d4691cc6c5..f436caaf720 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -295,16 +295,16 @@ where } impl Add for MinorUnit { - type Output = MinorUnit; - fn add(self, a2: MinorUnit) -> MinorUnit { - MinorUnit(self.0 + a2.0) + type Output = Self; + fn add(self, a2: Self) -> Self { + Self(self.0 + a2.0) } } impl Sub for MinorUnit { - type Output = MinorUnit; - fn sub(self, a2: MinorUnit) -> MinorUnit { - MinorUnit(self.0 - a2.0) + type Output = Self; + fn sub(self, a2: Self) -> Self { + Self(self.0 - a2.0) } } diff --git a/crates/router/src/compatibility/stripe/payment_intents/types.rs b/crates/router/src/compatibility/stripe/payment_intents/types.rs index 6ad596e171a..d615acff1ca 100644 --- a/crates/router/src/compatibility/stripe/payment_intents/types.rs +++ b/crates/router/src/compatibility/stripe/payment_intents/types.rs @@ -327,7 +327,7 @@ impl TryFrom for payments::PaymentsRequest { field_name: "currency", })?, capture_method: item.capture_method, - amount_to_capture: item.amount_capturable.map(|amt| MinorUnit::new(amt)), + amount_to_capture: item.amount_capturable.map(MinorUnit::new), confirm: item.confirm, customer_id: item.customer, email: item.receipt_email, diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 61faec10f08..7a9c6638589 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -147,7 +147,7 @@ where let captured_amount = types::Capturable::get_captured_amount(&self.request, payment_data); let total_capturable_amount = payment_data.payment_attempt.get_total_amount(); - if Some(total_capturable_amount) == captured_amount.map(|amt| MinorUnit::new(amt)) { + if Some(total_capturable_amount) == captured_amount.map(MinorUnit::new) { enums::AttemptStatus::Charged } else if captured_amount.is_some() { enums::AttemptStatus::PartialCharged diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 02b5d8cbd71..6723a2ee5af 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -797,7 +797,7 @@ async fn payment_response_update_tracker( amount_capturable: router_data .request .get_amount_capturable(&payment_data, status) - .map(|amt| MinorUnit::new(amt)), + .map(MinorUnit::new), updated_by: storage_scheme.to_string(), unified_code: option_gsm.clone().map(|gsm| gsm.unified_code), unified_message: option_gsm.map(|gsm| gsm.unified_message), @@ -944,7 +944,7 @@ async fn payment_response_update_tracker( amount_capturable: router_data .request .get_amount_capturable(&payment_data, updated_attempt_status) - .map(|amt| MinorUnit::new(amt)), + .map(MinorUnit::new), payment_method_id, mandate_id: payment_data.payment_attempt.mandate_id.clone(), connector_metadata, @@ -1102,7 +1102,7 @@ async fn payment_response_update_tracker( let amount_captured = get_total_amount_captured( &router_data.request, - router_data.amount_captured.map(|amt| MinorUnit::new(amt)), + router_data.amount_captured.map(MinorUnit::new), router_data.status, &payment_data, ); @@ -1370,7 +1370,7 @@ fn get_total_amount_captured( //Non multiple capture let amount = request .get_captured_amount(payment_data) - .map(|amt| MinorUnit::new(amt)); + .map(MinorUnit::new); amount_captured.or_else(|| { if router_data_status == enums::AttemptStatus::Charged { amount From eff793fb0c29211ba6791f91fbeec2f68e0d80a2 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 17 May 2024 16:57:34 +0530 Subject: [PATCH 12/82] refactor(router): fixed clippy issue --- crates/common_utils/src/types.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index f436caaf720..d99f0be9de7 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -205,7 +205,7 @@ impl FromSql for SemanticVersion where serde_json::Value: FromSql, { - fn from_sql(bytes: DB::RawValue<'_>) -> diesel::deserialize::Result { + fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result { let value = >::from_sql(bytes)?; Ok(serde_json::from_value(value)?) } @@ -238,7 +238,7 @@ where Eq, Hash, )] -#[diesel(sql_type = diesel::sql_types::BigInt)] +#[diesel(sql_type = sql_types::BigInt)] pub struct MinorUnit(i64); impl MinorUnit { @@ -250,7 +250,6 @@ impl MinorUnit { /// forms a new minor unit from amount pub fn new(value: i64) -> Self { - // remove in future Self(value) } } From bce3de03d3b54e31aeae8184e29fafbb5f949941 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 17 May 2024 17:09:40 +0530 Subject: [PATCH 13/82] refactor(router): fixed open-api-specs --- crates/api_models/src/payments.rs | 16 +++++++++---- openapi/openapi_spec.json | 39 +++++++++---------------------- 2 files changed, 22 insertions(+), 33 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 113ff9a07d9..95660ea91fe 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -484,6 +484,7 @@ impl PaymentsRequest { Default, Debug, Clone, serde::Serialize, serde::Deserialize, Copy, ToSchema, PartialEq, )] pub struct RequestSurchargeDetails { + #[schema(value_type = MinorUnit, example = 6540)] pub surcharge_amount: MinorUnit, pub tax_amount: Option, } @@ -561,6 +562,7 @@ pub struct PaymentAttemptResponse { #[schema(value_type = AttemptStatus, example = "charged")] pub status: enums::AttemptStatus, /// The payment attempt amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., + #[schema(value_type = MinorUnit, example = 6540)] pub amount: MinorUnit, /// The currency of the amount of the payment attempt #[schema(value_type = Option, example = "USD")] @@ -615,6 +617,7 @@ pub struct CaptureResponse { #[schema(value_type = CaptureStatus, example = "charged")] pub status: enums::CaptureStatus, /// The capture amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., + #[schema(value_type = MinorUnit, example = 6540)] pub amount: MinorUnit, /// The currency of the amount of the capture #[schema(value_type = Option, example = "USD")] @@ -809,7 +812,7 @@ pub struct SingleUseMandate { #[derive(Clone, Eq, PartialEq, Debug, Default, ToSchema, serde::Serialize, serde::Deserialize)] pub struct MandateAmountData { /// The maximum amount to be debited for the mandate transaction - #[schema(example = 6540)] + #[schema(value_type = MinorUnit, example = 6540)] pub amount: MinorUnit, /// The currency for the transaction #[schema(value_type = Currency, example = "USD")] @@ -2874,6 +2877,7 @@ pub struct PaymentsCaptureRequest { /// The unique identifier for the merchant pub merchant_id: Option, /// The Amount to be captured/ debited from the user's payment method. + #[schema(value_type = MinorUnit, example = 6540)] pub amount_to_capture: Option, /// Decider to refund the uncaptured amount pub refund_uncaptured_amount: Option, @@ -3127,20 +3131,20 @@ pub struct PaymentsResponse { pub status: api_enums::IntentStatus, /// 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., - #[schema(example = 100)] + #[schema(value_type = MinorUnit, example = 6540)] pub amount: MinorUnit, /// 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)] + #[schema(value_type = MinorUnit, example = 6540)] pub net_amount: MinorUnit, /// The maximum amount that could be captured from the payment - #[schema(minimum = 100, example = 6540)] + #[schema(value_type = MinorUnit, minimum = 100, example = 6540)] pub amount_capturable: Option, /// The amount which is already captured from the payment - #[schema(minimum = 100, example = 6540)] + #[schema(value_type = MinorUnit, example = 6540)] pub amount_received: Option, /// The connector used for the payment @@ -3495,6 +3499,7 @@ pub struct IncrementalAuthorizationResponse { /// The unique identifier of authorization pub authorization_id: String, /// Amount the authorization has been made for + #[schema(value_type = MinorUnit, example = 6540)] pub amount: MinorUnit, #[schema(value_type= AuthorizationStatus)] /// The status of the authorization @@ -4651,6 +4656,7 @@ pub struct RetrievePaymentLinkResponse { pub payment_link_id: String, pub merchant_id: String, pub link_to_pay: String, + #[schema(value_type = MinorUnit, example = 6540)] pub amount: MinorUnit, #[serde(with = "common_utils::custom_serde::iso8601")] pub created_at: PrimitiveDateTime, diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 4d5b2497f97..598d41a866a 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -10077,9 +10077,7 @@ "nullable": true }, "previously_authorized_amount": { - "type": "integer", - "format": "int64", - "description": "Previously authorized amount for the payment" + "$ref": "#/components/schemas/MinorUnit" } } }, @@ -13468,6 +13466,9 @@ }, "PaymentsCaptureRequest": { "type": "object", + "required": [ + "amount_to_capture" + ], "properties": { "merchant_id": { "type": "string", @@ -13475,12 +13476,7 @@ "nullable": true }, "amount_to_capture": { - "allOf": [ - { - "$ref": "#/components/schemas/MinorUnit" - } - ], - "nullable": true + "$ref": "#/components/schemas/MinorUnit" }, "refund_uncaptured_amount": { "type": "boolean", @@ -14365,10 +14361,7 @@ ], "properties": { "amount": { - "type": "integer", - "format": "int64", - "description": "The total amount including previously authorized amount and additional amount", - "example": 6540 + "$ref": "#/components/schemas/MinorUnit" }, "reason": { "type": "string", @@ -14798,6 +14791,8 @@ "status", "amount", "net_amount", + "amount_capturable", + "amount_received", "currency", "payment_method", "attempt_count" @@ -14833,20 +14828,10 @@ "$ref": "#/components/schemas/MinorUnit" }, "amount_capturable": { - "allOf": [ - { - "$ref": "#/components/schemas/MinorUnit" - } - ], - "nullable": true + "$ref": "#/components/schemas/MinorUnit" }, "amount_received": { - "allOf": [ - { - "$ref": "#/components/schemas/MinorUnit" - } - ], - "nullable": true + "$ref": "#/components/schemas/MinorUnit" }, "connector": { "type": "string", @@ -18232,9 +18217,7 @@ ] }, "value": { - "type": "integer", - "format": "int64", - "description": "Fixed Surcharge value" + "$ref": "#/components/schemas/MinorUnit" } } }, From 63ef54ce1df97e8b393d3215066e66e3addb37f2 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 17 May 2024 17:23:37 +0530 Subject: [PATCH 14/82] refactor(router): fixed open-api specs --- Cargo.lock | 2 ++ crates/common_utils/Cargo.toml | 1 + crates/common_utils/src/types.rs | 3 ++- crates/openapi/Cargo.toml | 1 + crates/openapi/src/openapi.rs | 1 + openapi/openapi_spec.json | 5 +++++ 6 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 5ba2d0dae6d..bc4815e8b07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1978,6 +1978,7 @@ dependencies = [ "thiserror", "time", "tokio 1.37.0", + "utoipa", "uuid", ] @@ -4527,6 +4528,7 @@ name = "openapi" version = "0.1.0" dependencies = [ "api_models", + "common_utils", "serde_json", "utoipa", ] diff --git a/crates/common_utils/Cargo.toml b/crates/common_utils/Cargo.toml index 6f08649fbda..e6fd27da31a 100644 --- a/crates/common_utils/Cargo.toml +++ b/crates/common_utils/Cargo.toml @@ -40,6 +40,7 @@ time = { version = "0.3.35", features = ["serde", "serde-well-known", "std"] } tokio = { version = "1.37.0", features = ["macros", "rt-multi-thread"], optional = true } semver = { version = "1.0.22", features = ["serde"] } uuid = { version = "1.8.0", features = ["v7"] } +utoipa = { version = "4.2.0", features = ["preserve_order", "preserve_path_order"] } # First party crates common_enums = { version = "0.1.0", path = "../common_enums" } diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index d99f0be9de7..d5a57a45b9d 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -5,7 +5,7 @@ use std::{ primitive::i64, str::FromStr, }; - +use utoipa::ToSchema; use diesel::{ backend::Backend, deserialize, @@ -237,6 +237,7 @@ where PartialEq, Eq, Hash, + ToSchema )] #[diesel(sql_type = sql_types::BigInt)] pub struct MinorUnit(i64); diff --git a/crates/openapi/Cargo.toml b/crates/openapi/Cargo.toml index 8cf8c156ba0..b8c55084a50 100644 --- a/crates/openapi/Cargo.toml +++ b/crates/openapi/Cargo.toml @@ -12,3 +12,4 @@ serde_json = "1.0.115" utoipa = { version = "4.2.0", features = ["preserve_order", "preserve_path_order", "time"] } api_models = { version = "0.1.0", path = "../api_models", features = ["frm", "payouts", "openapi"] } +common_utils = {version = "0.1.0", path = "../common_utils"} diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index 5f5597387b1..8af2737b5c1 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -183,6 +183,7 @@ Never share your secret api keys. Keep them guarded and secure. routes::poll::retrieve_poll_status, ), components(schemas( + common_utils::types::MinorUnit, api_models::refunds::RefundRequest, api_models::refunds::RefundType, api_models::refunds::RefundResponse, diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 598d41a866a..efd7a0efda6 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -11527,6 +11527,11 @@ } } }, + "MinorUnit": { + "type": "integer", + "format": "int64", + "description": "This Unit struct represents MinorUnit in which core amount works" + }, "MobilePayRedirection": { "type": "object" }, From 17c58f4defcfc454c62882391c503ed19dd558ec Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 11:54:34 +0000 Subject: [PATCH 15/82] chore: run formatter --- crates/common_utils/src/types.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index d5a57a45b9d..0118d315a6d 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -5,7 +5,7 @@ use std::{ primitive::i64, str::FromStr, }; -use utoipa::ToSchema; + use diesel::{ backend::Backend, deserialize, @@ -18,6 +18,7 @@ use diesel::{ use error_stack::{report, ResultExt}; use semver::Version; use serde::{de::Visitor, Deserialize, Deserializer}; +use utoipa::ToSchema; use crate::{ consts, @@ -237,7 +238,7 @@ where PartialEq, Eq, Hash, - ToSchema + ToSchema, )] #[diesel(sql_type = sql_types::BigInt)] pub struct MinorUnit(i64); From f76ba1d46e862e1bd08e772157e43fb0e0ce0c27 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 17 May 2024 17:40:21 +0530 Subject: [PATCH 16/82] refactor(router): fixed clippy issue --- .../router/src/core/payments/operations/payment_create.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index abf77ad5396..8d22c8fb097 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -882,7 +882,7 @@ impl PaymentCreate { attempt_id, status, currency, - amount: common_utils::types::MinorUnit::from(amount), + amount: MinorUnit::from(amount), payment_method, capture_method: request.capture_method, capture_on: request.capture_on, @@ -1000,7 +1000,7 @@ impl PaymentCreate { payment_id: payment_id.to_string(), merchant_id: merchant_account.merchant_id.to_string(), status, - amount: common_utils::types::MinorUnit::from(amount), + amount: MinorUnit::from(amount), currency, description: request.description.clone(), created_at, @@ -1112,7 +1112,7 @@ async fn create_payment_link( payment_id: payment_id.clone(), merchant_id: merchant_id.clone(), link_to_pay: payment_link.clone(), - amount: common_utils::types::MinorUnit::from(amount), + amount: MinorUnit::from(amount), currency: request.currency, created_at, last_modified_at, From 59ffc34771813f780087193c3aced4baa1627b47 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 17 May 2024 19:50:06 +0530 Subject: [PATCH 17/82] refactor(router): resolved comments --- crates/common_utils/src/types.rs | 11 ++++++----- crates/diesel_models/src/capture.rs | 9 +++++---- crates/router/src/connector/utils.rs | 2 +- crates/router/src/core/payments/types.rs | 12 ++++++------ crates/router/src/types.rs | 6 +++--- crates/router/src/types/storage/payment_attempt.rs | 2 +- crates/router/src/types/transformers.rs | 2 +- 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 0118d315a6d..1b3b067c58f 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -239,6 +239,7 @@ where Eq, Hash, ToSchema, + PartialOrd, )] #[diesel(sql_type = sql_types::BigInt)] pub struct MinorUnit(i64); @@ -309,8 +310,8 @@ impl Sub for MinorUnit { } } -impl PartialOrd for MinorUnit { - fn partial_cmp(&self, a2: &Self) -> Option { - Some(self.0.cmp(&a2.0)) - } -} +// impl PartialOrd for MinorUnit { +// fn partial_cmp(&self, a2: &Self) -> Option { +// Some(self.0.cmp(&a2.0)) +// } +// } diff --git a/crates/diesel_models/src/capture.rs b/crates/diesel_models/src/capture.rs index adc313ca3dd..0a66ae789aa 100644 --- a/crates/diesel_models/src/capture.rs +++ b/crates/diesel_models/src/capture.rs @@ -1,3 +1,4 @@ +use common_utils::types::MinorUnit; use diesel::{AsChangeset, Identifiable, Insertable, Queryable}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; @@ -12,13 +13,13 @@ pub struct Capture { pub payment_id: String, pub merchant_id: String, pub status: storage_enums::CaptureStatus, - pub amount: i64, + pub amount: MinorUnit, pub currency: Option, pub connector: String, pub error_message: Option, pub error_code: Option, pub error_reason: Option, - pub tax_amount: Option, + pub tax_amount: Option, #[serde(with = "common_utils::custom_serde::iso8601")] pub created_at: PrimitiveDateTime, #[serde(with = "common_utils::custom_serde::iso8601")] @@ -37,13 +38,13 @@ pub struct CaptureNew { pub payment_id: String, pub merchant_id: String, pub status: storage_enums::CaptureStatus, - pub amount: i64, + pub amount: MinorUnit, pub currency: Option, pub connector: String, pub error_message: Option, pub error_code: Option, pub error_reason: Option, - pub tax_amount: Option, + pub tax_amount: Option, #[serde(with = "common_utils::custom_serde::iso8601")] pub created_at: PrimitiveDateTime, #[serde(with = "common_utils::custom_serde::iso8601")] diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 7a9c6638589..edef2ca8bff 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -1985,7 +1985,7 @@ where status: capture_sync_response.get_capture_attempt_status(), connector_response_reference_id: capture_sync_response .get_connector_reference_id(), - amount: capture_sync_response.get_amount_captured(), + amount: capture_sync_response.get_amount_captured().map(|amt| MinorUnit::new(amt)), }, ); } diff --git a/crates/router/src/core/payments/types.rs b/crates/router/src/core/payments/types.rs index 3bc706f38e7..af594ea93f9 100644 --- a/crates/router/src/core/payments/types.rs +++ b/crates/router/src/core/payments/types.rs @@ -81,26 +81,26 @@ impl MultipleCaptureData { } } pub fn get_total_blocked_amount(&self) -> common_types::MinorUnit { - common_types::MinorUnit::new(self.all_captures.iter().fold(0, |accumulator, capture| { + self.all_captures.iter().fold(common_types::MinorUnit::new(0), |accumulator, capture| { accumulator + match capture.1.status { storage_enums::CaptureStatus::Charged | storage_enums::CaptureStatus::Pending => capture.1.amount, storage_enums::CaptureStatus::Started - | storage_enums::CaptureStatus::Failed => 0, + | storage_enums::CaptureStatus::Failed => common_types::MinorUnit::new(0), } - })) + }) } pub fn get_total_charged_amount(&self) -> common_types::MinorUnit { - common_types::MinorUnit::new(self.all_captures.iter().fold(0, |accumulator, capture| { + self.all_captures.iter().fold(common_types::MinorUnit::new(0), |accumulator, capture| { accumulator + match capture.1.status { storage_enums::CaptureStatus::Charged => capture.1.amount, storage_enums::CaptureStatus::Pending | storage_enums::CaptureStatus::Started - | storage_enums::CaptureStatus::Failed => 0, + | storage_enums::CaptureStatus::Failed => common_types::MinorUnit::new(0), } - })) + }) } pub fn get_captures_count(&self) -> RouterResult { i16::try_from(self.all_captures.len()) diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 7363e92303a..0afef760517 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -781,19 +781,19 @@ pub enum CaptureSyncResponse { resource_id: ResponseId, status: storage_enums::AttemptStatus, connector_response_reference_id: Option, - amount: Option, + amount: Option, }, Error { code: String, message: String, reason: Option, status_code: u16, - amount: Option, + amount: Option, }, } impl CaptureSyncResponse { - pub fn get_amount_captured(&self) -> Option { + pub fn get_amount_captured(&self) -> Option { match self { Self::Success { amount, .. } | Self::Error { amount, .. } => *amount, } diff --git a/crates/router/src/types/storage/payment_attempt.rs b/crates/router/src/types/storage/payment_attempt.rs index 2884f3423db..4ad45f554ce 100644 --- a/crates/router/src/types/storage/payment_attempt.rs +++ b/crates/router/src/types/storage/payment_attempt.rs @@ -33,7 +33,7 @@ impl PaymentAttemptExt for PaymentAttempt { merchant_id: self.merchant_id.clone(), capture_id: self.get_next_capture_id(), status: capture_status, - amount: capture_amount.get_amount_as_i64(), + amount: capture_amount, currency: self.currency, connector: self .connector diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 42ba7737572..7ec1ff0b58c 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -939,7 +939,7 @@ impl ForeignFrom for payments::CaptureResponse { Self { capture_id: capture.capture_id, status: capture.status, - amount: MinorUnit::new(capture.amount), + amount: capture.amount, currency: capture.currency, connector: capture.connector, authorized_attempt_id: capture.authorized_attempt_id, From 9ba21c4b7a174aa864077fb9ad597b1f3c8837e0 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 14:20:50 +0000 Subject: [PATCH 18/82] chore: run formatter --- crates/router/src/connector/utils.rs | 4 ++- crates/router/src/core/payments/types.rs | 40 +++++++++++++----------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index edef2ca8bff..7d940bab507 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -1985,7 +1985,9 @@ where status: capture_sync_response.get_capture_attempt_status(), connector_response_reference_id: capture_sync_response .get_connector_reference_id(), - amount: capture_sync_response.get_amount_captured().map(|amt| MinorUnit::new(amt)), + amount: capture_sync_response + .get_amount_captured() + .map(|amt| MinorUnit::new(amt)), }, ); } diff --git a/crates/router/src/core/payments/types.rs b/crates/router/src/core/payments/types.rs index af594ea93f9..71b7d84b9f9 100644 --- a/crates/router/src/core/payments/types.rs +++ b/crates/router/src/core/payments/types.rs @@ -81,26 +81,30 @@ impl MultipleCaptureData { } } pub fn get_total_blocked_amount(&self) -> common_types::MinorUnit { - self.all_captures.iter().fold(common_types::MinorUnit::new(0), |accumulator, capture| { - accumulator - + match capture.1.status { - storage_enums::CaptureStatus::Charged - | storage_enums::CaptureStatus::Pending => capture.1.amount, - storage_enums::CaptureStatus::Started - | storage_enums::CaptureStatus::Failed => common_types::MinorUnit::new(0), - } - }) + self.all_captures + .iter() + .fold(common_types::MinorUnit::new(0), |accumulator, capture| { + accumulator + + match capture.1.status { + storage_enums::CaptureStatus::Charged + | storage_enums::CaptureStatus::Pending => capture.1.amount, + storage_enums::CaptureStatus::Started + | storage_enums::CaptureStatus::Failed => common_types::MinorUnit::new(0), + } + }) } pub fn get_total_charged_amount(&self) -> common_types::MinorUnit { - self.all_captures.iter().fold(common_types::MinorUnit::new(0), |accumulator, capture| { - accumulator - + match capture.1.status { - storage_enums::CaptureStatus::Charged => capture.1.amount, - storage_enums::CaptureStatus::Pending - | storage_enums::CaptureStatus::Started - | storage_enums::CaptureStatus::Failed => common_types::MinorUnit::new(0), - } - }) + self.all_captures + .iter() + .fold(common_types::MinorUnit::new(0), |accumulator, capture| { + accumulator + + match capture.1.status { + storage_enums::CaptureStatus::Charged => capture.1.amount, + storage_enums::CaptureStatus::Pending + | storage_enums::CaptureStatus::Started + | storage_enums::CaptureStatus::Failed => common_types::MinorUnit::new(0), + } + }) } pub fn get_captures_count(&self) -> RouterResult { i16::try_from(self.all_captures.len()) From 3bce742b3424d630cf82637ce4a721ffb93cdfc5 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 17 May 2024 19:51:23 +0530 Subject: [PATCH 19/82] refactor(router): resolved comments --- crates/common_utils/src/types.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 1b3b067c58f..6574d1f1af4 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -309,9 +309,3 @@ impl Sub for MinorUnit { Self(self.0 - a2.0) } } - -// impl PartialOrd for MinorUnit { -// fn partial_cmp(&self, a2: &Self) -> Option { -// Some(self.0.cmp(&a2.0)) -// } -// } From 23e9158174f0bdf4c2efcbd62acc21c343fd1b54 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 17 May 2024 23:56:10 +0530 Subject: [PATCH 20/82] refactor(router): fixed clippy issue --- crates/router/src/connector/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 7d940bab507..8ff7d350f24 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -1987,7 +1987,7 @@ where .get_connector_reference_id(), amount: capture_sync_response .get_amount_captured() - .map(|amt| MinorUnit::new(amt)), + .map(MinorUnit::new), }, ); } From 78d71ba7d21dce086185ed0a27a01506a75285bf Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 20 May 2024 19:45:26 +0530 Subject: [PATCH 21/82] feat(router 0 --- crates/common_utils/src/types.rs | 161 +++++++++++++++++- .../src/router_data.rs | 1 + crates/router/src/connector/stripe.rs | 25 ++- crates/router/src/services/api.rs | 1 + crates/router/src/types/api.rs | 2 +- 5 files changed, 182 insertions(+), 8 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 6574d1f1af4..a327b9d9b72 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -1,11 +1,8 @@ //! Types that can be used in other crates use std::{ - fmt::Display, - ops::{Add, Sub}, - primitive::i64, - str::FromStr, + fmt::Display, num::{ParseFloatError, TryFromIntError}, ops::{Add, Sub}, primitive::i64, str::FromStr }; - +use common_enums::enums; use diesel::{ backend::Backend, deserialize, @@ -255,6 +252,54 @@ impl MinorUnit { pub fn new(value: i64) -> Self { Self(value) } + + /// Convert the amount to its major denomination based on Currency and return String + pub fn to_major_unit_as_string(&self, currency: enums::Currency) -> Result { + let amount_f64 = self.to_major_unit_asf64(currency)?; + Ok(format!("{:.2}", amount_f64.0)) + } + + /// Convert the amount to its major denomination based on Currency and return f64 + pub fn to_major_unit_asf64(&self, currency: enums::Currency) -> Result { + let amount_f64: f64 = u32::try_from(self.0)?.into(); + let amount = if currency.is_zero_decimal_currency() { + amount_f64 + } else if currency.is_three_decimal_currency() { + amount_f64 / 1000.00 + } else { + amount_f64 / 100.00 + }; + Ok(FloatMajorUnit::new(amount)) + } + + ///Convert the higher decimal amount to its major absolute units + pub fn to_minor_unit_as_string(&self, currency: enums::Currency) -> Result { + let amount_f64 = self.0.to_string().parse::()?; + let amount_string = if currency.is_zero_decimal_currency() { + amount_f64 + } else if currency.is_three_decimal_currency() { + amount_f64 * 1000.00 + } else { + amount_f64 * 100.00 + }; + Ok(amount_string.to_string()) + } + + /// Convert the amount to its major denomination based on Currency and check for zero decimal currency and return String + /// Paypal Connector accepts Zero and Two decimal currency but not three decimal and it should be updated as required for 3 decimal currencies. + /// Paypal Ref - https://developer.paypal.com/docs/reports/reference/paypal-supported-currencies/ + pub fn to_major_unit_as_string_with_zero_decimal_check( + &self, + currency: enums::Currency, + ) -> Result { + let amount_f64 = self.to_major_unit_asf64(currency)?; + if currency.is_zero_decimal_currency() { + Ok(StringMajorUnit::new(amount_f64.0.to_string())) + } else { + let amount_string = format!("{:.2}", amount_f64.0); + Ok(StringMajorUnit::new(amount_string)) + } + } } impl Display for MinorUnit { @@ -309,3 +354,109 @@ impl Sub for MinorUnit { Self(self.0 - a2.0) } } + +/// This struct represents Money unit on which conversion will be done +#[derive( + Default, + Debug, + serde::Deserialize, + serde::Serialize, + Clone, + Copy, + PartialEq, + Eq, + Hash, + ToSchema, +)] +pub struct Money { + amount: MinorUnit, + currency: enums::Currency +} + +// connector amount unit +#[derive( + Default, + Debug, + serde::Deserialize, + serde::Serialize, + Clone, + Copy, + PartialEq, +)] +pub struct FloatMajorUnit(f64); + +impl FloatMajorUnit{ + /// forms a new major unit from amount + pub fn new(value: f64) -> Self { + Self(value) + } + + pub fn to_minor_unit_as_i64(&self, currency:enums::Currency) -> Result { + let amount_f64 = self.0; + let amount = if currency.is_zero_decimal_currency() { + amount_f64 + } else if currency.is_three_decimal_currency() { + amount_f64 * 1000.00 + } else { + amount_f64 * 100.00 + }; + Ok(MinorUnit::new(amount as i64)) + } +} +#[derive( + Default, + Debug, + serde::Deserialize, + serde::Serialize, + Clone, + PartialEq, + Eq, +)] +pub struct StringMajorUnit(String); + +impl StringMajorUnit { + /// forms a new major unit from amount + pub fn new(value: String) -> Self { + Self(value) + } + + pub fn to_minor_unit_as_i64(&self, currency:enums::Currency) -> Result { + let amount_f64 = self.0.parse::()?; + let amount = if currency.is_zero_decimal_currency() { + amount_f64 + } else if currency.is_three_decimal_currency() { + amount_f64 * 1000.00 + } else { + amount_f64 * 100.00 + }; + Ok(MinorUnit::new(amount as i64)) + } +} + + +pub trait AmountConvertor : Send { + type Output; + fn convert(&self, i: MinorUnit, currency:enums::Currency) -> Result; + fn convert_back(&self, i:Self::Output, currency:enums::Currency) -> Result; +} + +impl AmountConvertor for FloatMajorUnit { + type Output = FloatMajorUnit; + fn convert(&self, i: MinorUnit, currency: enums::Currency) -> Result { + i.to_major_unit_asf64(currency) + } + fn convert_back(&self, i: FloatMajorUnit, currency:enums::Currency) -> Result { + i.to_minor_unit_as_i64(currency) + } +} + +impl AmountConvertor for StringMajorUnit { + type Output = StringMajorUnit; + fn convert(&self, i: MinorUnit, currency: enums::Currency) -> Result { + i.to_major_unit_as_string_with_zero_decimal_check(currency) + } + fn convert_back(&self, i: StringMajorUnit, currency:enums::Currency) -> Result { + i.to_minor_unit_as_i64(currency) + } +} + diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs index cbaaeeda42b..f36c7e8606d 100644 --- a/crates/hyperswitch_domain_models/src/router_data.rs +++ b/crates/hyperswitch_domain_models/src/router_data.rs @@ -8,6 +8,7 @@ use crate::payment_address::PaymentAddress; pub struct RouterData { pub flow: PhantomData, pub merchant_id: String, + // pub amount : Option, pub customer_id: Option, pub connector_customer: Option, pub connector: String, diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs index b41c331b74b..69b0089f3a7 100644 --- a/crates/router/src/connector/stripe.rs +++ b/crates/router/src/connector/stripe.rs @@ -2,7 +2,7 @@ pub mod transformers; use std::{collections::HashMap, fmt::Debug, ops::Deref}; -use common_utils::request::RequestContent; +use common_utils::{request::RequestContent, types::AmountConvertor, types::FloatMajorUnit, types::MinorUnit}; use diesel_models::enums; use error_stack::ResultExt; use masking::PeekInterface; @@ -36,7 +36,25 @@ use crate::{ }; #[derive(Debug, Clone)] -pub struct Stripe; +pub struct Stripe{ + boxed_convert : Box> +} + +impl Stripe { + pub fn new() -> Self { + Self { + boxed_convert: Box::new(FloatMajorUnit::new), + } + } + + pub fn convert_amount(&self, i: MinorUnit, currency: enums::Currency) -> Result> { + self.boxed_convert.convert(i, currency).change_context(errors::ConnectorError::ParsingFailed) + } + + pub fn convert_back(&self, i: FloatMajorUnit, currency: enums::Currency) -> Result> { + self.boxed_convert.convert_back(i, currency).change_context(errors::ConnectorError::ParsingFailed) + } +} impl ConnectorCommonExt for Stripe where @@ -916,6 +934,8 @@ impl req: &types::PaymentsAuthorizeRouterData, _connectors: &settings::Connectors, ) -> CustomResult { + let sahkal = self.convert_amount(MinorUnit::new(23), req.request.currency)?; + let sahkal_back_convert = self.convert_back(FloatMajorUnit::new(1.00), req.request.currency)?; match &req.request.payment_method_data { domain::PaymentMethodData::BankTransfer(bank_transfer_data) => { stripe::get_bank_transfer_request_data(req, bank_transfer_data.deref()) @@ -2733,3 +2753,4 @@ impl self.build_error_response(res, event_builder) } } + diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 71c74099ded..65e4d931118 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -279,6 +279,7 @@ pub trait ConnectorIntegration: ConnectorIntegrationAny CustomResult, errors::ConnectorError> { Ok(None) } + } pub enum CaptureSyncMethod { diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 2013f482750..6f99789ce37 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -378,7 +378,7 @@ impl ConnectorData { enums::Connector::Shift4 => Ok(Box::new(&connector::Shift4)), enums::Connector::Square => Ok(Box::new(&connector::Square)), enums::Connector::Stax => Ok(Box::new(&connector::Stax)), - enums::Connector::Stripe => Ok(Box::new(&connector::Stripe)), + enums::Connector::Stripe => Ok(Box::new(&connector::Stripe::new())), enums::Connector::Wise => Ok(Box::new(&connector::Wise)), enums::Connector::Worldline => Ok(Box::new(&connector::Worldline)), enums::Connector::Worldpay => Ok(Box::new(&connector::Worldpay)), From d4c363f9311ae4cc1e479a352864da6eb27a2a7f Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Mon, 20 May 2024 20:46:03 +0530 Subject: [PATCH 22/82] wip: reduce errors --- crates/common_utils/src/types.rs | 136 +++++++++++------- crates/router/src/connector/stripe.rs | 37 +++-- crates/router/src/types/api.rs | 134 +++++++++-------- crates/router/src/types/api/authentication.rs | 2 +- .../router/src/types/api/verify_connector.rs | 2 +- 5 files changed, 180 insertions(+), 131 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index a327b9d9b72..28afbb79f99 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -1,7 +1,4 @@ //! Types that can be used in other crates -use std::{ - fmt::Display, num::{ParseFloatError, TryFromIntError}, ops::{Add, Sub}, primitive::i64, str::FromStr -}; use common_enums::enums; use diesel::{ backend::Backend, @@ -15,6 +12,13 @@ use diesel::{ use error_stack::{report, ResultExt}; use semver::Version; use serde::{de::Visitor, Deserialize, Deserializer}; +use std::{ + fmt::Display, + num::{ParseFloatError, TryFromIntError}, + ops::{Add, Sub}, + primitive::i64, + str::FromStr, +}; use utoipa::ToSchema; use crate::{ @@ -253,14 +257,20 @@ impl MinorUnit { Self(value) } - /// Convert the amount to its major denomination based on Currency and return String - pub fn to_major_unit_as_string(&self, currency: enums::Currency) -> Result { + /// Convert the amount to its major denomination based on Currency and return String + pub fn to_major_unit_as_string( + &self, + currency: enums::Currency, + ) -> Result { let amount_f64 = self.to_major_unit_asf64(currency)?; Ok(format!("{:.2}", amount_f64.0)) } /// Convert the amount to its major denomination based on Currency and return f64 - pub fn to_major_unit_asf64(&self, currency: enums::Currency) -> Result { + pub fn to_major_unit_asf64( + &self, + currency: enums::Currency, + ) -> Result { let amount_f64: f64 = u32::try_from(self.0)?.into(); let amount = if currency.is_zero_decimal_currency() { amount_f64 @@ -273,7 +283,10 @@ impl MinorUnit { } ///Convert the higher decimal amount to its major absolute units - pub fn to_minor_unit_as_string(&self, currency: enums::Currency) -> Result { + pub fn to_minor_unit_as_string( + &self, + currency: enums::Currency, + ) -> Result { let amount_f64 = self.0.to_string().parse::()?; let amount_string = if currency.is_zero_decimal_currency() { amount_f64 @@ -357,41 +370,48 @@ impl Sub for MinorUnit { /// This struct represents Money unit on which conversion will be done #[derive( - Default, - Debug, - serde::Deserialize, - serde::Serialize, - Clone, - Copy, - PartialEq, - Eq, - Hash, - ToSchema, + Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq, Hash, ToSchema, )] pub struct Money { amount: MinorUnit, - currency: enums::Currency + currency: enums::Currency, } -// connector amount unit -#[derive( - Default, - Debug, - serde::Deserialize, - serde::Serialize, - Clone, - Copy, - PartialEq, -)] +// connector amount unit +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] pub struct FloatMajorUnit(f64); -impl FloatMajorUnit{ +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] +pub struct FloatMajorUnitForConnector; + +impl AmountConvertor for FloatMajorUnitForConnector { + type Output = FloatMajorUnit; + fn convert( + &self, + i: MinorUnit, + currency: enums::Currency, + ) -> Result { + i.to_major_unit_asf64(currency) + } + fn convert_back( + &self, + i: FloatMajorUnit, + currency: enums::Currency, + ) -> Result { + i.to_minor_unit_as_i64(currency) + } +} + +impl FloatMajorUnit { /// forms a new major unit from amount pub fn new(value: f64) -> Self { Self(value) } - pub fn to_minor_unit_as_i64(&self, currency:enums::Currency) -> Result { + pub fn to_minor_unit_as_i64( + &self, + currency: enums::Currency, + ) -> Result { let amount_f64 = self.0; let amount = if currency.is_zero_decimal_currency() { amount_f64 @@ -403,15 +423,7 @@ impl FloatMajorUnit{ Ok(MinorUnit::new(amount as i64)) } } -#[derive( - Default, - Debug, - serde::Deserialize, - serde::Serialize, - Clone, - PartialEq, - Eq, -)] +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq, Eq)] pub struct StringMajorUnit(String); impl StringMajorUnit { @@ -420,7 +432,10 @@ impl StringMajorUnit { Self(value) } - pub fn to_minor_unit_as_i64(&self, currency:enums::Currency) -> Result { + pub fn to_minor_unit_as_i64( + &self, + currency: enums::Currency, + ) -> Result { let amount_f64 = self.0.parse::()?; let amount = if currency.is_zero_decimal_currency() { amount_f64 @@ -433,30 +448,53 @@ impl StringMajorUnit { } } - -pub trait AmountConvertor : Send { +pub trait AmountConvertor: Send { type Output; - fn convert(&self, i: MinorUnit, currency:enums::Currency) -> Result; - fn convert_back(&self, i:Self::Output, currency:enums::Currency) -> Result; + fn convert( + &self, + i: MinorUnit, + currency: enums::Currency, + ) -> Result; + + fn convert_back( + &self, + i: Self::Output, + currency: enums::Currency, + ) -> Result; } impl AmountConvertor for FloatMajorUnit { type Output = FloatMajorUnit; - fn convert(&self, i: MinorUnit, currency: enums::Currency) -> Result { + fn convert( + &self, + i: MinorUnit, + currency: enums::Currency, + ) -> Result { i.to_major_unit_asf64(currency) } - fn convert_back(&self, i: FloatMajorUnit, currency:enums::Currency) -> Result { + fn convert_back( + &self, + i: FloatMajorUnit, + currency: enums::Currency, + ) -> Result { i.to_minor_unit_as_i64(currency) } } impl AmountConvertor for StringMajorUnit { type Output = StringMajorUnit; - fn convert(&self, i: MinorUnit, currency: enums::Currency) -> Result { + fn convert( + &self, + i: MinorUnit, + currency: enums::Currency, + ) -> Result { i.to_major_unit_as_string_with_zero_decimal_check(currency) } - fn convert_back(&self, i: StringMajorUnit, currency:enums::Currency) -> Result { + fn convert_back( + &self, + i: StringMajorUnit, + currency: enums::Currency, + ) -> Result { i.to_minor_unit_as_i64(currency) } } - diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs index 69b0089f3a7..313a44cf83a 100644 --- a/crates/router/src/connector/stripe.rs +++ b/crates/router/src/connector/stripe.rs @@ -2,8 +2,12 @@ pub mod transformers; use std::{collections::HashMap, fmt::Debug, ops::Deref}; -use common_utils::{request::RequestContent, types::AmountConvertor, types::FloatMajorUnit, types::MinorUnit}; +use common_utils::{ + request::RequestContent, + types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector, MinorUnit}, +}; use diesel_models::enums; +use dyn_clone::DynClone; use error_stack::ResultExt; use masking::PeekInterface; use router_env::{instrument, tracing}; @@ -35,24 +39,35 @@ use crate::{ utils::{crypto, ByteSliceExt, BytesExt, OptionExt}, }; -#[derive(Debug, Clone)] -pub struct Stripe{ - boxed_convert : Box> +pub struct Stripe { + boxed_convert: Box + Send + Sync>, } impl Stripe { pub fn new() -> Self { Self { - boxed_convert: Box::new(FloatMajorUnit::new), + boxed_convert: Box::new(FloatMajorUnitForConnector), } } - pub fn convert_amount(&self, i: MinorUnit, currency: enums::Currency) -> Result> { - self.boxed_convert.convert(i, currency).change_context(errors::ConnectorError::ParsingFailed) + pub fn convert_amount( + &self, + i: MinorUnit, + currency: enums::Currency, + ) -> Result> { + self.boxed_convert + .convert(i, currency) + .change_context(errors::ConnectorError::ParsingFailed) } - pub fn convert_back(&self, i: FloatMajorUnit, currency: enums::Currency) -> Result> { - self.boxed_convert.convert_back(i, currency).change_context(errors::ConnectorError::ParsingFailed) + pub fn convert_back( + &self, + i: FloatMajorUnit, + currency: enums::Currency, + ) -> Result> { + self.boxed_convert + .convert_back(i, currency) + .change_context(errors::ConnectorError::ParsingFailed) } } @@ -935,7 +950,8 @@ impl _connectors: &settings::Connectors, ) -> CustomResult { let sahkal = self.convert_amount(MinorUnit::new(23), req.request.currency)?; - let sahkal_back_convert = self.convert_back(FloatMajorUnit::new(1.00), req.request.currency)?; + let sahkal_back_convert = + self.convert_back(FloatMajorUnit::new(1.00), req.request.currency)?; match &req.request.payment_method_data { domain::PaymentMethodData::BankTransfer(bank_transfer_data) => { stripe::get_bank_transfer_request_data(req, bank_transfer_data.deref()) @@ -2753,4 +2769,3 @@ impl self.build_error_response(res, event_builder) } } - diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 6f99789ce37..8dd21a5c08f 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -170,7 +170,6 @@ pub trait Connector: Send + Refund + Payment - + Debug + ConnectorRedirectResponse + IncomingWebhook + ConnectorAccessToken @@ -192,7 +191,6 @@ pub struct Pe; impl< T: Refund + Payment - + Debug + ConnectorRedirectResponse + Send + IncomingWebhook @@ -209,7 +207,7 @@ impl< { } -type BoxedConnector = Box<&'static (dyn Connector + Sync)>; +type BoxedConnector = Box; // Normal flow will call the connector and follow the flow specific operations (capture, authorize) // SessionTokenFromMetadata will avoid calling the connector instead create the session token ( for sdk ) @@ -283,7 +281,7 @@ impl ConnectorData { let connector_name = api_enums::Connector::from_str(name) .change_context(errors::ConnectorError::InvalidConnectorName) .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable_lazy(|| format!("unable to parse connector name {connector:?}"))?; + .attach_printable_lazy(|| format!("unable to parse connector name {name}"))?; Ok(Self { connector, connector_name, @@ -303,9 +301,7 @@ impl ConnectorData { let payout_connector_name = api_enums::PayoutConnectors::from_str(name) .change_context(errors::ConnectorError::InvalidConnectorName) .change_context(errors::ApiErrorResponse::InternalServerError) - .attach_printable_lazy(|| { - format!("unable to parse payout connector name {connector:?}") - })?; + .attach_printable_lazy(|| format!("unable to parse payout connector name {name}"))?; let connector_name = api_enums::Connector::from(payout_connector_name); Ok(Self { connector, @@ -321,75 +317,75 @@ impl ConnectorData { ) -> CustomResult { match enums::Connector::from_str(connector_name) { Ok(name) => match name { - enums::Connector::Aci => Ok(Box::new(&connector::Aci)), - enums::Connector::Adyen => Ok(Box::new(&connector::Adyen)), - enums::Connector::Airwallex => Ok(Box::new(&connector::Airwallex)), - enums::Connector::Authorizedotnet => Ok(Box::new(&connector::Authorizedotnet)), - enums::Connector::Bambora => Ok(Box::new(&connector::Bambora)), - enums::Connector::Bankofamerica => Ok(Box::new(&connector::Bankofamerica)), - enums::Connector::Billwerk => Ok(Box::new(&connector::Billwerk)), - enums::Connector::Bitpay => Ok(Box::new(&connector::Bitpay)), - enums::Connector::Bluesnap => Ok(Box::new(&connector::Bluesnap)), - enums::Connector::Boku => Ok(Box::new(&connector::Boku)), - enums::Connector::Braintree => Ok(Box::new(&connector::Braintree)), - enums::Connector::Cashtocode => Ok(Box::new(&connector::Cashtocode)), - enums::Connector::Checkout => Ok(Box::new(&connector::Checkout)), - enums::Connector::Coinbase => Ok(Box::new(&connector::Coinbase)), - enums::Connector::Cryptopay => Ok(Box::new(&connector::Cryptopay)), - enums::Connector::Cybersource => Ok(Box::new(&connector::Cybersource)), - enums::Connector::Dlocal => Ok(Box::new(&connector::Dlocal)), + enums::Connector::Aci => Ok(Box::new(connector::Aci)), + enums::Connector::Adyen => Ok(Box::new(connector::Adyen)), + enums::Connector::Airwallex => Ok(Box::new(connector::Airwallex)), + enums::Connector::Authorizedotnet => Ok(Box::new(connector::Authorizedotnet)), + enums::Connector::Bambora => Ok(Box::new(connector::Bambora)), + enums::Connector::Bankofamerica => Ok(Box::new(connector::Bankofamerica)), + enums::Connector::Billwerk => Ok(Box::new(connector::Billwerk)), + enums::Connector::Bitpay => Ok(Box::new(connector::Bitpay)), + enums::Connector::Bluesnap => Ok(Box::new(connector::Bluesnap)), + enums::Connector::Boku => Ok(Box::new(connector::Boku)), + enums::Connector::Braintree => Ok(Box::new(connector::Braintree)), + enums::Connector::Cashtocode => Ok(Box::new(connector::Cashtocode)), + enums::Connector::Checkout => Ok(Box::new(connector::Checkout)), + enums::Connector::Coinbase => Ok(Box::new(connector::Coinbase)), + enums::Connector::Cryptopay => Ok(Box::new(connector::Cryptopay)), + enums::Connector::Cybersource => Ok(Box::new(connector::Cybersource)), + enums::Connector::Dlocal => Ok(Box::new(connector::Dlocal)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector1 => Ok(Box::new(&connector::DummyConnector::<1>)), + enums::Connector::DummyConnector1 => Ok(Box::new(connector::DummyConnector::<1>)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector2 => Ok(Box::new(&connector::DummyConnector::<2>)), + enums::Connector::DummyConnector2 => Ok(Box::new(connector::DummyConnector::<2>)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector3 => Ok(Box::new(&connector::DummyConnector::<3>)), + enums::Connector::DummyConnector3 => Ok(Box::new(connector::DummyConnector::<3>)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector4 => Ok(Box::new(&connector::DummyConnector::<4>)), + enums::Connector::DummyConnector4 => Ok(Box::new(connector::DummyConnector::<4>)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector5 => Ok(Box::new(&connector::DummyConnector::<5>)), + enums::Connector::DummyConnector5 => Ok(Box::new(connector::DummyConnector::<5>)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector6 => Ok(Box::new(&connector::DummyConnector::<6>)), + enums::Connector::DummyConnector6 => Ok(Box::new(connector::DummyConnector::<6>)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector7 => Ok(Box::new(&connector::DummyConnector::<7>)), - enums::Connector::Ebanx => Ok(Box::new(&connector::Ebanx)), - enums::Connector::Fiserv => Ok(Box::new(&connector::Fiserv)), - enums::Connector::Forte => Ok(Box::new(&connector::Forte)), - enums::Connector::Globalpay => Ok(Box::new(&connector::Globalpay)), - enums::Connector::Globepay => Ok(Box::new(&connector::Globepay)), - enums::Connector::Gocardless => Ok(Box::new(&connector::Gocardless)), - enums::Connector::Helcim => Ok(Box::new(&connector::Helcim)), - enums::Connector::Iatapay => Ok(Box::new(&connector::Iatapay)), - enums::Connector::Klarna => Ok(Box::new(&connector::Klarna)), - // enums::Connector::Mifinity => Ok(Box::new(&connector::Mifinity)), Added as template code for future usage - enums::Connector::Mollie => Ok(Box::new(&connector::Mollie)), - enums::Connector::Nmi => Ok(Box::new(&connector::Nmi)), - enums::Connector::Noon => Ok(Box::new(&connector::Noon)), - enums::Connector::Nuvei => Ok(Box::new(&connector::Nuvei)), - enums::Connector::Opennode => Ok(Box::new(&connector::Opennode)), - // "payeezy" => Ok(Box::new(&connector::Payeezy)), As psync and rsync are not supported by this connector, it is added as template code for future usage - enums::Connector::Payme => Ok(Box::new(&connector::Payme)), - // enums::Connector::Payone => Ok(Box::new(&connector::Payone)), Added as template code for future usage - enums::Connector::Payu => Ok(Box::new(&connector::Payu)), - enums::Connector::Placetopay => Ok(Box::new(&connector::Placetopay)), - enums::Connector::Powertranz => Ok(Box::new(&connector::Powertranz)), - enums::Connector::Prophetpay => Ok(Box::new(&connector::Prophetpay)), - enums::Connector::Rapyd => Ok(Box::new(&connector::Rapyd)), - enums::Connector::Shift4 => Ok(Box::new(&connector::Shift4)), - enums::Connector::Square => Ok(Box::new(&connector::Square)), - enums::Connector::Stax => Ok(Box::new(&connector::Stax)), - enums::Connector::Stripe => Ok(Box::new(&connector::Stripe::new())), - enums::Connector::Wise => Ok(Box::new(&connector::Wise)), - enums::Connector::Worldline => Ok(Box::new(&connector::Worldline)), - enums::Connector::Worldpay => Ok(Box::new(&connector::Worldpay)), - enums::Connector::Multisafepay => Ok(Box::new(&connector::Multisafepay)), - enums::Connector::Nexinets => Ok(Box::new(&connector::Nexinets)), - enums::Connector::Paypal => Ok(Box::new(&connector::Paypal)), - enums::Connector::Trustpay => Ok(Box::new(&connector::Trustpay)), - enums::Connector::Tsys => Ok(Box::new(&connector::Tsys)), - enums::Connector::Volt => Ok(Box::new(&connector::Volt)), - enums::Connector::Zen => Ok(Box::new(&connector::Zen)), - enums::Connector::Zsl => Ok(Box::new(&connector::Zsl)), + enums::Connector::DummyConnector7 => Ok(Box::new(connector::DummyConnector::<7>)), + enums::Connector::Ebanx => Ok(Box::new(connector::Ebanx)), + enums::Connector::Fiserv => Ok(Box::new(connector::Fiserv)), + enums::Connector::Forte => Ok(Box::new(connector::Forte)), + enums::Connector::Globalpay => Ok(Box::new(connector::Globalpay)), + enums::Connector::Globepay => Ok(Box::new(connector::Globepay)), + enums::Connector::Gocardless => Ok(Box::new(connector::Gocardless)), + enums::Connector::Helcim => Ok(Box::new(connector::Helcim)), + enums::Connector::Iatapay => Ok(Box::new(connector::Iatapay)), + enums::Connector::Klarna => Ok(Box::new(connector::Klarna)), + // enums::Connector::Mifinity => Ok(Box::new(connector::Mifinity)), Added as template code for future usage + enums::Connector::Mollie => Ok(Box::new(connector::Mollie)), + enums::Connector::Nmi => Ok(Box::new(connector::Nmi)), + enums::Connector::Noon => Ok(Box::new(connector::Noon)), + enums::Connector::Nuvei => Ok(Box::new(connector::Nuvei)), + enums::Connector::Opennode => Ok(Box::new(connector::Opennode)), + // "payeezy" => Ok(Box::new(connector::Payeezy)), As psync and rsync are not supported by this connector, it is added as template code for future usage + enums::Connector::Payme => Ok(Box::new(connector::Payme)), + // enums::Connector::Payone => Ok(Box::new(connector::Payone)), Added as template code for future usage + enums::Connector::Payu => Ok(Box::new(connector::Payu)), + enums::Connector::Placetopay => Ok(Box::new(connector::Placetopay)), + enums::Connector::Powertranz => Ok(Box::new(connector::Powertranz)), + enums::Connector::Prophetpay => Ok(Box::new(connector::Prophetpay)), + enums::Connector::Rapyd => Ok(Box::new(connector::Rapyd)), + enums::Connector::Shift4 => Ok(Box::new(connector::Shift4)), + enums::Connector::Square => Ok(Box::new(connector::Square)), + enums::Connector::Stax => Ok(Box::new(connector::Stax)), + enums::Connector::Stripe => Ok(Box::new(connector::Stripe::new())), + enums::Connector::Wise => Ok(Box::new(connector::Wise)), + enums::Connector::Worldline => Ok(Box::new(connector::Worldline)), + enums::Connector::Worldpay => Ok(Box::new(connector::Worldpay)), + enums::Connector::Multisafepay => Ok(Box::new(connector::Multisafepay)), + enums::Connector::Nexinets => Ok(Box::new(connector::Nexinets)), + enums::Connector::Paypal => Ok(Box::new(connector::Paypal)), + enums::Connector::Trustpay => Ok(Box::new(connector::Trustpay)), + enums::Connector::Tsys => Ok(Box::new(connector::Tsys)), + enums::Connector::Volt => Ok(Box::new(connector::Volt)), + enums::Connector::Zen => Ok(Box::new(connector::Zen)), + enums::Connector::Zsl => Ok(Box::new(connector::Zsl)), enums::Connector::Signifyd | enums::Connector::Plaid | enums::Connector::Riskified diff --git a/crates/router/src/types/api/authentication.rs b/crates/router/src/types/api/authentication.rs index 5b8e3238fb7..35cdd9331d9 100644 --- a/crates/router/src/types/api/authentication.rs +++ b/crates/router/src/types/api/authentication.rs @@ -111,7 +111,7 @@ pub trait ExternalAuthentication: { } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct AuthenticationConnectorData { pub connector: BoxedConnector, pub connector_name: enums::AuthenticationConnectors, diff --git a/crates/router/src/types/api/verify_connector.rs b/crates/router/src/types/api/verify_connector.rs index d35abd233f1..3df09591fad 100644 --- a/crates/router/src/types/api/verify_connector.rs +++ b/crates/router/src/types/api/verify_connector.rs @@ -12,7 +12,7 @@ use crate::{ AppState, }; -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct VerifyConnectorData { pub connector: &'static (dyn api::Connector + Sync), pub connector_auth: types::ConnectorAuthType, From ddee2bd11a0a132592edf5a9b28bf252a417c86a Mon Sep 17 00:00:00 2001 From: Narayan Bhat Date: Tue, 21 May 2024 00:46:17 +0530 Subject: [PATCH 23/82] chore: make it finally compile --- crates/router/src/connector/stripe.rs | 12 +- crates/router/src/types/api.rs | 126 ++++++++++----------- crates/router/src/types/api/fraud_check.rs | 2 +- crates/router/src/utils/ext_traits.rs | 11 +- 4 files changed, 74 insertions(+), 77 deletions(-) diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs index 313a44cf83a..01f595f268e 100644 --- a/crates/router/src/connector/stripe.rs +++ b/crates/router/src/connector/stripe.rs @@ -40,13 +40,13 @@ use crate::{ }; pub struct Stripe { - boxed_convert: Box + Send + Sync>, + amount_converter: &'static (dyn AmountConvertor + Sync), } impl Stripe { - pub fn new() -> Self { - Self { - boxed_convert: Box::new(FloatMajorUnitForConnector), + pub const fn new() -> &'static Self { + &Self { + amount_converter: &FloatMajorUnitForConnector, } } @@ -55,7 +55,7 @@ impl Stripe { i: MinorUnit, currency: enums::Currency, ) -> Result> { - self.boxed_convert + self.amount_converter .convert(i, currency) .change_context(errors::ConnectorError::ParsingFailed) } @@ -65,7 +65,7 @@ impl Stripe { i: FloatMajorUnit, currency: enums::Currency, ) -> Result> { - self.boxed_convert + self.amount_converter .convert_back(i, currency) .change_context(errors::ConnectorError::ParsingFailed) } diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 8dd21a5c08f..24037417068 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -207,7 +207,7 @@ impl< { } -type BoxedConnector = Box; +type BoxedConnector = Box<&'static (dyn Connector + Sync)>; // Normal flow will call the connector and follow the flow specific operations (capture, authorize) // SessionTokenFromMetadata will avoid calling the connector instead create the session token ( for sdk ) @@ -221,7 +221,7 @@ pub enum GetToken { /// Routing algorithm will output merchant connector identifier instead of connector name /// In order to support backwards compatibility for older routing algorithms and merchant accounts /// the support for connector name is retained -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct ConnectorData { pub connector: BoxedConnector, pub connector_name: types::Connector, @@ -317,75 +317,75 @@ impl ConnectorData { ) -> CustomResult { match enums::Connector::from_str(connector_name) { Ok(name) => match name { - enums::Connector::Aci => Ok(Box::new(connector::Aci)), - enums::Connector::Adyen => Ok(Box::new(connector::Adyen)), - enums::Connector::Airwallex => Ok(Box::new(connector::Airwallex)), - enums::Connector::Authorizedotnet => Ok(Box::new(connector::Authorizedotnet)), - enums::Connector::Bambora => Ok(Box::new(connector::Bambora)), - enums::Connector::Bankofamerica => Ok(Box::new(connector::Bankofamerica)), - enums::Connector::Billwerk => Ok(Box::new(connector::Billwerk)), - enums::Connector::Bitpay => Ok(Box::new(connector::Bitpay)), - enums::Connector::Bluesnap => Ok(Box::new(connector::Bluesnap)), - enums::Connector::Boku => Ok(Box::new(connector::Boku)), - enums::Connector::Braintree => Ok(Box::new(connector::Braintree)), - enums::Connector::Cashtocode => Ok(Box::new(connector::Cashtocode)), - enums::Connector::Checkout => Ok(Box::new(connector::Checkout)), - enums::Connector::Coinbase => Ok(Box::new(connector::Coinbase)), - enums::Connector::Cryptopay => Ok(Box::new(connector::Cryptopay)), - enums::Connector::Cybersource => Ok(Box::new(connector::Cybersource)), - enums::Connector::Dlocal => Ok(Box::new(connector::Dlocal)), + enums::Connector::Aci => Ok(Box::new(&connector::Aci)), + enums::Connector::Adyen => Ok(Box::new(&connector::Adyen)), + enums::Connector::Airwallex => Ok(Box::new(&connector::Airwallex)), + enums::Connector::Authorizedotnet => Ok(Box::new(&connector::Authorizedotnet)), + enums::Connector::Bambora => Ok(Box::new(&connector::Bambora)), + enums::Connector::Bankofamerica => Ok(Box::new(&connector::Bankofamerica)), + enums::Connector::Billwerk => Ok(Box::new(&connector::Billwerk)), + enums::Connector::Bitpay => Ok(Box::new(&connector::Bitpay)), + enums::Connector::Bluesnap => Ok(Box::new(&connector::Bluesnap)), + enums::Connector::Boku => Ok(Box::new(&connector::Boku)), + enums::Connector::Braintree => Ok(Box::new(&connector::Braintree)), + enums::Connector::Cashtocode => Ok(Box::new(&connector::Cashtocode)), + enums::Connector::Checkout => Ok(Box::new(&connector::Checkout)), + enums::Connector::Coinbase => Ok(Box::new(&connector::Coinbase)), + enums::Connector::Cryptopay => Ok(Box::new(&connector::Cryptopay)), + enums::Connector::Cybersource => Ok(Box::new(&connector::Cybersource)), + enums::Connector::Dlocal => Ok(Box::new(&connector::Dlocal)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector1 => Ok(Box::new(connector::DummyConnector::<1>)), + enums::Connector::DummyConnector1 => Ok(Box::new(&connector::DummyConnector::<1>)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector2 => Ok(Box::new(connector::DummyConnector::<2>)), + enums::Connector::DummyConnector2 => Ok(Box::new(&connector::DummyConnector::<2>)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector3 => Ok(Box::new(connector::DummyConnector::<3>)), + enums::Connector::DummyConnector3 => Ok(Box::new(&connector::DummyConnector::<3>)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector4 => Ok(Box::new(connector::DummyConnector::<4>)), + enums::Connector::DummyConnector4 => Ok(Box::new(&connector::DummyConnector::<4>)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector5 => Ok(Box::new(connector::DummyConnector::<5>)), + enums::Connector::DummyConnector5 => Ok(Box::new(&connector::DummyConnector::<5>)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector6 => Ok(Box::new(connector::DummyConnector::<6>)), + enums::Connector::DummyConnector6 => Ok(Box::new(&connector::DummyConnector::<6>)), #[cfg(feature = "dummy_connector")] - enums::Connector::DummyConnector7 => Ok(Box::new(connector::DummyConnector::<7>)), - enums::Connector::Ebanx => Ok(Box::new(connector::Ebanx)), - enums::Connector::Fiserv => Ok(Box::new(connector::Fiserv)), - enums::Connector::Forte => Ok(Box::new(connector::Forte)), - enums::Connector::Globalpay => Ok(Box::new(connector::Globalpay)), - enums::Connector::Globepay => Ok(Box::new(connector::Globepay)), - enums::Connector::Gocardless => Ok(Box::new(connector::Gocardless)), - enums::Connector::Helcim => Ok(Box::new(connector::Helcim)), - enums::Connector::Iatapay => Ok(Box::new(connector::Iatapay)), - enums::Connector::Klarna => Ok(Box::new(connector::Klarna)), - // enums::Connector::Mifinity => Ok(Box::new(connector::Mifinity)), Added as template code for future usage - enums::Connector::Mollie => Ok(Box::new(connector::Mollie)), - enums::Connector::Nmi => Ok(Box::new(connector::Nmi)), - enums::Connector::Noon => Ok(Box::new(connector::Noon)), - enums::Connector::Nuvei => Ok(Box::new(connector::Nuvei)), - enums::Connector::Opennode => Ok(Box::new(connector::Opennode)), - // "payeezy" => Ok(Box::new(connector::Payeezy)), As psync and rsync are not supported by this connector, it is added as template code for future usage - enums::Connector::Payme => Ok(Box::new(connector::Payme)), - // enums::Connector::Payone => Ok(Box::new(connector::Payone)), Added as template code for future usage - enums::Connector::Payu => Ok(Box::new(connector::Payu)), - enums::Connector::Placetopay => Ok(Box::new(connector::Placetopay)), - enums::Connector::Powertranz => Ok(Box::new(connector::Powertranz)), - enums::Connector::Prophetpay => Ok(Box::new(connector::Prophetpay)), - enums::Connector::Rapyd => Ok(Box::new(connector::Rapyd)), - enums::Connector::Shift4 => Ok(Box::new(connector::Shift4)), - enums::Connector::Square => Ok(Box::new(connector::Square)), - enums::Connector::Stax => Ok(Box::new(connector::Stax)), + enums::Connector::DummyConnector7 => Ok(Box::new(&connector::DummyConnector::<7>)), + enums::Connector::Ebanx => Ok(Box::new(&connector::Ebanx)), + enums::Connector::Fiserv => Ok(Box::new(&connector::Fiserv)), + enums::Connector::Forte => Ok(Box::new(&connector::Forte)), + enums::Connector::Globalpay => Ok(Box::new(&connector::Globalpay)), + enums::Connector::Globepay => Ok(Box::new(&connector::Globepay)), + enums::Connector::Gocardless => Ok(Box::new(&connector::Gocardless)), + enums::Connector::Helcim => Ok(Box::new(&connector::Helcim)), + enums::Connector::Iatapay => Ok(Box::new(&connector::Iatapay)), + enums::Connector::Klarna => Ok(Box::new(&connector::Klarna)), + // enums::Connector::Mifinity => Ok(Box::new(&connector::Mifinity)), Added as template code for future usage + enums::Connector::Mollie => Ok(Box::new(&connector::Mollie)), + enums::Connector::Nmi => Ok(Box::new(&connector::Nmi)), + enums::Connector::Noon => Ok(Box::new(&connector::Noon)), + enums::Connector::Nuvei => Ok(Box::new(&connector::Nuvei)), + enums::Connector::Opennode => Ok(Box::new(&connector::Opennode)), + // "payeezy" => Ok(Box::new(&connector::Payeezy)), As psync and rsync are not supported by this connector, it is added as template code for future usage + enums::Connector::Payme => Ok(Box::new(&connector::Payme)), + // enums::Connector::Payone => Ok(Box::new(&connector::Payone)), Added as template code for future usage + enums::Connector::Payu => Ok(Box::new(&connector::Payu)), + enums::Connector::Placetopay => Ok(Box::new(&connector::Placetopay)), + enums::Connector::Powertranz => Ok(Box::new(&connector::Powertranz)), + enums::Connector::Prophetpay => Ok(Box::new(&connector::Prophetpay)), + enums::Connector::Rapyd => Ok(Box::new(&connector::Rapyd)), + enums::Connector::Shift4 => Ok(Box::new(&connector::Shift4)), + enums::Connector::Square => Ok(Box::new(&connector::Square)), + enums::Connector::Stax => Ok(Box::new(&connector::Stax)), enums::Connector::Stripe => Ok(Box::new(connector::Stripe::new())), - enums::Connector::Wise => Ok(Box::new(connector::Wise)), - enums::Connector::Worldline => Ok(Box::new(connector::Worldline)), - enums::Connector::Worldpay => Ok(Box::new(connector::Worldpay)), - enums::Connector::Multisafepay => Ok(Box::new(connector::Multisafepay)), - enums::Connector::Nexinets => Ok(Box::new(connector::Nexinets)), - enums::Connector::Paypal => Ok(Box::new(connector::Paypal)), - enums::Connector::Trustpay => Ok(Box::new(connector::Trustpay)), - enums::Connector::Tsys => Ok(Box::new(connector::Tsys)), - enums::Connector::Volt => Ok(Box::new(connector::Volt)), - enums::Connector::Zen => Ok(Box::new(connector::Zen)), - enums::Connector::Zsl => Ok(Box::new(connector::Zsl)), + enums::Connector::Wise => Ok(Box::new(&connector::Wise)), + enums::Connector::Worldline => Ok(Box::new(&connector::Worldline)), + enums::Connector::Worldpay => Ok(Box::new(&connector::Worldpay)), + enums::Connector::Multisafepay => Ok(Box::new(&connector::Multisafepay)), + enums::Connector::Nexinets => Ok(Box::new(&connector::Nexinets)), + enums::Connector::Paypal => Ok(Box::new(&connector::Paypal)), + enums::Connector::Trustpay => Ok(Box::new(&connector::Trustpay)), + enums::Connector::Tsys => Ok(Box::new(&connector::Tsys)), + enums::Connector::Volt => Ok(Box::new(&connector::Volt)), + enums::Connector::Zen => Ok(Box::new(&connector::Zen)), + enums::Connector::Zsl => Ok(Box::new(&connector::Zsl)), enums::Connector::Signifyd | enums::Connector::Plaid | enums::Connector::Riskified diff --git a/crates/router/src/types/api/fraud_check.rs b/crates/router/src/types/api/fraud_check.rs index 45c79930e80..c413126ee04 100644 --- a/crates/router/src/types/api/fraud_check.rs +++ b/crates/router/src/types/api/fraud_check.rs @@ -55,7 +55,7 @@ pub trait FraudCheckRecordReturn: { } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct FraudCheckConnectorData { pub connector: BoxedConnector, pub connector_name: enums::FrmConnectors, diff --git a/crates/router/src/utils/ext_traits.rs b/crates/router/src/utils/ext_traits.rs index 7b08dc296c7..33fdb4c9b25 100644 --- a/crates/router/src/utils/ext_traits.rs +++ b/crates/router/src/utils/ext_traits.rs @@ -26,15 +26,12 @@ pub trait OptionExt { fn update_value(&mut self, value: Option); } -impl OptionExt for Option -where - T: std::fmt::Debug, -{ +impl OptionExt for Option { fn check_value_present(&self, field_name: &'static str) -> RouterResult<()> { when(self.is_none(), || { Err( Report::new(ApiErrorResponse::MissingRequiredField { field_name }) - .attach_printable(format!("Missing required field {field_name} in {self:?}")), + .attach_printable(format!("Missing required field {field_name}")), ) }) } @@ -46,7 +43,7 @@ where Some(v) => Ok(v), None => Err( Report::new(ApiErrorResponse::MissingRequiredField { field_name }) - .attach_printable(format!("Missing required field {field_name} in {self:?}")), + .attach_printable(format!("Missing required field {field_name}")), ), } } @@ -63,7 +60,7 @@ where E::from_str(value.as_ref()) .change_context(errors::ParsingError::UnknownError) - .attach_printable_lazy(|| format!("Invalid {{ {enum_name}: {value:?} }} ")) + .attach_printable_lazy(|| format!("Invalid {{ {enum_name} }} ")) } fn parse_value(self, type_name: &'static str) -> CustomResult From 6e0070d7e9e2a56b8ced90064bb27f5c2b94353e Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 19:23:55 +0000 Subject: [PATCH 24/82] chore: run formatter --- crates/common_utils/src/types.rs | 15 ++++++++------- crates/router/src/services/api.rs | 1 - 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 28afbb79f99..6ae3399fe60 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -1,4 +1,12 @@ //! Types that can be used in other crates +use std::{ + fmt::Display, + num::{ParseFloatError, TryFromIntError}, + ops::{Add, Sub}, + primitive::i64, + str::FromStr, +}; + use common_enums::enums; use diesel::{ backend::Backend, @@ -12,13 +20,6 @@ use diesel::{ use error_stack::{report, ResultExt}; use semver::Version; use serde::{de::Visitor, Deserialize, Deserializer}; -use std::{ - fmt::Display, - num::{ParseFloatError, TryFromIntError}, - ops::{Add, Sub}, - primitive::i64, - str::FromStr, -}; use utoipa::ToSchema; use crate::{ diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 65e4d931118..71c74099ded 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -279,7 +279,6 @@ pub trait ConnectorIntegration: ConnectorIntegrationAny CustomResult, errors::ConnectorError> { Ok(None) } - } pub enum CaptureSyncMethod { From 44caf0b066d2355d9808012f297968111374ad90 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Tue, 21 May 2024 14:59:05 +0530 Subject: [PATCH 25/82] feat(router): added conversion trait in core for connector to use --- crates/common_utils/src/types.rs | 163 +++++++++++++------------- crates/router/src/connector/stripe.rs | 3 +- 2 files changed, 80 insertions(+), 86 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 28afbb79f99..ddd07954e77 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -227,6 +227,74 @@ where } } +/// Amount convertor trait for connector +pub trait AmountConvertor: Send { + /// Output type for the connector + type Output; + /// helps in conversion of connector required amount type + fn convert( + &self, + i: MinorUnit, + currency: enums::Currency, + ) -> Result; + + /// helps in converting back connector required amount type to core minor unit + fn convert_back( + &self, + i: Self::Output, + currency: enums::Currency, + ) -> Result; +} + +/// Connector required amount type +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] +pub struct StringMajorUnitForConnector; + +impl AmountConvertor for StringMajorUnitForConnector { + type Output = StringMajorUnit; + fn convert( + &self, + i: MinorUnit, + currency: enums::Currency, + ) -> Result { + i.to_major_unit_as_string(currency) + } + + fn convert_back( + &self, + i: StringMajorUnit, + currency: enums::Currency, + ) -> Result { + i.to_minor_unit_as_i64(currency) + } +} + +/// Connector required amount type +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] +pub struct FloatMajorUnitForConnector; + +impl AmountConvertor for FloatMajorUnitForConnector { + type Output = FloatMajorUnit; + fn convert( + &self, + i: MinorUnit, + currency: enums::Currency, + ) -> Result { + i.to_major_unit_asf64(currency) + } + fn convert_back( + &self, + i: FloatMajorUnit, + currency: enums::Currency, + ) -> Result { + i.to_minor_unit_as_i64(currency) + } +} + + + + + /// This Unit struct represents MinorUnit in which core amount works #[derive( Default, @@ -261,9 +329,10 @@ impl MinorUnit { pub fn to_major_unit_as_string( &self, currency: enums::Currency, - ) -> Result { + ) -> Result { let amount_f64 = self.to_major_unit_asf64(currency)?; - Ok(format!("{:.2}", amount_f64.0)) + let amount_string = format!("{:.2}", amount_f64.0); + Ok(StringMajorUnit::new(amount_string)) } /// Convert the amount to its major denomination based on Currency and return f64 @@ -368,39 +437,11 @@ impl Sub for MinorUnit { } } -/// This struct represents Money unit on which conversion will be done -#[derive( - Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq, Hash, ToSchema, -)] -pub struct Money { - amount: MinorUnit, - currency: enums::Currency, -} -// connector amount unit -#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] -pub struct FloatMajorUnit(f64); +/// Connector specific types to send #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] -pub struct FloatMajorUnitForConnector; - -impl AmountConvertor for FloatMajorUnitForConnector { - type Output = FloatMajorUnit; - fn convert( - &self, - i: MinorUnit, - currency: enums::Currency, - ) -> Result { - i.to_major_unit_asf64(currency) - } - fn convert_back( - &self, - i: FloatMajorUnit, - currency: enums::Currency, - ) -> Result { - i.to_minor_unit_as_i64(currency) - } -} +pub struct FloatMajorUnit(f64); impl FloatMajorUnit { /// forms a new major unit from amount @@ -408,6 +449,7 @@ impl FloatMajorUnit { Self(value) } + /// converts to minor unit as i64 from FloatMajorUnit pub fn to_minor_unit_as_i64( &self, currency: enums::Currency, @@ -423,6 +465,9 @@ impl FloatMajorUnit { Ok(MinorUnit::new(amount as i64)) } } + + +/// Connector specific types to send #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq, Eq)] pub struct StringMajorUnit(String); @@ -432,6 +477,7 @@ impl StringMajorUnit { Self(value) } + /// Converts to minor unit as i64 from StringMajorUnit pub fn to_minor_unit_as_i64( &self, currency: enums::Currency, @@ -446,55 +492,4 @@ impl StringMajorUnit { }; Ok(MinorUnit::new(amount as i64)) } -} - -pub trait AmountConvertor: Send { - type Output; - fn convert( - &self, - i: MinorUnit, - currency: enums::Currency, - ) -> Result; - - fn convert_back( - &self, - i: Self::Output, - currency: enums::Currency, - ) -> Result; -} - -impl AmountConvertor for FloatMajorUnit { - type Output = FloatMajorUnit; - fn convert( - &self, - i: MinorUnit, - currency: enums::Currency, - ) -> Result { - i.to_major_unit_asf64(currency) - } - fn convert_back( - &self, - i: FloatMajorUnit, - currency: enums::Currency, - ) -> Result { - i.to_minor_unit_as_i64(currency) - } -} - -impl AmountConvertor for StringMajorUnit { - type Output = StringMajorUnit; - fn convert( - &self, - i: MinorUnit, - currency: enums::Currency, - ) -> Result { - i.to_major_unit_as_string_with_zero_decimal_check(currency) - } - fn convert_back( - &self, - i: StringMajorUnit, - currency: enums::Currency, - ) -> Result { - i.to_minor_unit_as_i64(currency) - } -} +} \ No newline at end of file diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs index 01f595f268e..680f8d8f260 100644 --- a/crates/router/src/connector/stripe.rs +++ b/crates/router/src/connector/stripe.rs @@ -1,13 +1,12 @@ pub mod transformers; -use std::{collections::HashMap, fmt::Debug, ops::Deref}; +use std::{collections::HashMap, ops::Deref}; use common_utils::{ request::RequestContent, types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector, MinorUnit}, }; use diesel_models::enums; -use dyn_clone::DynClone; use error_stack::ResultExt; use masking::PeekInterface; use router_env::{instrument, tracing}; From c0f549e4a21fe6afb70271cbcc823c9076b8b373 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Tue, 21 May 2024 09:30:01 +0000 Subject: [PATCH 26/82] chore: run formatter --- crates/common_utils/src/types.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 4d223824c9d..629db5e5b13 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -247,17 +247,17 @@ pub trait AmountConvertor: Send { ) -> Result; } -/// Connector required amount type +/// Connector required amount type #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] pub struct StringMajorUnitForConnector; impl AmountConvertor for StringMajorUnitForConnector { type Output = StringMajorUnit; fn convert( - &self, - i: MinorUnit, - currency: enums::Currency, - ) -> Result { + &self, + i: MinorUnit, + currency: enums::Currency, + ) -> Result { i.to_major_unit_as_string(currency) } @@ -270,7 +270,7 @@ impl AmountConvertor for StringMajorUnitForConnector { } } -/// Connector required amount type +/// Connector required amount type #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] pub struct FloatMajorUnitForConnector; @@ -292,10 +292,6 @@ impl AmountConvertor for FloatMajorUnitForConnector { } } - - - - /// This Unit struct represents MinorUnit in which core amount works #[derive( Default, @@ -438,7 +434,6 @@ impl Sub for MinorUnit { } } - /// Connector specific types to send #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] @@ -467,7 +462,6 @@ impl FloatMajorUnit { } } - /// Connector specific types to send #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq, Eq)] pub struct StringMajorUnit(String); @@ -493,4 +487,4 @@ impl StringMajorUnit { }; Ok(MinorUnit::new(amount as i64)) } -} \ No newline at end of file +} From 1a9fe2ab39ae7fa148454451c5403947375e17da Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Thu, 23 May 2024 14:14:20 +0530 Subject: [PATCH 27/82] refactor (router): made changes for nmi --- crates/common_utils/src/types.rs | 3 +- crates/router/src/connector/nmi.rs | 58 +++++++++++-------- .../router/src/connector/nmi/transformers.rs | 36 ++++++------ crates/router/src/connector/stripe.rs | 25 +------- crates/router/src/connector/utils.rs | 12 +++- crates/router/src/core/errors.rs | 2 + crates/router/src/core/errors/utils.rs | 9 ++- .../router/src/core/payments/transformers.rs | 1 + crates/router/src/types.rs | 2 + crates/router/src/types/api.rs | 5 +- .../router/src/types/api/verify_connector.rs | 3 + 11 files changed, 86 insertions(+), 70 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 4d223824c9d..9a814390fc9 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -493,4 +493,5 @@ impl StringMajorUnit { }; Ok(MinorUnit::new(amount as i64)) } -} \ No newline at end of file +} + diff --git a/crates/router/src/connector/nmi.rs b/crates/router/src/connector/nmi.rs index 744eeb4a975..be63774b87e 100644 --- a/crates/router/src/connector/nmi.rs +++ b/crates/router/src/connector/nmi.rs @@ -1,8 +1,7 @@ pub mod transformers; -use std::fmt::Debug; -use common_utils::{crypto, ext_traits::ByteSliceExt, request::RequestContent}; +use common_utils::{crypto, ext_traits::ByteSliceExt, request::RequestContent, types::{FloatMajorUnit, FloatMajorUnitForConnector, MinorUnit, AmountConvertor}}; use diesel_models::enums; use error_stack::{report, ResultExt}; use regex::Regex; @@ -25,8 +24,18 @@ use crate::{ }, }; -#[derive(Clone, Debug)] -pub struct Nmi; +#[derive(Clone)] +pub struct Nmi { + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Nmi { + pub const fn new() -> &'static Self { + &Self { + amount_converter: &FloatMajorUnitForConnector, + } + } +} impl api::Payment for Nmi {} impl api::PaymentSession for Nmi {} @@ -92,6 +101,10 @@ impl ConnectorCommon for Nmi { connector_transaction_id: Some(response.transactionid), }) } + + // fn amount_convertor(&self) -> impl AmountConvertor { + // FloatMajorUnitForConnector + // } } impl ConnectorValidation for Nmi { @@ -325,12 +338,11 @@ impl ConnectorIntegration CustomResult { - let connector_router_data = nmi::NmiRouterData::try_from(( - &self.get_currency_unit(), - req.request.currency, - req.request.amount, + let amount = connector_utils::convert_amount(self.amount_converter, req.request.test_amount.unwrap_or(MinorUnit::new(req.request.amount)), req.request.currency)?; + let connector_router_data = nmi::NmiRouterData::from(( + amount, req, - ))?; + )); let connector_req = nmi::NmiPaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } @@ -413,12 +425,11 @@ impl req: &types::PaymentsCompleteAuthorizeRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = nmi::NmiRouterData::try_from(( - &self.get_currency_unit(), - req.request.currency, - req.request.amount, + let amount = connector_utils::convert_amount(self.amount_converter, MinorUnit::new(req.request.amount), req.request.currency)?; + let connector_router_data = nmi::NmiRouterData::from(( + amount, req, - ))?; + )); let connector_req = nmi::NmiCompleteRequest::try_from(&connector_router_data)?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } @@ -565,12 +576,11 @@ impl ConnectorIntegration CustomResult { - let connector_router_data = nmi::NmiRouterData::try_from(( - &self.get_currency_unit(), - req.request.currency, - req.request.amount_to_capture, + let amount = connector_utils::convert_amount(self.amount_converter, MinorUnit::new(req.request.amount_to_capture), req.request.currency)?; + let connector_router_data = nmi::NmiRouterData::from(( + amount, req, - ))?; + )); let connector_req = nmi::NmiCaptureRequest::try_from(&connector_router_data)?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } @@ -713,12 +723,12 @@ impl ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = nmi::NmiRouterData::try_from(( - &self.get_currency_unit(), - req.request.currency, - req.request.refund_amount, + let refund_amount = connector_utils::convert_amount(self.amount_converter, MinorUnit::new(req.request.refund_amount), req.request.currency)?; + + let connector_router_data = nmi::NmiRouterData::from(( + refund_amount, req, - ))?; + )); let connector_req = nmi::NmiRefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } diff --git a/crates/router/src/connector/nmi/transformers.rs b/crates/router/src/connector/nmi/transformers.rs index fdc65963fe8..e7230a3207c 100644 --- a/crates/router/src/connector/nmi/transformers.rs +++ b/crates/router/src/connector/nmi/transformers.rs @@ -5,6 +5,7 @@ use common_utils::{ errors::CustomResult, ext_traits::XmlExt, pii::{self, Email}, + types::FloatMajorUnit }; use error_stack::{report, Report, ResultExt}; use masking::{ExposeInterface, PeekInterface, Secret}; @@ -13,7 +14,7 @@ use serde::{Deserialize, Serialize}; use crate::{ connector::utils::{ self, AddressDetailsData, PaymentsAuthorizeRequestData, - PaymentsCompleteAuthorizeRequestData, RouterData, + PaymentsCompleteAuthorizeRequestData, RouterData }, core::errors, services, @@ -57,25 +58,24 @@ impl TryFrom<&ConnectorAuthType> for NmiAuthType { #[derive(Debug, Serialize)] pub struct NmiRouterData { - pub amount: f64, + pub amount: FloatMajorUnit, pub router_data: T, } -impl TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for NmiRouterData { - type Error = Report; +impl From<(FloatMajorUnit, T)> for NmiRouterData { + // type Error = Report; - fn try_from( - (_currency_unit, currency, amount, router_data): ( - &api::CurrencyUnit, - enums::Currency, - i64, + fn from( + (amount, router_data): ( + FloatMajorUnit, T, ), - ) -> Result { - Ok(Self { - amount: utils::to_currency_base_unit_asf64(amount, currency)?, + ) -> Self { + Self { + // amount: utils::to_currency_base_unit_asf64(amount, currency)?, + amount, router_data, - }) + } } } @@ -250,7 +250,7 @@ impl #[derive(Debug, Serialize)] pub struct NmiCompleteRequest { - amount: f64, + amount: FloatMajorUnit, #[serde(rename = "type")] transaction_type: TransactionType, security_key: Secret, @@ -420,7 +420,7 @@ impl ForeignFrom<(NmiCompleteResponse, u16)> for types::ErrorResponse { pub struct NmiPaymentsRequest { #[serde(rename = "type")] transaction_type: TransactionType, - amount: f64, + amount: FloatMajorUnit, security_key: Secret, currency: enums::Currency, #[serde(flatten)] @@ -673,7 +673,7 @@ impl TryFrom<&types::SetupMandateRouterData> for NmiPaymentsRequest { Ok(Self { transaction_type: TransactionType::Validate, security_key: auth_type.api_key, - amount: 0.0, + amount: FloatMajorUnit::new(0.0), currency: item.request.currency, payment_method, merchant_defined_field: None, @@ -705,7 +705,7 @@ pub struct NmiCaptureRequest { pub transaction_type: TransactionType, pub security_key: Secret, pub transactionid: String, - pub amount: Option, + pub amount: Option, } impl TryFrom<&NmiRouterData<&types::PaymentsCaptureRouterData>> for NmiCaptureRequest { @@ -1055,7 +1055,7 @@ pub struct NmiRefundRequest { security_key: Secret, transactionid: String, orderid: String, - amount: f64, + amount: FloatMajorUnit, } impl TryFrom<&NmiRouterData<&types::RefundsRouterData>> for NmiRefundRequest { diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs index 680f8d8f260..bf8468a5b0b 100644 --- a/crates/router/src/connector/stripe.rs +++ b/crates/router/src/connector/stripe.rs @@ -48,27 +48,9 @@ impl Stripe { amount_converter: &FloatMajorUnitForConnector, } } +} - pub fn convert_amount( - &self, - i: MinorUnit, - currency: enums::Currency, - ) -> Result> { - self.amount_converter - .convert(i, currency) - .change_context(errors::ConnectorError::ParsingFailed) - } - pub fn convert_back( - &self, - i: FloatMajorUnit, - currency: enums::Currency, - ) -> Result> { - self.amount_converter - .convert_back(i, currency) - .change_context(errors::ConnectorError::ParsingFailed) - } -} impl ConnectorCommonExt for Stripe where @@ -948,9 +930,8 @@ impl req: &types::PaymentsAuthorizeRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let sahkal = self.convert_amount(MinorUnit::new(23), req.request.currency)?; - let sahkal_back_convert = - self.convert_back(FloatMajorUnit::new(1.00), req.request.currency)?; + let _sahkal = connector_utils::convert_amount(self.amount_converter, MinorUnit::new(23), req.request.currency)?; + let _sahkal_back_convert = connector_utils::convert_back(self.amount_converter, FloatMajorUnit::new(1.00), req.request.currency)?; match &req.request.payment_method_data { domain::PaymentMethodData::BankTransfer(bank_transfer_data) => { stripe::get_bank_transfer_request_data(req, bank_transfer_data.deref()) diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 8ff7d350f24..f3b0168f9ec 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -12,7 +12,7 @@ use common_utils::{ errors::ReportSwitchExt, ext_traits::StringExt, pii::{self, Email, IpAddress}, - types::MinorUnit, + types::{MinorUnit, AmountConvertor} }; use diesel_models::enums; use error_stack::{report, ResultExt}; @@ -2617,3 +2617,13 @@ impl From for PaymentMethodDataType { } } } + +pub fn convert_amount(amount_convertor: &dyn AmountConvertor, i: MinorUnit, currency: enums::Currency) -> Result> +{ + amount_convertor.convert(i, currency).change_context(errors::ConnectorError::AmountConversionFailed) +} + +pub fn convert_back(amount_convertor: &dyn AmountConvertor, i: C, currency: enums::Currency) -> Result> { + amount_convertor.convert_back(i, currency) + .change_context(errors::ConnectorError::AmountConversionFailed) +} \ No newline at end of file diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs index a70a97e7bf0..22726524356 100644 --- a/crates/router/src/core/errors.rs +++ b/crates/router/src/core/errors.rs @@ -218,6 +218,8 @@ pub enum ConnectorError { }, #[error("Invalid Configuration")] InvalidConnectorConfig { config: &'static str }, + #[error("Failed to convert amount to required type")] + AmountConversionFailed, } #[derive(Debug, thiserror::Error)] diff --git a/crates/router/src/core/errors/utils.rs b/crates/router/src/core/errors/utils.rs index 678a351a4c3..bae10698277 100644 --- a/crates/router/src/core/errors/utils.rs +++ b/crates/router/src/core/errors/utils.rs @@ -217,7 +217,8 @@ impl ConnectorErrorExt for error_stack::Result | errors::ConnectorError::InSufficientBalanceInPaymentMethod | errors::ConnectorError::RequestTimeoutReceived | errors::ConnectorError::CurrencyNotSupported { .. } - | errors::ConnectorError::InvalidConnectorConfig { .. } => { + | errors::ConnectorError::InvalidConnectorConfig { .. } + | errors::ConnectorError::AmountConversionFailed { .. } => { err.change_context(errors::ApiErrorResponse::RefundFailed { data: None }) } }) @@ -311,7 +312,8 @@ impl ConnectorErrorExt for error_stack::Result errors::ConnectorError::MissingPaymentMethodType | errors::ConnectorError::InSufficientBalanceInPaymentMethod | errors::ConnectorError::RequestTimeoutReceived | - errors::ConnectorError::ProcessingStepFailed(None) => errors::ApiErrorResponse::InternalServerError + errors::ConnectorError::ProcessingStepFailed(None)| + errors::ConnectorError::AmountConversionFailed => errors::ApiErrorResponse::InternalServerError }; err.change_context(error) }) @@ -401,7 +403,8 @@ impl ConnectorErrorExt for error_stack::Result | errors::ConnectorError::InSufficientBalanceInPaymentMethod | errors::ConnectorError::RequestTimeoutReceived | errors::ConnectorError::CurrencyNotSupported { .. } - | errors::ConnectorError::ProcessingStepFailed(None) => { + | errors::ConnectorError::ProcessingStepFailed(None) + | errors::ConnectorError::AmountConversionFailed { .. } => { logger::error!(%error,"Setup Mandate flow failed"); errors::ApiErrorResponse::PaymentAuthorizationFailed { data: None } } diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index f5229e7e410..6f11cabefea 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -1174,6 +1174,7 @@ impl TryFrom> for types::PaymentsAuthoriz statement_descriptor: payment_data.payment_intent.statement_descriptor_name, capture_method: payment_data.payment_attempt.capture_method, amount: amount.get_amount_as_i64(), + test_amount: Some(amount), currency: payment_data.currency, browser_info, email: payment_data.email, diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 0afef760517..cc91d9f0a0c 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -326,6 +326,7 @@ pub struct PaymentsAuthorizeData { /// get_total_surcharge_amount() // returns surcharge_amount + tax_on_surcharge_amount /// ``` pub amount: i64, + pub test_amount : Option, pub email: Option, pub customer_name: Option>, pub currency: storage_enums::Currency, @@ -1311,6 +1312,7 @@ impl From<&SetupMandateRouterData> for PaymentsAuthorizeData { email: data.request.email.clone(), customer_name: data.request.customer_name.clone(), amount: 0, + test_amount: Some(MinorUnit::new(0)), statement_descriptor: None, capture_method: None, webhook_url: None, diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 24037417068..363c8f72220 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -28,6 +28,7 @@ pub mod webhooks; use std::{fmt::Debug, str::FromStr}; +use common_utils::types::AmountConvertor; use error_stack::{report, ResultExt}; #[cfg(feature = "frm")] @@ -148,6 +149,8 @@ pub trait ConnectorCommon { connector_transaction_id: None, }) } + + // fn amount_convertor(&self) -> impl AmountConvertor; } /// Extended trait for connector common to allow functions with generic type @@ -359,7 +362,7 @@ impl ConnectorData { enums::Connector::Klarna => Ok(Box::new(&connector::Klarna)), // enums::Connector::Mifinity => Ok(Box::new(&connector::Mifinity)), Added as template code for future usage enums::Connector::Mollie => Ok(Box::new(&connector::Mollie)), - enums::Connector::Nmi => Ok(Box::new(&connector::Nmi)), + enums::Connector::Nmi => Ok(Box::new(connector::Nmi::new())), enums::Connector::Noon => Ok(Box::new(&connector::Noon)), enums::Connector::Nuvei => Ok(Box::new(&connector::Nuvei)), enums::Connector::Opennode => Ok(Box::new(&connector::Opennode)), diff --git a/crates/router/src/types/api/verify_connector.rs b/crates/router/src/types/api/verify_connector.rs index 3df09591fad..bf9a9e73bd6 100644 --- a/crates/router/src/types/api/verify_connector.rs +++ b/crates/router/src/types/api/verify_connector.rs @@ -12,6 +12,8 @@ use crate::{ AppState, }; +use common_utils::types::MinorUnit; + #[derive(Clone)] pub struct VerifyConnectorData { pub connector: &'static (dyn api::Connector + Sync), @@ -26,6 +28,7 @@ impl VerifyConnectorData { email: None, customer_name: None, amount: 1000, + test_amount: Some(MinorUnit::new(1000)), confirm: true, currency: storage_enums::Currency::USD, metadata: None, From f30b3887a58677d1f7666e32f7b475cb856d4b85 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Thu, 23 May 2024 16:29:47 +0530 Subject: [PATCH 28/82] refactor(router): fixed clippy issues --- Cargo.lock | 2 + crates/common_utils/Cargo.toml | 2 + crates/common_utils/src/errors.rs | 9 ++++ crates/common_utils/src/types.rs | 37 ++++++++++--- crates/router/src/connector/nmi.rs | 54 +++++++++++-------- .../router/src/connector/nmi/transformers.rs | 11 ++-- crates/router/src/connector/stripe.rs | 22 ++------ crates/router/src/connector/utils.rs | 26 ++++++--- crates/router/src/types.rs | 2 +- crates/router/src/types/api.rs | 3 +- .../router/src/types/api/verify_connector.rs | 3 +- crates/router/tests/connectors/aci.rs | 1 + crates/router/tests/connectors/adyen.rs | 1 + crates/router/tests/connectors/bitpay.rs | 1 + crates/router/tests/connectors/cashtocode.rs | 1 + crates/router/tests/connectors/coinbase.rs | 1 + crates/router/tests/connectors/cryptopay.rs | 1 + crates/router/tests/connectors/nmi.rs | 2 +- crates/router/tests/connectors/opennode.rs | 1 + crates/router/tests/connectors/utils.rs | 1 + crates/router/tests/connectors/worldline.rs | 1 + 21 files changed, 111 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc4815e8b07..502912eff0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1966,7 +1966,9 @@ dependencies = [ "reqwest", "ring 0.17.8", "router_env", + "rust_decimal", "rustc-hash", + "rusty-money", "semver 1.0.22", "serde", "serde_json", diff --git a/crates/common_utils/Cargo.toml b/crates/common_utils/Cargo.toml index e6fd27da31a..2e51bd8b564 100644 --- a/crates/common_utils/Cargo.toml +++ b/crates/common_utils/Cargo.toml @@ -43,6 +43,8 @@ uuid = { version = "1.8.0", features = ["v7"] } utoipa = { version = "4.2.0", features = ["preserve_order", "preserve_path_order"] } # First party crates +rust_decimal = "1.35" +rusty-money = { git = "https://github.com/varunsrin/rusty_money", rev = "bbc0150742a0fff905225ff11ee09388e9babdcc", features = ["iso", "crypto"] } common_enums = { version = "0.1.0", path = "../common_enums" } masking = { version = "0.1.0", path = "../masking" } router_env = { version = "0.1.0", path = "../router_env", features = ["log_extra_implicit_fields", "log_custom_entries_to_extra"], optional = true } diff --git a/crates/common_utils/src/errors.rs b/crates/common_utils/src/errors.rs index 967580f0ae5..861b4eae0d8 100644 --- a/crates/common_utils/src/errors.rs +++ b/crates/common_utils/src/errors.rs @@ -34,6 +34,15 @@ pub enum ParsingError { /// Failed to parse phone number #[error("Failed to parse phone number")] PhoneNumberParsingError, + /// Failed to convert amount value to Decimal value + #[error("Failed to parse Float value for converting to decimal points")] + FloatToDecimalConversionFailure, + /// Failed to convert Float value to Decimal value + #[error("Failed to parse Decimal value for i64 value conversion")] + DecimalToI64ConversionFailure, + /// Failed to convert String value to Float value + #[error("Failed to parse string value for f64 value conversion")] + StringToFloatConversionFailure, } /// Validation errors. diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 629db5e5b13..e620cbb23a2 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -18,6 +18,10 @@ use diesel::{ AsExpression, FromSqlRow, Queryable, }; use error_stack::{report, ResultExt}; +use rust_decimal::{ + prelude::{FromPrimitive, ToPrimitive}, + Decimal, +}; use semver::Version; use serde::{de::Visitor, Deserialize, Deserializer}; use utoipa::ToSchema; @@ -244,7 +248,7 @@ pub trait AmountConvertor: Send { &self, i: Self::Output, currency: enums::Currency, - ) -> Result; + ) -> Result>; } /// Connector required amount type @@ -265,7 +269,7 @@ impl AmountConvertor for StringMajorUnitForConnector { &self, i: StringMajorUnit, currency: enums::Currency, - ) -> Result { + ) -> Result> { i.to_minor_unit_as_i64(currency) } } @@ -287,7 +291,7 @@ impl AmountConvertor for FloatMajorUnitForConnector { &self, i: FloatMajorUnit, currency: enums::Currency, - ) -> Result { + ) -> Result> { i.to_minor_unit_as_i64(currency) } } @@ -449,7 +453,7 @@ impl FloatMajorUnit { pub fn to_minor_unit_as_i64( &self, currency: enums::Currency, - ) -> Result { + ) -> Result> { let amount_f64 = self.0; let amount = if currency.is_zero_decimal_currency() { amount_f64 @@ -458,7 +462,14 @@ impl FloatMajorUnit { } else { amount_f64 * 100.00 }; - Ok(MinorUnit::new(amount as i64)) + + let amount_decimal = + Decimal::from_f64(amount).ok_or(ParsingError::FloatToDecimalConversionFailure)?; + let amount_decimal_scaled = amount_decimal.round(); + let amount_i64 = amount_decimal_scaled + .to_i64() + .ok_or(ParsingError::DecimalToI64ConversionFailure)?; + Ok(MinorUnit::new(amount_i64)) } } @@ -476,8 +487,11 @@ impl StringMajorUnit { pub fn to_minor_unit_as_i64( &self, currency: enums::Currency, - ) -> Result { - let amount_f64 = self.0.parse::()?; + ) -> Result> { + let amount_f64 = self + .0 + .parse::() + .change_context(ParsingError::StringToFloatConversionFailure)?; let amount = if currency.is_zero_decimal_currency() { amount_f64 } else if currency.is_three_decimal_currency() { @@ -485,6 +499,13 @@ impl StringMajorUnit { } else { amount_f64 * 100.00 }; - Ok(MinorUnit::new(amount as i64)) + + let amount_decimal = + Decimal::from_f64(amount).ok_or(ParsingError::FloatToDecimalConversionFailure)?; + let amount_decimal_scaled = amount_decimal.round(); + let amount_i64 = amount_decimal_scaled + .to_i64() + .ok_or(ParsingError::DecimalToI64ConversionFailure)?; + Ok(MinorUnit::new(amount_i64)) } } diff --git a/crates/router/src/connector/nmi.rs b/crates/router/src/connector/nmi.rs index be63774b87e..46f592ef1b4 100644 --- a/crates/router/src/connector/nmi.rs +++ b/crates/router/src/connector/nmi.rs @@ -1,7 +1,11 @@ pub mod transformers; - -use common_utils::{crypto, ext_traits::ByteSliceExt, request::RequestContent, types::{FloatMajorUnit, FloatMajorUnitForConnector, MinorUnit, AmountConvertor}}; +use common_utils::{ + crypto, + ext_traits::ByteSliceExt, + request::RequestContent, + types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector, MinorUnit}, +}; use diesel_models::enums; use error_stack::{report, ResultExt}; use regex::Regex; @@ -338,11 +342,14 @@ impl ConnectorIntegration CustomResult { - let amount = connector_utils::convert_amount(self.amount_converter, req.request.test_amount.unwrap_or(MinorUnit::new(req.request.amount)), req.request.currency)?; - let connector_router_data = nmi::NmiRouterData::from(( - amount, - req, - )); + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request + .test_amount + .unwrap_or(MinorUnit::new(req.request.amount)), + req.request.currency, + )?; + let connector_router_data = nmi::NmiRouterData::from((amount, req)); let connector_req = nmi::NmiPaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } @@ -425,11 +432,12 @@ impl req: &types::PaymentsCompleteAuthorizeRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let amount = connector_utils::convert_amount(self.amount_converter, MinorUnit::new(req.request.amount), req.request.currency)?; - let connector_router_data = nmi::NmiRouterData::from(( - amount, - req, - )); + let amount = connector_utils::convert_amount( + self.amount_converter, + MinorUnit::new(req.request.amount), + req.request.currency, + )?; + let connector_router_data = nmi::NmiRouterData::from((amount, req)); let connector_req = nmi::NmiCompleteRequest::try_from(&connector_router_data)?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } @@ -576,11 +584,12 @@ impl ConnectorIntegration CustomResult { - let amount = connector_utils::convert_amount(self.amount_converter, MinorUnit::new(req.request.amount_to_capture), req.request.currency)?; - let connector_router_data = nmi::NmiRouterData::from(( - amount, - req, - )); + let amount = connector_utils::convert_amount( + self.amount_converter, + MinorUnit::new(req.request.amount_to_capture), + req.request.currency, + )?; + let connector_router_data = nmi::NmiRouterData::from((amount, req)); let connector_req = nmi::NmiCaptureRequest::try_from(&connector_router_data)?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } @@ -723,12 +732,13 @@ impl ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { - let refund_amount = connector_utils::convert_amount(self.amount_converter, MinorUnit::new(req.request.refund_amount), req.request.currency)?; + let refund_amount = connector_utils::convert_amount( + self.amount_converter, + MinorUnit::new(req.request.refund_amount), + req.request.currency, + )?; - let connector_router_data = nmi::NmiRouterData::from(( - refund_amount, - req, - )); + let connector_router_data = nmi::NmiRouterData::from((refund_amount, req)); let connector_req = nmi::NmiRefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } diff --git a/crates/router/src/connector/nmi/transformers.rs b/crates/router/src/connector/nmi/transformers.rs index e7230a3207c..ec68f37d645 100644 --- a/crates/router/src/connector/nmi/transformers.rs +++ b/crates/router/src/connector/nmi/transformers.rs @@ -5,7 +5,7 @@ use common_utils::{ errors::CustomResult, ext_traits::XmlExt, pii::{self, Email}, - types::FloatMajorUnit + types::FloatMajorUnit, }; use error_stack::{report, Report, ResultExt}; use masking::{ExposeInterface, PeekInterface, Secret}; @@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize}; use crate::{ connector::utils::{ self, AddressDetailsData, PaymentsAuthorizeRequestData, - PaymentsCompleteAuthorizeRequestData, RouterData + PaymentsCompleteAuthorizeRequestData, RouterData, }, core::errors, services, @@ -65,12 +65,7 @@ pub struct NmiRouterData { impl From<(FloatMajorUnit, T)> for NmiRouterData { // type Error = Report; - fn from( - (amount, router_data): ( - FloatMajorUnit, - T, - ), - ) -> Self { + fn from((amount, router_data): (FloatMajorUnit, T)) -> Self { Self { // amount: utils::to_currency_base_unit_asf64(amount, currency)?, amount, diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs index bf8468a5b0b..bed146a37e4 100644 --- a/crates/router/src/connector/stripe.rs +++ b/crates/router/src/connector/stripe.rs @@ -2,10 +2,7 @@ pub mod transformers; use std::{collections::HashMap, ops::Deref}; -use common_utils::{ - request::RequestContent, - types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector, MinorUnit}, -}; +use common_utils::request::RequestContent; use diesel_models::enums; use error_stack::ResultExt; use masking::PeekInterface; @@ -38,19 +35,8 @@ use crate::{ utils::{crypto, ByteSliceExt, BytesExt, OptionExt}, }; -pub struct Stripe { - amount_converter: &'static (dyn AmountConvertor + Sync), -} - -impl Stripe { - pub const fn new() -> &'static Self { - &Self { - amount_converter: &FloatMajorUnitForConnector, - } - } -} - - +#[derive(Debug, Clone)] +pub struct Stripe; impl ConnectorCommonExt for Stripe where @@ -930,8 +916,6 @@ impl req: &types::PaymentsAuthorizeRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let _sahkal = connector_utils::convert_amount(self.amount_converter, MinorUnit::new(23), req.request.currency)?; - let _sahkal_back_convert = connector_utils::convert_back(self.amount_converter, FloatMajorUnit::new(1.00), req.request.currency)?; match &req.request.payment_method_data { domain::PaymentMethodData::BankTransfer(bank_transfer_data) => { stripe::get_bank_transfer_request_data(req, bank_transfer_data.deref()) diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index f3b0168f9ec..796d1debeac 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -12,7 +12,7 @@ use common_utils::{ errors::ReportSwitchExt, ext_traits::StringExt, pii::{self, Email, IpAddress}, - types::{MinorUnit, AmountConvertor} + types::{AmountConvertor, MinorUnit}, }; use diesel_models::enums; use error_stack::{report, ResultExt}; @@ -2618,12 +2618,22 @@ impl From for PaymentMethodDataType { } } -pub fn convert_amount(amount_convertor: &dyn AmountConvertor, i: MinorUnit, currency: enums::Currency) -> Result> -{ - amount_convertor.convert(i, currency).change_context(errors::ConnectorError::AmountConversionFailed) +pub fn convert_amount( + amount_convertor: &dyn AmountConvertor, + i: MinorUnit, + currency: enums::Currency, +) -> Result> { + amount_convertor + .convert(i, currency) + .change_context(errors::ConnectorError::AmountConversionFailed) } -pub fn convert_back(amount_convertor: &dyn AmountConvertor, i: C, currency: enums::Currency) -> Result> { - amount_convertor.convert_back(i, currency) - .change_context(errors::ConnectorError::AmountConversionFailed) -} \ No newline at end of file +pub fn convert_back( + amount_convertor: &dyn AmountConvertor, + i: C, + currency: enums::Currency, +) -> Result> { + amount_convertor + .convert_back(i, currency) + .change_context(errors::ConnectorError::AmountConversionFailed) +} diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index cc91d9f0a0c..50172992a33 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -326,7 +326,7 @@ pub struct PaymentsAuthorizeData { /// get_total_surcharge_amount() // returns surcharge_amount + tax_on_surcharge_amount /// ``` pub amount: i64, - pub test_amount : Option, + pub test_amount: Option, pub email: Option, pub customer_name: Option>, pub currency: storage_enums::Currency, diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 363c8f72220..bee6a7861ff 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -28,7 +28,6 @@ pub mod webhooks; use std::{fmt::Debug, str::FromStr}; -use common_utils::types::AmountConvertor; use error_stack::{report, ResultExt}; #[cfg(feature = "frm")] @@ -377,7 +376,7 @@ impl ConnectorData { enums::Connector::Shift4 => Ok(Box::new(&connector::Shift4)), enums::Connector::Square => Ok(Box::new(&connector::Square)), enums::Connector::Stax => Ok(Box::new(&connector::Stax)), - enums::Connector::Stripe => Ok(Box::new(connector::Stripe::new())), + enums::Connector::Stripe => Ok(Box::new(&connector::Stripe)), enums::Connector::Wise => Ok(Box::new(&connector::Wise)), enums::Connector::Worldline => Ok(Box::new(&connector::Worldline)), enums::Connector::Worldpay => Ok(Box::new(&connector::Worldpay)), diff --git a/crates/router/src/types/api/verify_connector.rs b/crates/router/src/types/api/verify_connector.rs index bf9a9e73bd6..3f622bbaeb3 100644 --- a/crates/router/src/types/api/verify_connector.rs +++ b/crates/router/src/types/api/verify_connector.rs @@ -1,6 +1,7 @@ pub mod paypal; pub mod stripe; +use common_utils::types::MinorUnit; use error_stack::ResultExt; use crate::{ @@ -12,8 +13,6 @@ use crate::{ AppState, }; -use common_utils::types::MinorUnit; - #[derive(Clone)] pub struct VerifyConnectorData { pub connector: &'static (dyn api::Connector + Sync), diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs index 3548bc5e5bd..c96cabb25ea 100644 --- a/crates/router/tests/connectors/aci.rs +++ b/crates/router/tests/connectors/aci.rs @@ -35,6 +35,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData { payment_method_status: None, request: types::PaymentsAuthorizeData { amount: 1000, + test_amount: None, currency: enums::Currency::USD, payment_method_data: types::domain::PaymentMethodData::Card(types::domain::Card { card_number: cards::CardNumber::from_str("4200000000000000").unwrap(), diff --git a/crates/router/tests/connectors/adyen.rs b/crates/router/tests/connectors/adyen.rs index 4d4318064e2..acbbec99a49 100644 --- a/crates/router/tests/connectors/adyen.rs +++ b/crates/router/tests/connectors/adyen.rs @@ -141,6 +141,7 @@ impl AdyenTest { capture_method: enums::CaptureMethod, ) -> Option { Some(types::PaymentsAuthorizeData { + test_amount: None, amount: 3500, currency: enums::Currency::USD, payment_method_data: types::domain::PaymentMethodData::Card(types::domain::Card { diff --git a/crates/router/tests/connectors/bitpay.rs b/crates/router/tests/connectors/bitpay.rs index 2dd90e704b9..77e0b2c3f42 100644 --- a/crates/router/tests/connectors/bitpay.rs +++ b/crates/router/tests/connectors/bitpay.rs @@ -66,6 +66,7 @@ fn get_default_payment_info() -> Option { fn payment_method_details() -> Option { Some(types::PaymentsAuthorizeData { + test_amount: None, amount: 1, currency: enums::Currency::USD, payment_method_data: domain::PaymentMethodData::Crypto(domain::CryptoData { diff --git a/crates/router/tests/connectors/cashtocode.rs b/crates/router/tests/connectors/cashtocode.rs index 60620d1b4c4..c14ac1436c2 100644 --- a/crates/router/tests/connectors/cashtocode.rs +++ b/crates/router/tests/connectors/cashtocode.rs @@ -42,6 +42,7 @@ impl CashtocodeTest { payment_method_data: domain::PaymentMethodData, ) -> Option { Some(types::PaymentsAuthorizeData { + test_amount: None, amount: 1000, currency: enums::Currency::EUR, payment_method_data, diff --git a/crates/router/tests/connectors/coinbase.rs b/crates/router/tests/connectors/coinbase.rs index 5dd42a2c97c..3fa41134036 100644 --- a/crates/router/tests/connectors/coinbase.rs +++ b/crates/router/tests/connectors/coinbase.rs @@ -68,6 +68,7 @@ fn get_default_payment_info() -> Option { fn payment_method_details() -> Option { Some(types::PaymentsAuthorizeData { + test_amount: None, amount: 1, currency: enums::Currency::USD, payment_method_data: domain::PaymentMethodData::Crypto(domain::CryptoData { diff --git a/crates/router/tests/connectors/cryptopay.rs b/crates/router/tests/connectors/cryptopay.rs index c26bad8c567..94fc20c7336 100644 --- a/crates/router/tests/connectors/cryptopay.rs +++ b/crates/router/tests/connectors/cryptopay.rs @@ -67,6 +67,7 @@ fn get_default_payment_info() -> Option { fn payment_method_details() -> Option { Some(types::PaymentsAuthorizeData { + test_amount: None, amount: 1, currency: enums::Currency::USD, payment_method_data: domain::PaymentMethodData::Crypto(domain::CryptoData { diff --git a/crates/router/tests/connectors/nmi.rs b/crates/router/tests/connectors/nmi.rs index 1d719e052a0..d5f1ebd4fad 100644 --- a/crates/router/tests/connectors/nmi.rs +++ b/crates/router/tests/connectors/nmi.rs @@ -13,7 +13,7 @@ impl utils::Connector for NmiTest { fn get_data(&self) -> types::api::ConnectorData { use router::connector::Nmi; types::api::ConnectorData { - connector: Box::new(&Nmi), + connector: Box::new(Nmi::new()), connector_name: types::Connector::Nmi, get_token: types::api::GetToken::Connector, merchant_connector_id: None, diff --git a/crates/router/tests/connectors/opennode.rs b/crates/router/tests/connectors/opennode.rs index 1e2cea554e9..d4a74e5e2aa 100644 --- a/crates/router/tests/connectors/opennode.rs +++ b/crates/router/tests/connectors/opennode.rs @@ -67,6 +67,7 @@ fn get_default_payment_info() -> Option { fn payment_method_details() -> Option { Some(types::PaymentsAuthorizeData { + test_amount: None, amount: 1, currency: enums::Currency::USD, payment_method_data: domain::PaymentMethodData::Crypto(domain::CryptoData { diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index cd1a44a7022..7b066773ad3 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -912,6 +912,7 @@ impl Default for CCardType { impl Default for PaymentAuthorizeType { fn default() -> Self { let data = types::PaymentsAuthorizeData { + test_amount: None, payment_method_data: types::domain::PaymentMethodData::Card(CCardType::default().0), amount: 100, currency: enums::Currency::USD, diff --git a/crates/router/tests/connectors/worldline.rs b/crates/router/tests/connectors/worldline.rs index 36d0bba6c46..0345776effc 100644 --- a/crates/router/tests/connectors/worldline.rs +++ b/crates/router/tests/connectors/worldline.rs @@ -70,6 +70,7 @@ impl WorldlineTest { capture_method: enums::CaptureMethod, ) -> Option { Some(types::PaymentsAuthorizeData { + test_amount: None, amount: 3500, currency: enums::Currency::USD, payment_method_data: types::domain::PaymentMethodData::Card(types::domain::Card { From fc05741dc3b7b17c5583d781e423456182d87d0f Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Thu, 23 May 2024 11:16:00 +0000 Subject: [PATCH 29/82] docs(openapi): re-generate OpenAPI specification --- openapi/openapi_spec.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index b67d15c7b9d..26eb8997c17 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -10276,7 +10276,10 @@ ], "properties": { "amount": { - "$ref": "#/components/schemas/MinorUnit" + "type": "integer", + "format": "int64", + "description": "The maximum amount to be debited for the mandate transaction", + "example": 6540 }, "currency": { "$ref": "#/components/schemas/Currency" @@ -14403,7 +14406,10 @@ ], "properties": { "amount": { - "$ref": "#/components/schemas/MinorUnit" + "type": "integer", + "format": "int64", + "description": "The total amount including previously authorized amount and additional amount", + "example": 6540 }, "reason": { "type": "string", From db98d60529c0bc17050b114adcbbcb70165db395 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Thu, 23 May 2024 16:48:35 +0530 Subject: [PATCH 30/82] refactor(router):fixed open-api issue --- openapi/openapi_spec.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index b67d15c7b9d..26eb8997c17 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -10276,7 +10276,10 @@ ], "properties": { "amount": { - "$ref": "#/components/schemas/MinorUnit" + "type": "integer", + "format": "int64", + "description": "The maximum amount to be debited for the mandate transaction", + "example": 6540 }, "currency": { "$ref": "#/components/schemas/Currency" @@ -14403,7 +14406,10 @@ ], "properties": { "amount": { - "$ref": "#/components/schemas/MinorUnit" + "type": "integer", + "format": "int64", + "description": "The total amount including previously authorized amount and additional amount", + "example": 6540 }, "reason": { "type": "string", From d94ef10921c7e3dd696425e445db83673874bfcf Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Thu, 23 May 2024 16:55:48 +0530 Subject: [PATCH 31/82] refactor(router): removed unnecessary code --- .../src/router_data.rs | 1 - crates/router/src/connector/utils.rs | 18 +++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs index d542d175ab1..d0481cecc53 100644 --- a/crates/hyperswitch_domain_models/src/router_data.rs +++ b/crates/hyperswitch_domain_models/src/router_data.rs @@ -8,7 +8,6 @@ use crate::payment_address::PaymentAddress; pub struct RouterData { pub flow: PhantomData, pub merchant_id: String, - // pub amount : Option, pub customer_id: Option, pub connector_customer: Option, pub connector: String, diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 796d1debeac..d12c680e738 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -2618,22 +2618,22 @@ impl From for PaymentMethodDataType { } } -pub fn convert_amount( - amount_convertor: &dyn AmountConvertor, - i: MinorUnit, +pub fn convert_amount( + amount_convertor: &dyn AmountConvertor, + amount: MinorUnit, currency: enums::Currency, -) -> Result> { +) -> Result> { amount_convertor - .convert(i, currency) + .convert(amount, currency) .change_context(errors::ConnectorError::AmountConversionFailed) } -pub fn convert_back( - amount_convertor: &dyn AmountConvertor, - i: C, +pub fn convert_back( + amount_convertor: &dyn AmountConvertor, + amount: T, currency: enums::Currency, ) -> Result> { amount_convertor - .convert_back(i, currency) + .convert_back(amount, currency) .change_context(errors::ConnectorError::AmountConversionFailed) } From 4910dec5dadbb8867029800218bb1344ee2c8083 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 27 May 2024 20:18:28 +0530 Subject: [PATCH 32/82] refactor(router): added unit test case for amount conversions --- crates/common_utils/src/errors.rs | 6 ++ crates/common_utils/src/types.rs | 155 ++++++++++++++++++++++++++---- 2 files changed, 140 insertions(+), 21 deletions(-) diff --git a/crates/common_utils/src/errors.rs b/crates/common_utils/src/errors.rs index 861b4eae0d8..6ec39a01a9a 100644 --- a/crates/common_utils/src/errors.rs +++ b/crates/common_utils/src/errors.rs @@ -43,6 +43,12 @@ pub enum ParsingError { /// Failed to convert String value to Float value #[error("Failed to parse string value for f64 value conversion")] StringToFloatConversionFailure, + /// Failed to convert String value to Float value + #[error("Failed to parse i64 value for f64 value conversion")] + I64ToDecimalConversionFailure, + /// Failed to convert String value to Float value + #[error("Failed to parse String value to Decimal value conversion")] + StringToDecimalConversionFailure, } /// Validation errors. diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index e620cbb23a2..9c0cc0c0f52 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -1,7 +1,6 @@ //! Types that can be used in other crates use std::{ fmt::Display, - num::{ParseFloatError, TryFromIntError}, ops::{Add, Sub}, primitive::i64, str::FromStr, @@ -241,7 +240,7 @@ pub trait AmountConvertor: Send { &self, i: MinorUnit, currency: enums::Currency, - ) -> Result; + ) -> Result>; /// helps in converting back connector required amount type to core minor unit fn convert_back( @@ -251,6 +250,29 @@ pub trait AmountConvertor: Send { ) -> Result>; } +/// Connector required amount type +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] +pub struct StringMinorUnitForConnector; + +impl AmountConvertor for StringMinorUnitForConnector { + type Output = StringMinorUnit; + fn convert( + &self, + i: MinorUnit, + _currency: enums::Currency, + ) -> Result> { + i.to_minor_unit_as_string() + } + + fn convert_back( + &self, + i: Self::Output, + _currency: enums::Currency, + ) -> Result> { + i.to_minor_unit_as_i64() + } +} + /// Connector required amount type #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] pub struct StringMajorUnitForConnector; @@ -261,7 +283,7 @@ impl AmountConvertor for StringMajorUnitForConnector { &self, i: MinorUnit, currency: enums::Currency, - ) -> Result { + ) -> Result> { i.to_major_unit_as_string(currency) } @@ -284,7 +306,7 @@ impl AmountConvertor for FloatMajorUnitForConnector { &self, i: MinorUnit, currency: enums::Currency, - ) -> Result { + ) -> Result> { i.to_major_unit_asf64(currency) } fn convert_back( @@ -315,9 +337,8 @@ impl AmountConvertor for FloatMajorUnitForConnector { pub struct MinorUnit(i64); impl MinorUnit { - /// gets amount as i64 value + /// gets amount as i64 value will be removed in future pub fn get_amount_as_i64(&self) -> i64 { - // will be removed in future self.0 } @@ -330,7 +351,7 @@ impl MinorUnit { pub fn to_major_unit_as_string( &self, currency: enums::Currency, - ) -> Result { + ) -> Result> { let amount_f64 = self.to_major_unit_asf64(currency)?; let amount_string = format!("{:.2}", amount_f64.0); Ok(StringMajorUnit::new(amount_string)) @@ -340,8 +361,12 @@ impl MinorUnit { pub fn to_major_unit_asf64( &self, currency: enums::Currency, - ) -> Result { - let amount_f64: f64 = u32::try_from(self.0)?.into(); + ) -> Result> { + let amount_decimal = + Decimal::from_i64(self.0).ok_or(ParsingError::I64ToDecimalConversionFailure)?; + let amount_f64 = amount_decimal + .to_f64() + .ok_or(ParsingError::FloatToDecimalConversionFailure)?; let amount = if currency.is_zero_decimal_currency() { amount_f64 } else if currency.is_three_decimal_currency() { @@ -355,17 +380,10 @@ impl MinorUnit { ///Convert the higher decimal amount to its major absolute units pub fn to_minor_unit_as_string( &self, - currency: enums::Currency, - ) -> Result { - let amount_f64 = self.0.to_string().parse::()?; - let amount_string = if currency.is_zero_decimal_currency() { - amount_f64 - } else if currency.is_three_decimal_currency() { - amount_f64 * 1000.00 - } else { - amount_f64 * 100.00 - }; - Ok(amount_string.to_string()) + ) -> Result> { + let amount_decimal = + Decimal::from_i64(self.0).ok_or(ParsingError::I64ToDecimalConversionFailure)?; + Ok(StringMinorUnit::new(amount_decimal.to_string())) } /// Convert the amount to its major denomination based on Currency and check for zero decimal currency and return String @@ -374,7 +392,7 @@ impl MinorUnit { pub fn to_major_unit_as_string_with_zero_decimal_check( &self, currency: enums::Currency, - ) -> Result { + ) -> Result> { let amount_f64 = self.to_major_unit_asf64(currency)?; if currency.is_zero_decimal_currency() { Ok(StringMajorUnit::new(amount_f64.0.to_string())) @@ -440,6 +458,29 @@ impl Sub for MinorUnit { /// Connector specific types to send +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq)] +pub struct StringMinorUnit(String); + +impl StringMinorUnit { + /// forms a new minor unit in string from amount + pub fn new(value: String) -> Self { + Self(value) + } + + /// converts to i64 from minor unit string value + pub fn to_minor_unit_as_i64(&self) -> Result> { + let amount_string = &self.0; + let amount_decimal = Decimal::from_str(amount_string) + .map_err(|_| ParsingError::StringToDecimalConversionFailure)?; + let amount_decimal_scaled = amount_decimal.round(); + let amount_i64 = amount_decimal_scaled + .to_i64() + .ok_or(ParsingError::DecimalToI64ConversionFailure)?; + Ok(MinorUnit::new(amount_i64)) + } +} + +/// Connector specific types to send #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] pub struct FloatMajorUnit(f64); @@ -509,3 +550,75 @@ impl StringMajorUnit { Ok(MinorUnit::new(amount_i64)) } } + +#[cfg(test)] +mod amount_conversion_tests { + use super::*; + // #[test] + // fn max_bound_amount_conversion_to_float_major_unit(){ + // let max_amount = MinorUnit::new(std::i64::MAX); + // let currency = enums::Currency::USD; + // let required_conversion = FloatMajorUnitForConnector; + // let conversion_amount = required_conversion.convert(max_amount, currency).unwrap(); + // assert_eq!(conversion_amount.0, 92233720368547758.07); + // let converted_back_amount = required_conversion.convert_back(conversion_amount, currency).unwrap(); + // assert_eq!(converted_back_amount, max_amount); + // } + + // #[test] + // fn max_bound_amount_conversion_to_string_major_unit(){ + // let max_amount = MinorUnit::new(std::i64::MAX); + // // let small_amount = MinorUnit::new(23235); + // // let convertion_in_usd_float = max_amount.to_major_unit_asf64(enums::Currency::USD).unwrap(); + // // println!("float value {:?}", convertion_in_usd_float.0); + // let convertion_in_usd = max_amount.to_major_unit_as_string(enums::Currency::USD).unwrap(); + // println!("string value {:?}", convertion_in_usd); + // // assert_eq!(convertion_in_usd.0, "232.35".to_string()); + // assert_eq!(convertion_in_usd.0, "92233720368547758.07".to_string()); + // } + + #[test] + fn amount_conversion_to_float_major_unit() { + let request_amount = MinorUnit::new(13124364); + let currency = enums::Currency::USD; + let required_conversion = FloatMajorUnitForConnector; + let converted_amount = required_conversion + .convert(request_amount, currency) + .unwrap(); + assert_eq!(converted_amount.0, 131243.64); + let converted_back_amount = required_conversion + .convert_back(converted_amount, currency) + .unwrap(); + assert_eq!(converted_back_amount, request_amount); + } + + #[test] + fn amount_conversion_to_string_major_unit() { + let request_amount = MinorUnit::new(13124364); + let currency = enums::Currency::USD; + let required_conversion = StringMajorUnitForConnector; + let converted_amount = required_conversion + .convert(request_amount, currency) + .unwrap(); + assert_eq!(converted_amount.0, "131243.64".to_string()); + let converted_back_amount = required_conversion + .convert_back(converted_amount, currency) + .unwrap(); + assert_eq!(converted_back_amount, request_amount); + } + + #[test] + fn amount_conversion_to_string_minor_unit() { + let request_amount = MinorUnit::new(13124364); + let currency = enums::Currency::USD; + let required_conversion = StringMinorUnitForConnector; + let converted_amount = required_conversion + .convert(request_amount, currency) + .unwrap(); + assert_eq!(converted_amount.0, "13124364".to_string()); + let converted_back_amount = required_conversion + .convert_back(converted_amount, currency) + .unwrap(); + assert_eq!(converted_back_amount, request_amount); + } +} From 37f5b1cb19d886f1557504f72e2f7a3a7fa0100b Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 27 May 2024 20:40:10 +0530 Subject: [PATCH 33/82] refactor(router): added unit case for three_decimal_currency --- crates/common_utils/src/types.rs | 57 +++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 9c0cc0c0f52..5ea78c3393b 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -353,7 +353,11 @@ impl MinorUnit { currency: enums::Currency, ) -> Result> { let amount_f64 = self.to_major_unit_asf64(currency)?; - let amount_string = format!("{:.2}", amount_f64.0); + let amount_string = if currency.is_three_decimal_currency() { + format!("{:.3}", amount_f64.0) + } else { + format!("{:.2}", amount_f64.0) + }; Ok(StringMajorUnit::new(amount_string)) } @@ -580,14 +584,27 @@ mod amount_conversion_tests { #[test] fn amount_conversion_to_float_major_unit() { let request_amount = MinorUnit::new(13124364); - let currency = enums::Currency::USD; + let two_decimal_currency = enums::Currency::USD; + let three_decimal_currency = enums::Currency::BHD; let required_conversion = FloatMajorUnitForConnector; + + // Two decimal currency conversions let converted_amount = required_conversion - .convert(request_amount, currency) + .convert(request_amount, two_decimal_currency) .unwrap(); assert_eq!(converted_amount.0, 131243.64); let converted_back_amount = required_conversion - .convert_back(converted_amount, currency) + .convert_back(converted_amount, two_decimal_currency) + .unwrap(); + assert_eq!(converted_back_amount, request_amount); + + // Three decimal currency conversions + let converted_amount = required_conversion + .convert(request_amount, three_decimal_currency) + .unwrap(); + assert_eq!(converted_amount.0, 13124.364); + let converted_back_amount = required_conversion + .convert_back(converted_amount, three_decimal_currency) .unwrap(); assert_eq!(converted_back_amount, request_amount); } @@ -595,14 +612,36 @@ mod amount_conversion_tests { #[test] fn amount_conversion_to_string_major_unit() { let request_amount = MinorUnit::new(13124364); - let currency = enums::Currency::USD; + let two_decimal_currency = enums::Currency::USD; + let three_decimal_currency = enums::Currency::BHD; let required_conversion = StringMajorUnitForConnector; - let converted_amount = required_conversion - .convert(request_amount, currency) + + // Two decimal currency conversions + let converted_amount_two_decimal_currency = required_conversion + .convert(request_amount, two_decimal_currency) .unwrap(); - assert_eq!(converted_amount.0, "131243.64".to_string()); + assert_eq!( + converted_amount_two_decimal_currency.0, + "131243.64".to_string() + ); let converted_back_amount = required_conversion - .convert_back(converted_amount, currency) + .convert_back(converted_amount_two_decimal_currency, two_decimal_currency) + .unwrap(); + assert_eq!(converted_back_amount, request_amount); + + // Three decimal currency conversions + let converted_amount_three_decimal_currency = required_conversion + .convert(request_amount, three_decimal_currency) + .unwrap(); + assert_eq!( + converted_amount_three_decimal_currency.0, + "13124.364".to_string() + ); + let converted_back_amount = required_conversion + .convert_back( + converted_amount_three_decimal_currency, + three_decimal_currency, + ) .unwrap(); assert_eq!(converted_back_amount, request_amount); } From bc00c6301a243a3844e577654a4f7ddb7a8cd15e Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Tue, 28 May 2024 14:51:43 +0530 Subject: [PATCH 34/82] refactor(router): addressed pr comments --- crates/common_utils/src/errors.rs | 10 ++-- crates/common_utils/src/types.rs | 47 +++++-------------- crates/router/src/connector/nmi.rs | 7 +-- .../router/src/connector/nmi/transformers.rs | 2 - .../router/src/core/payments/transformers.rs | 1 - crates/router/src/types.rs | 2 - crates/router/src/types/api.rs | 1 - .../router/src/types/api/verify_connector.rs | 3 -- 8 files changed, 18 insertions(+), 55 deletions(-) diff --git a/crates/common_utils/src/errors.rs b/crates/common_utils/src/errors.rs index 6ec39a01a9a..7108aa105cc 100644 --- a/crates/common_utils/src/errors.rs +++ b/crates/common_utils/src/errors.rs @@ -34,19 +34,19 @@ pub enum ParsingError { /// Failed to parse phone number #[error("Failed to parse phone number")] PhoneNumberParsingError, - /// Failed to convert amount value to Decimal value + /// Failed to parse Float value for converting to decimal points #[error("Failed to parse Float value for converting to decimal points")] FloatToDecimalConversionFailure, - /// Failed to convert Float value to Decimal value + /// Failed to parse Decimal value for i64 value conversion #[error("Failed to parse Decimal value for i64 value conversion")] DecimalToI64ConversionFailure, - /// Failed to convert String value to Float value + /// Failed to parse string value for f64 value conversion #[error("Failed to parse string value for f64 value conversion")] StringToFloatConversionFailure, - /// Failed to convert String value to Float value + /// Failed to parse i64 value for f64 value conversion #[error("Failed to parse i64 value for f64 value conversion")] I64ToDecimalConversionFailure, - /// Failed to convert String value to Float value + /// Failed to parse String value to Decimal value conversion #[error("Failed to parse String value to Decimal value conversion")] StringToDecimalConversionFailure, } diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 5ea78c3393b..509532f7e9b 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -307,7 +307,7 @@ impl AmountConvertor for FloatMajorUnitForConnector { i: MinorUnit, currency: enums::Currency, ) -> Result> { - i.to_major_unit_asf64(currency) + i.to_major_unit_as_f64(currency) } fn convert_back( &self, @@ -352,7 +352,7 @@ impl MinorUnit { &self, currency: enums::Currency, ) -> Result> { - let amount_f64 = self.to_major_unit_asf64(currency)?; + let amount_f64 = self.to_major_unit_as_f64(currency)?; let amount_string = if currency.is_three_decimal_currency() { format!("{:.3}", amount_f64.0) } else { @@ -362,7 +362,7 @@ impl MinorUnit { } /// Convert the amount to its major denomination based on Currency and return f64 - pub fn to_major_unit_asf64( + pub fn to_major_unit_as_f64( &self, currency: enums::Currency, ) -> Result> { @@ -397,7 +397,7 @@ impl MinorUnit { &self, currency: enums::Currency, ) -> Result> { - let amount_f64 = self.to_major_unit_asf64(currency)?; + let amount_f64 = self.to_major_unit_as_f64(currency)?; if currency.is_zero_decimal_currency() { Ok(StringMajorUnit::new(amount_f64.0.to_string())) } else { @@ -558,32 +558,9 @@ impl StringMajorUnit { #[cfg(test)] mod amount_conversion_tests { use super::*; - // #[test] - // fn max_bound_amount_conversion_to_float_major_unit(){ - // let max_amount = MinorUnit::new(std::i64::MAX); - // let currency = enums::Currency::USD; - // let required_conversion = FloatMajorUnitForConnector; - // let conversion_amount = required_conversion.convert(max_amount, currency).unwrap(); - // assert_eq!(conversion_amount.0, 92233720368547758.07); - // let converted_back_amount = required_conversion.convert_back(conversion_amount, currency).unwrap(); - // assert_eq!(converted_back_amount, max_amount); - // } - - // #[test] - // fn max_bound_amount_conversion_to_string_major_unit(){ - // let max_amount = MinorUnit::new(std::i64::MAX); - // // let small_amount = MinorUnit::new(23235); - // // let convertion_in_usd_float = max_amount.to_major_unit_asf64(enums::Currency::USD).unwrap(); - // // println!("float value {:?}", convertion_in_usd_float.0); - // let convertion_in_usd = max_amount.to_major_unit_as_string(enums::Currency::USD).unwrap(); - // println!("string value {:?}", convertion_in_usd); - // // assert_eq!(convertion_in_usd.0, "232.35".to_string()); - // assert_eq!(convertion_in_usd.0, "92233720368547758.07".to_string()); - // } - #[test] fn amount_conversion_to_float_major_unit() { - let request_amount = MinorUnit::new(13124364); + let request_amount = MinorUnit::new(999999999); let two_decimal_currency = enums::Currency::USD; let three_decimal_currency = enums::Currency::BHD; let required_conversion = FloatMajorUnitForConnector; @@ -592,7 +569,7 @@ mod amount_conversion_tests { let converted_amount = required_conversion .convert(request_amount, two_decimal_currency) .unwrap(); - assert_eq!(converted_amount.0, 131243.64); + assert_eq!(converted_amount.0, 9999999.99); let converted_back_amount = required_conversion .convert_back(converted_amount, two_decimal_currency) .unwrap(); @@ -602,7 +579,7 @@ mod amount_conversion_tests { let converted_amount = required_conversion .convert(request_amount, three_decimal_currency) .unwrap(); - assert_eq!(converted_amount.0, 13124.364); + assert_eq!(converted_amount.0, 999999.999); let converted_back_amount = required_conversion .convert_back(converted_amount, three_decimal_currency) .unwrap(); @@ -611,7 +588,7 @@ mod amount_conversion_tests { #[test] fn amount_conversion_to_string_major_unit() { - let request_amount = MinorUnit::new(13124364); + let request_amount = MinorUnit::new(999999999); let two_decimal_currency = enums::Currency::USD; let three_decimal_currency = enums::Currency::BHD; let required_conversion = StringMajorUnitForConnector; @@ -622,7 +599,7 @@ mod amount_conversion_tests { .unwrap(); assert_eq!( converted_amount_two_decimal_currency.0, - "131243.64".to_string() + "9999999.99".to_string() ); let converted_back_amount = required_conversion .convert_back(converted_amount_two_decimal_currency, two_decimal_currency) @@ -635,7 +612,7 @@ mod amount_conversion_tests { .unwrap(); assert_eq!( converted_amount_three_decimal_currency.0, - "13124.364".to_string() + "999999.999".to_string() ); let converted_back_amount = required_conversion .convert_back( @@ -648,13 +625,13 @@ mod amount_conversion_tests { #[test] fn amount_conversion_to_string_minor_unit() { - let request_amount = MinorUnit::new(13124364); + let request_amount = MinorUnit::new(999999999); let currency = enums::Currency::USD; let required_conversion = StringMinorUnitForConnector; let converted_amount = required_conversion .convert(request_amount, currency) .unwrap(); - assert_eq!(converted_amount.0, "13124364".to_string()); + assert_eq!(converted_amount.0, "999999999".to_string()); let converted_back_amount = required_conversion .convert_back(converted_amount, currency) .unwrap(); diff --git a/crates/router/src/connector/nmi.rs b/crates/router/src/connector/nmi.rs index 46f592ef1b4..e88e2a12c8d 100644 --- a/crates/router/src/connector/nmi.rs +++ b/crates/router/src/connector/nmi.rs @@ -106,9 +106,6 @@ impl ConnectorCommon for Nmi { }) } - // fn amount_convertor(&self) -> impl AmountConvertor { - // FloatMajorUnitForConnector - // } } impl ConnectorValidation for Nmi { @@ -344,9 +341,7 @@ impl ConnectorIntegration CustomResult { let amount = connector_utils::convert_amount( self.amount_converter, - req.request - .test_amount - .unwrap_or(MinorUnit::new(req.request.amount)), + MinorUnit::new(req.request.amount), req.request.currency, )?; let connector_router_data = nmi::NmiRouterData::from((amount, req)); diff --git a/crates/router/src/connector/nmi/transformers.rs b/crates/router/src/connector/nmi/transformers.rs index ec68f37d645..0059fbdb0db 100644 --- a/crates/router/src/connector/nmi/transformers.rs +++ b/crates/router/src/connector/nmi/transformers.rs @@ -63,11 +63,9 @@ pub struct NmiRouterData { } impl From<(FloatMajorUnit, T)> for NmiRouterData { - // type Error = Report; fn from((amount, router_data): (FloatMajorUnit, T)) -> Self { Self { - // amount: utils::to_currency_base_unit_asf64(amount, currency)?, amount, router_data, } diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 644c791431a..ca068f1d592 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -1179,7 +1179,6 @@ impl TryFrom> for types::PaymentsAuthoriz statement_descriptor: payment_data.payment_intent.statement_descriptor_name, capture_method: payment_data.payment_attempt.capture_method, amount: amount.get_amount_as_i64(), - test_amount: Some(amount), currency: payment_data.currency, browser_info, email: payment_data.email, diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 2282c0b3859..8e668a4a283 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -320,7 +320,6 @@ pub struct PaymentsAuthorizeData { /// get_total_surcharge_amount() // returns surcharge_amount + tax_on_surcharge_amount /// ``` pub amount: i64, - pub test_amount: Option, pub email: Option, pub customer_name: Option>, pub currency: storage_enums::Currency, @@ -1152,7 +1151,6 @@ impl From<&SetupMandateRouterData> for PaymentsAuthorizeData { email: data.request.email.clone(), customer_name: data.request.customer_name.clone(), amount: 0, - test_amount: Some(MinorUnit::new(0)), statement_descriptor: None, capture_method: None, webhook_url: None, diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index bee6a7861ff..41894e6b98b 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -149,7 +149,6 @@ pub trait ConnectorCommon { }) } - // fn amount_convertor(&self) -> impl AmountConvertor; } /// Extended trait for connector common to allow functions with generic type diff --git a/crates/router/src/types/api/verify_connector.rs b/crates/router/src/types/api/verify_connector.rs index 3f622bbaeb3..212e615524f 100644 --- a/crates/router/src/types/api/verify_connector.rs +++ b/crates/router/src/types/api/verify_connector.rs @@ -1,7 +1,5 @@ pub mod paypal; pub mod stripe; - -use common_utils::types::MinorUnit; use error_stack::ResultExt; use crate::{ @@ -27,7 +25,6 @@ impl VerifyConnectorData { email: None, customer_name: None, amount: 1000, - test_amount: Some(MinorUnit::new(1000)), confirm: true, currency: storage_enums::Currency::USD, metadata: None, From 35473562f3a63b7e63b72f25495ccb21e02a32e9 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Tue, 28 May 2024 15:12:37 +0530 Subject: [PATCH 35/82] refactor(router): removed test_amount from tests --- crates/router/tests/connectors/aci.rs | 1 - crates/router/tests/connectors/adyen.rs | 1 - crates/router/tests/connectors/bitpay.rs | 1 - crates/router/tests/connectors/cashtocode.rs | 1 - crates/router/tests/connectors/coinbase.rs | 1 - crates/router/tests/connectors/cryptopay.rs | 1 - crates/router/tests/connectors/opennode.rs | 1 - crates/router/tests/connectors/utils.rs | 1 - crates/router/tests/connectors/worldline.rs | 1 - 9 files changed, 9 deletions(-) diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs index b7f769ef2b1..b4eafee4c83 100644 --- a/crates/router/tests/connectors/aci.rs +++ b/crates/router/tests/connectors/aci.rs @@ -35,7 +35,6 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData { payment_method_status: None, request: types::PaymentsAuthorizeData { amount: 1000, - test_amount: None, currency: enums::Currency::USD, payment_method_data: types::domain::PaymentMethodData::Card(types::domain::Card { card_number: cards::CardNumber::from_str("4200000000000000").unwrap(), diff --git a/crates/router/tests/connectors/adyen.rs b/crates/router/tests/connectors/adyen.rs index def7a817ee6..ff703dd84ef 100644 --- a/crates/router/tests/connectors/adyen.rs +++ b/crates/router/tests/connectors/adyen.rs @@ -141,7 +141,6 @@ impl AdyenTest { capture_method: enums::CaptureMethod, ) -> Option { Some(types::PaymentsAuthorizeData { - test_amount: None, amount: 3500, currency: enums::Currency::USD, payment_method_data: types::domain::PaymentMethodData::Card(types::domain::Card { diff --git a/crates/router/tests/connectors/bitpay.rs b/crates/router/tests/connectors/bitpay.rs index c7a05e8ef08..85026c9c447 100644 --- a/crates/router/tests/connectors/bitpay.rs +++ b/crates/router/tests/connectors/bitpay.rs @@ -66,7 +66,6 @@ fn get_default_payment_info() -> Option { fn payment_method_details() -> Option { Some(types::PaymentsAuthorizeData { - test_amount: None, amount: 1, currency: enums::Currency::USD, payment_method_data: domain::PaymentMethodData::Crypto(domain::CryptoData { diff --git a/crates/router/tests/connectors/cashtocode.rs b/crates/router/tests/connectors/cashtocode.rs index f9a7bad1d80..76887fa0441 100644 --- a/crates/router/tests/connectors/cashtocode.rs +++ b/crates/router/tests/connectors/cashtocode.rs @@ -42,7 +42,6 @@ impl CashtocodeTest { payment_method_data: domain::PaymentMethodData, ) -> Option { Some(types::PaymentsAuthorizeData { - test_amount: None, amount: 1000, currency: enums::Currency::EUR, payment_method_data, diff --git a/crates/router/tests/connectors/coinbase.rs b/crates/router/tests/connectors/coinbase.rs index 4fed9ac5282..306255c94c5 100644 --- a/crates/router/tests/connectors/coinbase.rs +++ b/crates/router/tests/connectors/coinbase.rs @@ -68,7 +68,6 @@ fn get_default_payment_info() -> Option { fn payment_method_details() -> Option { Some(types::PaymentsAuthorizeData { - test_amount: None, amount: 1, currency: enums::Currency::USD, payment_method_data: domain::PaymentMethodData::Crypto(domain::CryptoData { diff --git a/crates/router/tests/connectors/cryptopay.rs b/crates/router/tests/connectors/cryptopay.rs index d82c75994da..6d52a174b58 100644 --- a/crates/router/tests/connectors/cryptopay.rs +++ b/crates/router/tests/connectors/cryptopay.rs @@ -67,7 +67,6 @@ fn get_default_payment_info() -> Option { fn payment_method_details() -> Option { Some(types::PaymentsAuthorizeData { - test_amount: None, amount: 1, currency: enums::Currency::USD, payment_method_data: domain::PaymentMethodData::Crypto(domain::CryptoData { diff --git a/crates/router/tests/connectors/opennode.rs b/crates/router/tests/connectors/opennode.rs index dccea126c9f..91162b829e2 100644 --- a/crates/router/tests/connectors/opennode.rs +++ b/crates/router/tests/connectors/opennode.rs @@ -67,7 +67,6 @@ fn get_default_payment_info() -> Option { fn payment_method_details() -> Option { Some(types::PaymentsAuthorizeData { - test_amount: None, amount: 1, currency: enums::Currency::USD, payment_method_data: domain::PaymentMethodData::Crypto(domain::CryptoData { diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index 8737cb4859b..9955cb77df7 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -913,7 +913,6 @@ impl Default for CCardType { impl Default for PaymentAuthorizeType { fn default() -> Self { let data = types::PaymentsAuthorizeData { - test_amount: None, payment_method_data: types::domain::PaymentMethodData::Card(CCardType::default().0), amount: 100, currency: enums::Currency::USD, diff --git a/crates/router/tests/connectors/worldline.rs b/crates/router/tests/connectors/worldline.rs index 577e19ef80f..e26ba15eb25 100644 --- a/crates/router/tests/connectors/worldline.rs +++ b/crates/router/tests/connectors/worldline.rs @@ -70,7 +70,6 @@ impl WorldlineTest { capture_method: enums::CaptureMethod, ) -> Option { Some(types::PaymentsAuthorizeData { - test_amount: None, amount: 3500, currency: enums::Currency::USD, payment_method_data: types::domain::PaymentMethodData::Card(types::domain::Card { From 7a916a5bcab7b6a76e42afe5fc95d4d7aba77289 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Tue, 28 May 2024 09:48:45 +0000 Subject: [PATCH 36/82] docs(openapi): re-generate OpenAPI specification --- openapi/openapi_spec.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 30bd356cd45..3d7fb6af586 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -7319,7 +7319,7 @@ }, "ChargeRefunds": { "type": "object", - "description": "Charge object for refunds", + "description": "Charges structs\nCharge object for refunds", "required": [ "charge_id" ], From d9b564becbcfd9a4c8ca9f3f27f37558c0aafaa0 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Tue, 28 May 2024 15:29:13 +0530 Subject: [PATCH 37/82] refactor(router): fixed clippy issues --- crates/common_utils/src/types.rs | 29 +++++++++++++++-------------- openapi/openapi_spec.json | 2 +- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 1cbc726c27d..0308643a0af 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -238,14 +238,14 @@ pub trait AmountConvertor: Send { /// helps in conversion of connector required amount type fn convert( &self, - i: MinorUnit, + amount: MinorUnit, currency: enums::Currency, ) -> Result>; /// helps in converting back connector required amount type to core minor unit fn convert_back( &self, - i: Self::Output, + amount: Self::Output, currency: enums::Currency, ) -> Result>; } @@ -258,18 +258,18 @@ impl AmountConvertor for StringMinorUnitForConnector { type Output = StringMinorUnit; fn convert( &self, - i: MinorUnit, + amount: MinorUnit, _currency: enums::Currency, ) -> Result> { - i.to_minor_unit_as_string() + amount.to_minor_unit_as_string() } fn convert_back( &self, - i: Self::Output, + amount: Self::Output, _currency: enums::Currency, ) -> Result> { - i.to_minor_unit_as_i64() + amount.to_minor_unit_as_i64() } } @@ -281,18 +281,18 @@ impl AmountConvertor for StringMajorUnitForConnector { type Output = StringMajorUnit; fn convert( &self, - i: MinorUnit, + amount: MinorUnit, currency: enums::Currency, ) -> Result> { - i.to_major_unit_as_string(currency) + amount.to_major_unit_as_string(currency) } fn convert_back( &self, - i: StringMajorUnit, + amount: StringMajorUnit, currency: enums::Currency, ) -> Result> { - i.to_minor_unit_as_i64(currency) + amount.to_minor_unit_as_i64(currency) } } @@ -304,17 +304,17 @@ impl AmountConvertor for FloatMajorUnitForConnector { type Output = FloatMajorUnit; fn convert( &self, - i: MinorUnit, + amount: MinorUnit, currency: enums::Currency, ) -> Result> { - i.to_major_unit_as_f64(currency) + amount.to_major_unit_as_f64(currency) } fn convert_back( &self, - i: FloatMajorUnit, + amount: FloatMajorUnit, currency: enums::Currency, ) -> Result> { - i.to_minor_unit_as_i64(currency) + amount.to_minor_unit_as_i64(currency) } } /// This Unit struct represents MinorUnit in which core amount works @@ -550,6 +550,7 @@ impl StringMajorUnit { #[cfg(test)] mod amount_conversion_tests { + #![allow(clippy::unwrap_used)] use super::*; #[test] fn amount_conversion_to_float_major_unit() { diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 30bd356cd45..3d7fb6af586 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -7319,7 +7319,7 @@ }, "ChargeRefunds": { "type": "object", - "description": "Charge object for refunds", + "description": "Charges structs\nCharge object for refunds", "required": [ "charge_id" ], From 6b8c733e6225d234859d9cf5f16b29cc1a07c13d Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Tue, 28 May 2024 15:31:08 +0530 Subject: [PATCH 38/82] refactor(router): fixed open api issue --- crates/common_utils/src/types.rs | 2 +- openapi/openapi_spec.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 0308643a0af..a1c600b6e21 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -633,7 +633,7 @@ mod amount_conversion_tests { } } -/// Charges structs +// Charges structs #[derive( Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, FromSqlRow, AsExpression, ToSchema, )] diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 3d7fb6af586..30bd356cd45 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -7319,7 +7319,7 @@ }, "ChargeRefunds": { "type": "object", - "description": "Charges structs\nCharge object for refunds", + "description": "Charge object for refunds", "required": [ "charge_id" ], From 56ea7302f0a0dad851aa3b5bf20fba100c131b4e Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Tue, 28 May 2024 17:09:09 +0530 Subject: [PATCH 39/82] refactor(connector): changed amount to minor Unit for stripe --- .../src/connector/stripe/transformers.rs | 56 ++++++++++--------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 83bca39626f..9a658c2423d 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -6,6 +6,7 @@ use common_utils::{ ext_traits::{ByteSliceExt, Encode}, pii::{self, Email}, request::RequestContent, + types::MinorUnit }; use error_stack::ResultExt; use hyperswitch_domain_models::mandates::AcceptanceType; @@ -127,7 +128,7 @@ pub struct StripeBrowserInformation { #[derive(Debug, Eq, PartialEq, Serialize)] pub struct PaymentIntentRequest { - pub amount: i64, //amount in cents, hence passed as integer + pub amount: MinorUnit, //amount in cents, hence passed as integer pub currency: String, pub statement_descriptor_suffix: Option, pub statement_descriptor: Option, @@ -163,7 +164,7 @@ pub struct PaymentIntentRequest { #[derive(Debug, Eq, PartialEq, Serialize)] pub struct IntentCharges { - pub application_fee_amount: i64, + pub application_fee_amount: MinorUnit, #[serde( rename = "transfer_data[destination]", skip_serializing_if = "Option::is_none" @@ -443,7 +444,7 @@ pub struct MultibancoCreditTransferSourceRequest { #[serde(flatten)] pub payment_method_data: MultibancoTransferData, pub currency: enums::Currency, - pub amount: Option, + pub amount: Option, #[serde(rename = "redirect[return_url]")] pub return_url: Option, } @@ -1844,11 +1845,11 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest { let charges = match &charges.charge_type { api_enums::PaymentChargeType::Stripe(charge_type) => match charge_type { api_enums::StripeChargeType::Direct => Some(IntentCharges { - application_fee_amount: charges.fees, + application_fee_amount: MinorUnit::new(charges.fees), destination_account_id: None, }), api_enums::StripeChargeType::Destination => Some(IntentCharges { - application_fee_amount: charges.fees, + application_fee_amount: MinorUnit::new(charges.fees), destination_account_id: Some(charges.transfer_account_id.clone()), }), }, @@ -1859,7 +1860,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest { }; Ok(Self { - amount: item.request.amount, //hopefully we don't loose some cents here + amount: MinorUnit::new(item.request.amount), //hopefully we don't loose some cents here currency: item.request.currency.to_string(), //we need to copy the value and not transfer ownership statement_descriptor_suffix: item.request.statement_descriptor_suffix.clone(), statement_descriptor: item.request.statement_descriptor.clone(), @@ -2036,9 +2037,9 @@ impl From for enums::AttemptStatus { pub struct PaymentIntentResponse { pub id: String, pub object: String, - pub amount: i64, - pub amount_received: Option, - pub amount_capturable: Option, + pub amount: MinorUnit, + pub amount_received: Option, + pub amount_capturable: Option, pub currency: String, pub status: StripePaymentStatus, pub client_secret: Option>, @@ -2083,8 +2084,8 @@ pub struct MultibancoCreditTansferResponse { #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] pub struct AchReceiverDetails { - pub amount_received: i64, - pub amount_charged: i64, + pub amount_received: MinorUnit, + pub amount_charged: MinorUnit, } #[serde_with::skip_serializing_none] @@ -2099,13 +2100,13 @@ pub struct SepaAndBacsBankTransferInstructions { #[derive(Clone, Debug, Serialize)] pub struct QrCodeNextInstructions { pub image_data_url: Url, - pub display_to_timestamp: Option, + pub display_to_timestamp: Option, } #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] pub struct SepaAndBacsReceiver { - pub amount_received: i64, - pub amount_remaining: i64, + pub amount_received: MinorUnit, + pub amount_remaining: MinorUnit, } #[derive(Debug, Default, Eq, PartialEq, Deserialize)] @@ -2416,7 +2417,7 @@ impl // statement_descriptor_suffix: item.response.statement_descriptor_suffix.map(|x| x.as_str()), // three_ds_form, response, - amount_captured: item.response.amount_received, + amount_captured: item.response.amount_received.map(|amount| amount.get_amount_as_i64()), connector_response: connector_response_data, ..item.data }) @@ -2425,7 +2426,7 @@ impl pub fn get_connector_metadata( next_action: Option<&StripeNextActionResponse>, - amount: i64, + amount: MinorUnit, ) -> CustomResult, errors::ConnectorError> { let next_action_response = next_action .and_then(|next_action_response| match next_action_response { @@ -2598,7 +2599,7 @@ impl Ok(Self { status: enums::AttemptStatus::from(item.response.status.to_owned()), response, - amount_captured: item.response.amount_received, + amount_captured: item.response.amount_received.map(|amount| amount.get_amount_as_i64()), connector_response: connector_response_data, ..item.data }) @@ -2795,7 +2796,7 @@ pub struct StripeVerifyWithMicroDepositsResponse { #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct StripeBankTransferDetails { - pub amount_remaining: i64, + pub amount_remaining: MinorUnit, pub currency: String, pub financial_addresses: Vec, pub hosted_instructions_url: Option, @@ -2813,7 +2814,7 @@ pub struct StripeCashappQrResponse { #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct QrCodeResponse { - pub expires_at: Option, + pub expires_at: Option, pub image_url_png: Url, pub image_url_svg: Url, } @@ -2847,7 +2848,7 @@ pub struct BacsFinancialDetails { #[derive(Debug, Serialize)] pub struct RefundRequest { - pub amount: Option, //amount in cents, hence passed as integer + pub amount: Option, //amount in cents, hence passed as integer pub payment_intent: String, #[serde(flatten)] pub meta_data: StripeMetadata, @@ -2859,7 +2860,7 @@ impl TryFrom<&types::RefundsRouterData> for RefundRequest { let amount = item.request.refund_amount; let payment_intent = item.request.connector_transaction_id.clone(); Ok(Self { - amount: Some(amount), + amount: Some(MinorUnit::new(amount)), payment_intent, meta_data: StripeMetadata { order_id: Some(item.request.refund_id.clone()), @@ -2874,7 +2875,7 @@ pub struct ChargeRefundRequest { pub charge: String, pub refund_application_fee: Option, pub reverse_transfer: Option, - pub amount: Option, //amount in cents, hence passed as integer + pub amount: Option, //amount in cents, hence passed as integer #[serde(flatten)] pub meta_data: StripeMetadata, } @@ -2902,7 +2903,7 @@ impl TryFrom<&types::RefundsRouterData> for ChargeRefundRequest { charge: charges.charge_id.clone(), refund_application_fee, reverse_transfer, - amount: Some(amount), + amount: Some(MinorUnit::new(amount)), meta_data: StripeMetadata { order_id: Some(item.request.refund_id.clone()), is_refund_id_as_reference: Some("true".to_string()), @@ -2940,7 +2941,7 @@ impl From for enums::RefundStatus { pub struct RefundResponse { pub id: String, pub object: String, - pub amount: i64, + pub amount: MinorUnit, pub currency: String, pub metadata: StripeMetadata, pub payment_intent: String, @@ -3170,14 +3171,14 @@ pub struct StripeMandateOptions { #[derive(Debug, Serialize, Clone, Copy)] pub struct CaptureRequest { /// If amount_to_capture is None stripe captures the amount in the payment intent. - amount_to_capture: Option, + amount_to_capture: Option, } impl TryFrom<&types::PaymentsCaptureRouterData> for CaptureRequest { type Error = error_stack::Report; fn try_from(item: &types::PaymentsCaptureRouterData) -> Result { Ok(Self { - amount_to_capture: Some(item.request.amount_to_capture), + amount_to_capture: Some(MinorUnit::new(item.request.amount_to_capture)), }) } } @@ -3186,6 +3187,7 @@ impl TryFrom<&types::PaymentsPreProcessingRouterData> for StripeCreditTransferSo type Error = error_stack::Report; fn try_from(item: &types::PaymentsPreProcessingRouterData) -> Result { let currency = item.request.get_currency()?; + let amount = item.request.get_amount()?; match &item.request.payment_method_data { Some(domain::PaymentMethodData::BankTransfer(bank_transfer_data)) => { @@ -3197,7 +3199,7 @@ impl TryFrom<&types::PaymentsPreProcessingRouterData> for StripeCreditTransferSo payment_method_data: MultibancoTransferData { email: item.request.get_email()?, }, - amount: Some(item.request.get_amount()?), + amount: Some(MinorUnit::new(amount)), return_url: Some(item.get_return_url()?), }), ), From 96f9aa3f32dd8c9ff85c38f5d610bffbf41dddb7 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Tue, 28 May 2024 11:47:10 +0000 Subject: [PATCH 40/82] chore: run formatter --- crates/router/src/connector/stripe/transformers.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 9a658c2423d..17a7773c1ae 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -6,7 +6,7 @@ use common_utils::{ ext_traits::{ByteSliceExt, Encode}, pii::{self, Email}, request::RequestContent, - types::MinorUnit + types::MinorUnit, }; use error_stack::ResultExt; use hyperswitch_domain_models::mandates::AcceptanceType; @@ -2417,7 +2417,10 @@ impl // statement_descriptor_suffix: item.response.statement_descriptor_suffix.map(|x| x.as_str()), // three_ds_form, response, - amount_captured: item.response.amount_received.map(|amount| amount.get_amount_as_i64()), + amount_captured: item + .response + .amount_received + .map(|amount| amount.get_amount_as_i64()), connector_response: connector_response_data, ..item.data }) @@ -2599,7 +2602,10 @@ impl Ok(Self { status: enums::AttemptStatus::from(item.response.status.to_owned()), response, - amount_captured: item.response.amount_received.map(|amount| amount.get_amount_as_i64()), + amount_captured: item + .response + .amount_received + .map(|amount| amount.get_amount_as_i64()), connector_response: connector_response_data, ..item.data }) From 5be12e1d940b560ebc0c00b26eef03c9f07bbbd9 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Tue, 28 May 2024 20:50:09 +0530 Subject: [PATCH 41/82] refactor(router): mapped error to error message --- crates/common_utils/src/errors.rs | 7 ++++--- crates/common_utils/src/types.rs | 8 ++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/common_utils/src/errors.rs b/crates/common_utils/src/errors.rs index 7108aa105cc..e4c59ba2a31 100644 --- a/crates/common_utils/src/errors.rs +++ b/crates/common_utils/src/errors.rs @@ -11,6 +11,7 @@ use crate::types::MinorUnit; pub type CustomResult = error_stack::Result; /// Parsing Errors +#[allow(missing_docs)] // Only to prevent warnings about struct fields not being documented #[derive(Debug, thiserror::Error)] pub enum ParsingError { ///Failed to parse enum @@ -46,9 +47,9 @@ pub enum ParsingError { /// Failed to parse i64 value for f64 value conversion #[error("Failed to parse i64 value for f64 value conversion")] I64ToDecimalConversionFailure, - /// Failed to parse String value to Decimal value conversion - #[error("Failed to parse String value to Decimal value conversion")] - StringToDecimalConversionFailure, + /// Failed to parse String value to Decimal value conversion because `error` + #[error("Failed to parse String value to Decimal value conversion because {error}")] + StringToDecimalConversionFailure { error: String }, } /// Validation errors. diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index a1c600b6e21..63c0a6b922c 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -475,7 +475,9 @@ impl StringMinorUnit { pub fn to_minor_unit_as_i64(&self) -> Result> { let amount_string = &self.0; let amount_decimal = Decimal::from_str(amount_string) - .map_err(|_| ParsingError::StringToDecimalConversionFailure)?; + .map_err(|e| ParsingError::StringToDecimalConversionFailure{ + error : e.to_string() + })?; let amount_i64 = amount_decimal .to_i64() .ok_or(ParsingError::DecimalToI64ConversionFailure)?; @@ -532,7 +534,9 @@ impl StringMajorUnit { currency: enums::Currency, ) -> Result> { let amount_decimal = Decimal::from_str(&self.0) - .map_err(|_| ParsingError::StringToDecimalConversionFailure)?; + .map_err(|e| ParsingError::StringToDecimalConversionFailure{ + error : e.to_string() + })?; let amount = if currency.is_zero_decimal_currency() { amount_decimal From fa440df4a3951fb937f1b9d4f189a68e5f23d2b4 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Tue, 28 May 2024 15:20:55 +0000 Subject: [PATCH 42/82] chore: run formatter --- crates/common_utils/src/types.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 63c0a6b922c..c182d222285 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -474,10 +474,11 @@ impl StringMinorUnit { /// converts to minor unit i64 from minor unit string value pub fn to_minor_unit_as_i64(&self) -> Result> { let amount_string = &self.0; - let amount_decimal = Decimal::from_str(amount_string) - .map_err(|e| ParsingError::StringToDecimalConversionFailure{ - error : e.to_string() - })?; + let amount_decimal = Decimal::from_str(amount_string).map_err(|e| { + ParsingError::StringToDecimalConversionFailure { + error: e.to_string(), + } + })?; let amount_i64 = amount_decimal .to_i64() .ok_or(ParsingError::DecimalToI64ConversionFailure)?; @@ -533,10 +534,11 @@ impl StringMajorUnit { &self, currency: enums::Currency, ) -> Result> { - let amount_decimal = Decimal::from_str(&self.0) - .map_err(|e| ParsingError::StringToDecimalConversionFailure{ - error : e.to_string() - })?; + let amount_decimal = Decimal::from_str(&self.0).map_err(|e| { + ParsingError::StringToDecimalConversionFailure { + error: e.to_string(), + } + })?; let amount = if currency.is_zero_decimal_currency() { amount_decimal From 6967e5f3119c30bf5268aef7ba2991eec85c8c78 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 10:03:46 +0000 Subject: [PATCH 43/82] chore: run formatter --- crates/router/src/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 4a28f0cfc99..f2e8c449564 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -21,7 +21,7 @@ use std::marker::PhantomData; pub use api_models::{enums::Connector, mandates}; #[cfg(feature = "payouts")] pub use api_models::{enums::PayoutConnectors, payouts as payout_types}; -pub use common_utils::{request::RequestContent, pii, pii::Email, types::MinorUnit}; +pub use common_utils::{pii, pii::Email, request::RequestContent, types::MinorUnit}; #[cfg(feature = "payouts")] pub use hyperswitch_domain_models::router_request_types::PayoutsData; #[cfg(feature = "payouts")] From 773b45872cc818b986f94825b0f4c43030143bc3 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Wed, 29 May 2024 18:07:26 +0530 Subject: [PATCH 44/82] refactor(router): addressed pr comments --- crates/api_models/src/refunds.rs | 6 +- crates/common_utils/src/types.rs | 100 ++++++++++-------- crates/diesel_models/src/refund.rs | 13 ++- .../src/router_request_types.rs | 27 +++-- .../src/compatibility/stripe/refunds/types.rs | 6 +- crates/router/src/connector/nmi.rs | 10 +- .../router/src/connector/nmi/transformers.rs | 2 +- .../router/src/core/payments/transformers.rs | 4 + crates/router/src/core/refunds.rs | 19 ++-- crates/router/src/core/refunds/validator.rs | 2 +- crates/router/src/core/utils.rs | 10 +- crates/router/src/db/refund.rs | 13 ++- crates/router/src/services/kafka/refund.rs | 5 +- crates/router/src/types.rs | 3 +- .../router/src/types/api/verify_connector.rs | 1 + crates/router/src/utils/user/sample_data.rs | 9 +- 16 files changed, 140 insertions(+), 90 deletions(-) diff --git a/crates/api_models/src/refunds.rs b/crates/api_models/src/refunds.rs index 881cc3912ec..9f531bc549c 100644 --- a/crates/api_models/src/refunds.rs +++ b/crates/api_models/src/refunds.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use common_utils::pii; -pub use common_utils::types::ChargeRefunds; +pub use common_utils::types::{ChargeRefunds, MinorUnit}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; use utoipa::ToSchema; @@ -37,7 +37,7 @@ pub struct RefundRequest { /// Total amount for which the refund is to be initiated. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, this will default to the full payment amount #[schema(minimum = 100, example = 6540)] - pub amount: Option, + pub amount: Option, /// Reason for the refund. Often useful for displaying to users and your customer support executive. In case the payment went through Stripe, this field needs to be passed with one of these enums: `duplicate`, `fraudulent`, or `requested_by_customer` #[schema(max_length = 255, example = "Customer returned the product")] @@ -115,7 +115,7 @@ pub struct RefundResponse { /// The payment id against which refund is initiated pub payment_id: String, /// The refund amount, which should be less than or equal to the total 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 - pub amount: i64, + pub amount: MinorUnit, /// The three-letter ISO currency code pub currency: String, /// The status for refund diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index c182d222285..08731e053ae 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -251,7 +251,7 @@ pub trait AmountConvertor: Send { } /// Connector required amount type -#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] +#[derive(Default, Debug, Clone, Copy, PartialEq)] pub struct StringMinorUnitForConnector; impl AmountConvertor for StringMinorUnitForConnector { @@ -347,12 +347,16 @@ impl MinorUnit { } /// Convert the amount to its major denomination based on Currency and return String - pub fn to_major_unit_as_string( + /// Paypal Connector accepts Zero and Two decimal currency but not three decimal and it should be updated as required for 3 decimal currencies. + /// Paypal Ref - https://developer.paypal.com/docs/reports/reference/paypal-supported-currencies/ + fn to_major_unit_as_string( &self, currency: enums::Currency, ) -> Result> { let amount_f64 = self.to_major_unit_as_f64(currency)?; - let amount_string = if currency.is_three_decimal_currency() { + let amount_string = if currency.is_zero_decimal_currency() { + amount_f64.0.to_string() + } else if currency.is_three_decimal_currency() { format!("{:.3}", amount_f64.0) } else { format!("{:.2}", amount_f64.0) @@ -361,7 +365,7 @@ impl MinorUnit { } /// Convert the amount to its major denomination based on Currency and return f64 - pub fn to_major_unit_as_f64( + fn to_major_unit_as_f64( &self, currency: enums::Currency, ) -> Result> { @@ -381,29 +385,11 @@ impl MinorUnit { Ok(FloatMajorUnit::new(amount_f64)) } - ///Convert the higher decimal amount to its major absolute units - pub fn to_minor_unit_as_string( + ///Convert minor unit to string minor unit + fn to_minor_unit_as_string( &self, ) -> Result> { - let amount_decimal = - Decimal::from_i64(self.0).ok_or(ParsingError::I64ToDecimalConversionFailure)?; - Ok(StringMinorUnit::new(amount_decimal.to_string())) - } - - /// Convert the amount to its major denomination based on Currency and check for zero decimal currency and return String - /// Paypal Connector accepts Zero and Two decimal currency but not three decimal and it should be updated as required for 3 decimal currencies. - /// Paypal Ref - https://developer.paypal.com/docs/reports/reference/paypal-supported-currencies/ - pub fn to_major_unit_as_string_with_zero_decimal_check( - &self, - currency: enums::Currency, - ) -> Result> { - let amount_f64 = self.to_major_unit_as_f64(currency)?; - if currency.is_zero_decimal_currency() { - Ok(StringMajorUnit::new(amount_f64.0.to_string())) - } else { - let amount_string = format!("{:.2}", amount_f64.0); - Ok(StringMajorUnit::new(amount_string)) - } + Ok(StringMinorUnit::new(self.0.to_string())) } } @@ -467,12 +453,12 @@ pub struct StringMinorUnit(String); impl StringMinorUnit { /// forms a new minor unit in string from amount - pub fn new(value: String) -> Self { + fn new(value: String) -> Self { Self(value) } /// converts to minor unit i64 from minor unit string value - pub fn to_minor_unit_as_i64(&self) -> Result> { + fn to_minor_unit_as_i64(&self) -> Result> { let amount_string = &self.0; let amount_decimal = Decimal::from_str(amount_string).map_err(|e| { ParsingError::StringToDecimalConversionFailure { @@ -492,12 +478,17 @@ pub struct FloatMajorUnit(f64); impl FloatMajorUnit { /// forms a new major unit from amount - pub fn new(value: f64) -> Self { + fn new(value: f64) -> Self { Self(value) } + /// forms a new major unit with zero amount + pub fn zero() -> Self { + Self(0.0) + } + /// converts to minor unit as i64 from FloatMajorUnit - pub fn to_minor_unit_as_i64( + fn to_minor_unit_as_i64( &self, currency: enums::Currency, ) -> Result> { @@ -525,12 +516,12 @@ pub struct StringMajorUnit(String); impl StringMajorUnit { /// forms a new major unit from amount - pub fn new(value: String) -> Self { + fn new(value: String) -> Self { Self(value) } /// Converts to minor unit as i64 from StringMajorUnit - pub fn to_minor_unit_as_i64( + fn to_minor_unit_as_i64( &self, currency: enums::Currency, ) -> Result> { @@ -558,30 +549,42 @@ impl StringMajorUnit { mod amount_conversion_tests { #![allow(clippy::unwrap_used)] use super::*; + const TWO_DECIMAL_CURRENCY: enums::Currency = enums::Currency::USD; + const THREE_DECIMAL_CURRENCY: enums::Currency = enums::Currency::BHD; + const ZERO_DECIMAL_CURRENCY: enums::Currency = enums::Currency::JPY; #[test] fn amount_conversion_to_float_major_unit() { let request_amount = MinorUnit::new(999999999); - let two_decimal_currency = enums::Currency::USD; - let three_decimal_currency = enums::Currency::BHD; let required_conversion = FloatMajorUnitForConnector; // Two decimal currency conversions let converted_amount = required_conversion - .convert(request_amount, two_decimal_currency) + .convert(request_amount, TWO_DECIMAL_CURRENCY) .unwrap(); assert_eq!(converted_amount.0, 9999999.99); let converted_back_amount = required_conversion - .convert_back(converted_amount, two_decimal_currency) + .convert_back(converted_amount, TWO_DECIMAL_CURRENCY) .unwrap(); assert_eq!(converted_back_amount, request_amount); // Three decimal currency conversions let converted_amount = required_conversion - .convert(request_amount, three_decimal_currency) + .convert(request_amount, THREE_DECIMAL_CURRENCY) .unwrap(); assert_eq!(converted_amount.0, 999999.999); let converted_back_amount = required_conversion - .convert_back(converted_amount, three_decimal_currency) + .convert_back(converted_amount, THREE_DECIMAL_CURRENCY) + .unwrap(); + assert_eq!(converted_back_amount, request_amount); + + // Zero decimal currency conversions + let converted_amount = required_conversion + .convert(request_amount, ZERO_DECIMAL_CURRENCY) + .unwrap(); + assert_eq!(converted_amount.0, 999999999.0); + + let converted_back_amount = required_conversion + .convert_back(converted_amount, ZERO_DECIMAL_CURRENCY) .unwrap(); assert_eq!(converted_back_amount, request_amount); } @@ -589,26 +592,24 @@ mod amount_conversion_tests { #[test] fn amount_conversion_to_string_major_unit() { let request_amount = MinorUnit::new(999999999); - let two_decimal_currency = enums::Currency::USD; - let three_decimal_currency = enums::Currency::BHD; let required_conversion = StringMajorUnitForConnector; // Two decimal currency conversions let converted_amount_two_decimal_currency = required_conversion - .convert(request_amount, two_decimal_currency) + .convert(request_amount, TWO_DECIMAL_CURRENCY) .unwrap(); assert_eq!( converted_amount_two_decimal_currency.0, "9999999.99".to_string() ); let converted_back_amount = required_conversion - .convert_back(converted_amount_two_decimal_currency, two_decimal_currency) + .convert_back(converted_amount_two_decimal_currency, TWO_DECIMAL_CURRENCY) .unwrap(); assert_eq!(converted_back_amount, request_amount); // Three decimal currency conversions let converted_amount_three_decimal_currency = required_conversion - .convert(request_amount, three_decimal_currency) + .convert(request_amount, THREE_DECIMAL_CURRENCY) .unwrap(); assert_eq!( converted_amount_three_decimal_currency.0, @@ -617,16 +618,27 @@ mod amount_conversion_tests { let converted_back_amount = required_conversion .convert_back( converted_amount_three_decimal_currency, - three_decimal_currency, + THREE_DECIMAL_CURRENCY, ) .unwrap(); assert_eq!(converted_back_amount, request_amount); + + // Zero decimal currency conversions + let converted_amount = required_conversion + .convert(request_amount, ZERO_DECIMAL_CURRENCY) + .unwrap(); + assert_eq!(converted_amount.0, "999999999".to_string()); + + let converted_back_amount = required_conversion + .convert_back(converted_amount, ZERO_DECIMAL_CURRENCY) + .unwrap(); + assert_eq!(converted_back_amount, request_amount); } #[test] fn amount_conversion_to_string_minor_unit() { let request_amount = MinorUnit::new(999999999); - let currency = enums::Currency::USD; + let currency = TWO_DECIMAL_CURRENCY; let required_conversion = StringMinorUnitForConnector; let converted_amount = required_conversion .convert(request_amount, currency) diff --git a/crates/diesel_models/src/refund.rs b/crates/diesel_models/src/refund.rs index aac282992a8..7d5b20c3d0c 100644 --- a/crates/diesel_models/src/refund.rs +++ b/crates/diesel_models/src/refund.rs @@ -1,4 +1,7 @@ -use common_utils::{pii, types::ChargeRefunds}; +use common_utils::{ + pii, + types::{ChargeRefunds, MinorUnit}, +}; use diesel::{AsChangeset, Identifiable, Insertable, Queryable}; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; @@ -20,9 +23,9 @@ pub struct Refund { pub connector_refund_id: Option, pub external_reference_id: Option, pub refund_type: storage_enums::RefundType, - pub total_amount: i64, + pub total_amount: MinorUnit, pub currency: storage_enums::Currency, - pub refund_amount: i64, + pub refund_amount: MinorUnit, pub refund_status: storage_enums::RefundStatus, pub sent_to_gateway: bool, pub refund_error_message: Option, @@ -65,9 +68,9 @@ pub struct RefundNew { pub connector: String, pub connector_refund_id: Option, pub refund_type: storage_enums::RefundType, - pub total_amount: i64, + pub total_amount: MinorUnit, pub currency: storage_enums::Currency, - pub refund_amount: i64, + pub refund_amount: MinorUnit, pub refund_status: storage_enums::RefundStatus, pub sent_to_gateway: bool, pub metadata: Option, diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index 56a4ba739c0..9b14c691372 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -1,7 +1,7 @@ pub mod authentication; pub mod fraud_check; use api_models::payments::RequestSurchargeDetails; -use common_utils::{consts, errors, ext_traits::OptionExt, pii}; +use common_utils::{consts, errors, ext_traits::OptionExt, pii, types::MinorUnit}; use diesel_models::enums as storage_enums; use error_stack::ResultExt; use masking::Secret; @@ -57,6 +57,9 @@ pub struct PaymentsAuthorizeData { pub metadata: Option, pub authentication_data: Option, pub charges: Option, + + // New amount for amount frame work + pub minor_amount: MinorUnit, } #[derive(Debug, serde::Deserialize, Clone)] @@ -77,6 +80,10 @@ pub struct PaymentsCaptureData { pub browser_info: Option, pub metadata: Option, // This metadata is used to store the metadata shared during the payment intent request. + + // New amount for amount frame work + pub minor_payment_amount: MinorUnit, + pub minor_amount_to_capture: MinorUnit, } #[derive(Debug, Clone, Default)] @@ -296,6 +303,9 @@ pub struct CompleteAuthorizeData { pub connector_meta: Option, pub complete_authorize_url: Option, pub metadata: Option, + + // New amount for amount frame work + pub minor_amount: MinorUnit, } #[derive(Debug, Clone)] @@ -387,18 +397,18 @@ impl ResponseId { #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] pub struct SurchargeDetails { /// original_amount - pub original_amount: common_utils::types::MinorUnit, + pub original_amount: MinorUnit, /// surcharge value pub surcharge: common_utils::types::Surcharge, /// tax on surcharge value pub tax_on_surcharge: Option>, /// surcharge amount for this payment - pub surcharge_amount: common_utils::types::MinorUnit, + pub surcharge_amount: MinorUnit, /// tax on surcharge amount for this payment - pub tax_on_surcharge_amount: common_utils::types::MinorUnit, + pub tax_on_surcharge_amount: MinorUnit, /// sum of original amount, - pub final_amount: common_utils::types::MinorUnit, + pub final_amount: MinorUnit, } impl SurchargeDetails { @@ -410,7 +420,7 @@ impl SurchargeDetails { && request_surcharge_details.tax_amount.unwrap_or_default() == self.tax_on_surcharge_amount } - pub fn get_total_surcharge_amount(&self) -> common_utils::types::MinorUnit { + pub fn get_total_surcharge_amount(&self) -> MinorUnit { self.surcharge_amount + self.tax_on_surcharge_amount } } @@ -459,6 +469,7 @@ pub struct RefundsData { pub currency: storage_enums::Currency, /// Amount for the payment against which this refund is issued pub payment_amount: i64, + pub reason: Option, pub webhook_url: Option, /// Amount to be refunded @@ -468,6 +479,10 @@ pub struct RefundsData { pub browser_info: Option, /// Charges associated with the payment pub charges: Option, + + // New amount for amount frame work + pub minor_payment_amount: MinorUnit, + pub minor_refund_amount: MinorUnit, } #[derive(Debug, serde::Deserialize, Clone)] diff --git a/crates/router/src/compatibility/stripe/refunds/types.rs b/crates/router/src/compatibility/stripe/refunds/types.rs index 10a01836144..7205eeef739 100644 --- a/crates/router/src/compatibility/stripe/refunds/types.rs +++ b/crates/router/src/compatibility/stripe/refunds/types.rs @@ -46,7 +46,9 @@ impl From for refunds::RefundRequest { fn from(req: StripeCreateRefundRequest) -> Self { Self { refund_id: req.refund_id, - amount: req.amount, + amount: req + .amount + .map(|amount| common_utils::types::MinorUnit::new(amount)), payment_id: req.payment_intent, reason: req.reason, refund_type: Some(refunds::RefundType::Instant), @@ -82,7 +84,7 @@ impl From for StripeRefundResponse { fn from(res: refunds::RefundResponse) -> Self { Self { id: res.refund_id, - amount: res.amount, + amount: res.amount.get_amount_as_i64(), currency: res.currency.to_ascii_lowercase(), payment_intent: res.payment_id, status: res.status.into(), diff --git a/crates/router/src/connector/nmi.rs b/crates/router/src/connector/nmi.rs index 6b174ed8929..2c0712c5408 100644 --- a/crates/router/src/connector/nmi.rs +++ b/crates/router/src/connector/nmi.rs @@ -4,7 +4,7 @@ use common_utils::{ crypto, ext_traits::ByteSliceExt, request::RequestContent, - types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector, MinorUnit}, + types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector}, }; use diesel_models::enums; use error_stack::{report, ResultExt}; @@ -340,7 +340,7 @@ impl ConnectorIntegration CustomResult { let amount = connector_utils::convert_amount( self.amount_converter, - MinorUnit::new(req.request.amount), + req.request.minor_amount, req.request.currency, )?; let connector_router_data = nmi::NmiRouterData::from((amount, req)); @@ -428,7 +428,7 @@ impl ) -> CustomResult { let amount = connector_utils::convert_amount( self.amount_converter, - MinorUnit::new(req.request.amount), + req.request.minor_amount, req.request.currency, )?; let connector_router_data = nmi::NmiRouterData::from((amount, req)); @@ -580,7 +580,7 @@ impl ConnectorIntegration CustomResult { let amount = connector_utils::convert_amount( self.amount_converter, - MinorUnit::new(req.request.amount_to_capture), + req.request.minor_amount_to_capture, req.request.currency, )?; let connector_router_data = nmi::NmiRouterData::from((amount, req)); @@ -728,7 +728,7 @@ impl ConnectorIntegration CustomResult { let refund_amount = connector_utils::convert_amount( self.amount_converter, - MinorUnit::new(req.request.refund_amount), + req.request.minor_refund_amount, req.request.currency, )?; diff --git a/crates/router/src/connector/nmi/transformers.rs b/crates/router/src/connector/nmi/transformers.rs index 280fedaab51..378dbd581eb 100644 --- a/crates/router/src/connector/nmi/transformers.rs +++ b/crates/router/src/connector/nmi/transformers.rs @@ -667,7 +667,7 @@ impl TryFrom<&types::SetupMandateRouterData> for NmiPaymentsRequest { Ok(Self { transaction_type: TransactionType::Validate, security_key: auth_type.api_key, - amount: FloatMajorUnit::new(0.0), + amount: FloatMajorUnit::zero(), currency: item.request.currency, payment_method, merchant_defined_field: None, diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index d8a7092455b..a5859ea6dc6 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -1260,6 +1260,7 @@ impl TryFrom> for types::PaymentsAuthoriz statement_descriptor: payment_data.payment_intent.statement_descriptor_name, capture_method: payment_data.payment_attempt.capture_method, amount: amount.get_amount_as_i64(), + minor_amount: amount, currency: payment_data.currency, browser_info, email: payment_data.email, @@ -1420,12 +1421,14 @@ impl TryFrom> for types::PaymentsCaptureD let amount = MinorUnit::from(payment_data.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, currency: payment_data.currency, connector_transaction_id: connector .connector .connector_transaction_id(payment_data.payment_attempt.clone())? .ok_or(errors::ApiErrorResponse::ResourceIdNotFound)?, payment_amount: amount.get_amount_as_i64(), // This should be removed once we start moving to connector module + minor_payment_amount: amount, connector_meta: payment_data.payment_attempt.connector_metadata, multiple_capture_data: match payment_data.multiple_capture_data { Some(multiple_capture_data) => Some(MultipleCaptureRequestData { @@ -1702,6 +1705,7 @@ impl TryFrom> for types::CompleteAuthoriz statement_descriptor_suffix: payment_data.payment_intent.statement_descriptor_suffix, capture_method: payment_data.payment_attempt.capture_method, amount: amount.get_amount_as_i64(), // need to change once we move to connector module + minor_amount: amount, currency: payment_data.currency, browser_info, email: payment_data.email, diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index b9861ea1f23..7eea2c0e188 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -5,7 +5,10 @@ use std::collections::HashMap; #[cfg(feature = "olap")] use api_models::admin::MerchantConnectorInfo; -use common_utils::ext_traits::{AsyncExt, ValueExt}; +use common_utils::{ + ext_traits::{AsyncExt, ValueExt}, + types::MinorUnit, +}; use error_stack::{report, ResultExt}; use masking::PeekInterface; use router_env::{instrument, tracing}; @@ -77,12 +80,12 @@ pub async fn refund_create_core( .amount .or(payment_intent .amount_captured - .map(|capture_amount| capture_amount.get_amount_as_i64())) + .map(|capture_amount| capture_amount)) .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable("amount captured is none in a successful payment")?; //[#299]: Can we change the flow based on some workflow idea - utils::when(amount <= 0, || { + utils::when(amount <= MinorUnit::new(0), || { Err(report!(errors::ApiErrorResponse::InvalidDataFormat { field_name: "amount".to_string(), expected_format: "positive integer".to_string() @@ -178,7 +181,7 @@ pub async fn trigger_refund_to_gateway( &routed_through, merchant_account, key_store, - (payment_attempt.amount.get_amount_as_i64(), currency), + (payment_attempt.amount, currency), payment_intent, payment_attempt, refund, @@ -458,7 +461,7 @@ pub async fn sync_refund_with_gateway( &connector_id, merchant_account, key_store, - (payment_attempt.amount.get_amount_as_i64(), currency), + (payment_attempt.amount, currency), payment_intent, payment_attempt, refund, @@ -588,7 +591,7 @@ pub async fn validate_and_create_refund( key_store: &domain::MerchantKeyStore, payment_attempt: &storage::PaymentAttempt, payment_intent: &storage::PaymentIntent, - refund_amount: i64, + refund_amount: MinorUnit, req: refunds::RefundRequest, creds_identifier: Option, ) -> RouterResult { @@ -680,7 +683,7 @@ pub async fn validate_and_create_refund( validator::validate_refund_amount( total_amount_captured.get_amount_as_i64(), &all_refunds, - refund_amount, + refund_amount.get_amount_as_i64(), ) .change_context(errors::ApiErrorResponse::RefundAmountExceedsPaymentAmount)?; @@ -705,7 +708,7 @@ pub async fn validate_and_create_refund( .set_connector_transaction_id(connecter_transaction_id.to_string()) .set_connector(connector) .set_refund_type(req.refund_type.unwrap_or_default().foreign_into()) - .set_total_amount(payment_attempt.amount.get_amount_as_i64()) + .set_total_amount(payment_attempt.amount) .set_refund_amount(refund_amount) .set_currency(currency) .set_created_at(Some(common_utils::date_time::now())) diff --git a/crates/router/src/core/refunds/validator.rs b/crates/router/src/core/refunds/validator.rs index 3788b8ac26d..6d60508961d 100644 --- a/crates/router/src/core/refunds/validator.rs +++ b/crates/router/src/core/refunds/validator.rs @@ -54,7 +54,7 @@ pub fn validate_refund_amount( if refund.refund_status != enums::RefundStatus::Failure && refund.refund_status != enums::RefundStatus::TransactionFailure { - Some(refund.refund_amount) + Some(refund.refund_amount.get_amount_as_i64()) } else { None } diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index ca464cc6270..369b5a66396 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -5,7 +5,7 @@ use api_models::enums::{DisputeStage, DisputeStatus}; use api_models::payouts::PayoutVendorAccountDetails; use common_enums::{IntentStatus, RequestIncrementalAuthorization}; #[cfg(feature = "payouts")] -use common_utils::{crypto::Encryptable, pii::Email}; +use common_utils::{crypto::Encryptable, pii::Email, types::MinorUnit}; use common_utils::{errors::CustomResult, ext_traits::AsyncExt}; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{payment_address::PaymentAddress, router_data::ErrorResponse}; @@ -218,7 +218,7 @@ pub async fn construct_refund_router_data<'a, F>( connector_id: &str, merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, - money: (i64, enums::Currency), + money: (MinorUnit, enums::Currency), payment_intent: &'a storage::PaymentIntent, payment_attempt: &storage::PaymentAttempt, refund: &'a storage::Refund, @@ -323,9 +323,11 @@ pub async fn construct_refund_router_data<'a, F>( request: types::RefundsData { refund_id: refund.refund_id.clone(), connector_transaction_id: refund.connector_transaction_id.clone(), - refund_amount: refund.refund_amount, + refund_amount: refund.refund_amount.get_amount_as_i64(), + minor_refund_amount: refund.refund_amount, currency, - payment_amount, + payment_amount: payment_amount.get_amount_as_i64(), + minor_payment_amount: payment_amount, webhook_url, connector_metadata: payment_attempt.connector_metadata.clone(), reason: refund.refund_reason.clone(), diff --git a/crates/router/src/db/refund.rs b/crates/router/src/db/refund.rs index 1b1bfed3871..b6db4fae72c 100644 --- a/crates/router/src/db/refund.rs +++ b/crates/router/src/db/refund.rs @@ -1,6 +1,7 @@ #[cfg(feature = "olap")] use std::collections::HashSet; +use common_utils::types::MinorUnit; use diesel_models::{errors::DatabaseError, refund::RefundUpdateInternal}; use error_stack::ResultExt; @@ -1024,8 +1025,10 @@ impl RefundInterface for MockDb { .amount_filter .as_ref() .map_or(true, |amount| { - refund.refund_amount >= amount.start_amount.unwrap_or(i64::MIN) - && refund.refund_amount <= amount.end_amount.unwrap_or(i64::MAX) + refund.refund_amount + >= MinorUnit::new(amount.start_amount.unwrap_or(i64::MIN)) + && refund.refund_amount + <= MinorUnit::new(amount.end_amount.unwrap_or(i64::MAX)) }) }) .filter(|refund| { @@ -1173,8 +1176,10 @@ impl RefundInterface for MockDb { .amount_filter .as_ref() .map_or(true, |amount| { - refund.refund_amount >= amount.start_amount.unwrap_or(i64::MIN) - && refund.refund_amount <= amount.end_amount.unwrap_or(i64::MAX) + refund.refund_amount + >= MinorUnit::new(amount.start_amount.unwrap_or(i64::MIN)) + && refund.refund_amount + <= MinorUnit::new(amount.end_amount.unwrap_or(i64::MAX)) }) }) .filter(|refund| { diff --git a/crates/router/src/services/kafka/refund.rs b/crates/router/src/services/kafka/refund.rs index 4bfe2cd31ec..d5ef71bf651 100644 --- a/crates/router/src/services/kafka/refund.rs +++ b/crates/router/src/services/kafka/refund.rs @@ -1,3 +1,4 @@ +use common_utils::types::MinorUnit; use diesel_models::{enums as storage_enums, refund::Refund}; use time::OffsetDateTime; @@ -12,9 +13,9 @@ pub struct KafkaRefund<'a> { pub connector_refund_id: Option<&'a String>, pub external_reference_id: Option<&'a String>, pub refund_type: &'a storage_enums::RefundType, - pub total_amount: &'a i64, + pub total_amount: &'a MinorUnit, pub currency: &'a storage_enums::Currency, - pub refund_amount: &'a i64, + pub refund_amount: &'a MinorUnit, pub refund_status: &'a storage_enums::RefundStatus, pub sent_to_gateway: &'a bool, pub refund_error_message: Option<&'a String>, diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index 4a28f0cfc99..e17ec791637 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -21,7 +21,7 @@ use std::marker::PhantomData; pub use api_models::{enums::Connector, mandates}; #[cfg(feature = "payouts")] pub use api_models::{enums::PayoutConnectors, payouts as payout_types}; -pub use common_utils::{request::RequestContent, pii, pii::Email, types::MinorUnit}; +pub use common_utils::{pii, pii::Email, request::RequestContent, types::MinorUnit}; #[cfg(feature = "payouts")] pub use hyperswitch_domain_models::router_request_types::PayoutsData; #[cfg(feature = "payouts")] @@ -761,6 +761,7 @@ impl ForeignFrom<&SetupMandateRouterData> for PaymentsAuthorizeData { email: data.request.email.clone(), customer_name: data.request.customer_name.clone(), amount: 0, + minor_amount: MinorUnit::new(0), statement_descriptor: None, capture_method: None, webhook_url: None, diff --git a/crates/router/src/types/api/verify_connector.rs b/crates/router/src/types/api/verify_connector.rs index 0d69f277e18..60749f64789 100644 --- a/crates/router/src/types/api/verify_connector.rs +++ b/crates/router/src/types/api/verify_connector.rs @@ -25,6 +25,7 @@ impl VerifyConnectorData { email: None, customer_name: None, amount: 1000, + minor_amount: common_utils::types::MinorUnit::new(1000), confirm: true, currency: storage_enums::Currency::USD, metadata: None, diff --git a/crates/router/src/utils/user/sample_data.rs b/crates/router/src/utils/user/sample_data.rs index 8936b2af67f..043d98da18e 100644 --- a/crates/router/src/utils/user/sample_data.rs +++ b/crates/router/src/utils/user/sample_data.rs @@ -2,6 +2,7 @@ use api_models::{ enums::Connector::{DummyConnector4, DummyConnector7}, user::sample_data::SampleDataRequest, }; +use common_utils::types::MinorUnit; use diesel_models::{user::sample_data::PaymentAttemptBatchNew, RefundNew}; use error_stack::ResultExt; use hyperswitch_domain_models::payments::payment_intent::PaymentIntentNew; @@ -174,7 +175,7 @@ pub async fn generate_sample_data( true => common_enums::IntentStatus::Failed, _ => common_enums::IntentStatus::Succeeded, }, - amount: common_utils::types::MinorUnit::new(amount * 100), + amount: MinorUnit::new(amount * 100), currency: Some( *currency_vec .get((num - 1) % currency_vec_len) @@ -192,7 +193,7 @@ pub async fn generate_sample_data( ), attempt_count: 1, customer_id: Some("hs-dashboard-user".to_string()), - amount_captured: Some(common_utils::types::MinorUnit::new(amount * 100)), + amount_captured: Some(MinorUnit::new(amount * 100)), profile_id: Some(profile_id.clone()), return_url: Default::default(), metadata: Default::default(), @@ -286,8 +287,8 @@ pub async fn generate_sample_data( currency: *currency_vec .get((num - 1) % currency_vec_len) .unwrap_or(&common_enums::Currency::USD), - total_amount: amount * 100, - refund_amount: amount * 100, + total_amount: MinorUnit::new(amount * 100), + refund_amount: MinorUnit::new(amount * 100), refund_status: common_enums::RefundStatus::Success, sent_to_gateway: true, refund_type: diesel_models::enums::RefundType::InstantRefund, From 64b8693f69bec9dce9021e787b17987b7e0938dc Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 12:39:49 +0000 Subject: [PATCH 45/82] docs(openapi): re-generate OpenAPI specification --- openapi/openapi_spec.json | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 4ee0e58c77a..ac1fcf02201 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -17258,12 +17258,12 @@ "maxLength": 255 }, "amount": { - "type": "integer", - "format": "int64", - "description": "Total amount for which the refund is to be initiated. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, this will default to the full payment amount", - "example": 6540, - "nullable": true, - "minimum": 100 + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true }, "reason": { "type": "string", @@ -17325,9 +17325,7 @@ "description": "The payment id against which refund is initiated" }, "amount": { - "type": "integer", - "format": "int64", - "description": "The refund amount, which should be less than or equal to the total 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" + "$ref": "#/components/schemas/MinorUnit" }, "currency": { "type": "string", From 1939b5fac74f4a9e007a7c876d700b247d9504e1 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Wed, 29 May 2024 18:13:59 +0530 Subject: [PATCH 46/82] refactor(router): fixed open-api specs' --- crates/api_models/src/refunds.rs | 3 ++- openapi/openapi_spec.json | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/api_models/src/refunds.rs b/crates/api_models/src/refunds.rs index 9f531bc549c..2cec4038703 100644 --- a/crates/api_models/src/refunds.rs +++ b/crates/api_models/src/refunds.rs @@ -36,7 +36,7 @@ pub struct RefundRequest { pub merchant_id: Option, /// Total amount for which the refund is to be initiated. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, this will default to the full payment amount - #[schema(minimum = 100, example = 6540)] + #[schema(value_type = Option , minimum = 100, example = 6540)] pub amount: Option, /// Reason for the refund. Often useful for displaying to users and your customer support executive. In case the payment went through Stripe, this field needs to be passed with one of these enums: `duplicate`, `fraudulent`, or `requested_by_customer` @@ -115,6 +115,7 @@ pub struct RefundResponse { /// The payment id against which refund is initiated pub payment_id: String, /// The refund amount, which should be less than or equal to the total 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 + #[schema(value_type = Option , minimum = 100, example = 6540)] pub amount: MinorUnit, /// The three-letter ISO currency code pub currency: String, diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 4ee0e58c77a..d7a9b3121ac 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -17310,7 +17310,6 @@ "required": [ "refund_id", "payment_id", - "amount", "currency", "status", "connector" @@ -17327,7 +17326,10 @@ "amount": { "type": "integer", "format": "int64", - "description": "The refund amount, which should be less than or equal to the total 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" + "description": "The refund amount, which should be less than or equal to the total 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": 6540, + "nullable": true, + "minimum": 100 }, "currency": { "type": "string", From 7edf17b5b5e2c318d4e6c529d3fbf9411c2b3a80 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 12:47:23 +0000 Subject: [PATCH 47/82] docs(openapi): re-generate OpenAPI specification --- openapi/openapi_spec.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 07854b40b42..d7a9b3121ac 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -17258,12 +17258,12 @@ "maxLength": 255 }, "amount": { - "allOf": [ - { - "$ref": "#/components/schemas/MinorUnit" - } - ], - "nullable": true + "type": "integer", + "format": "int64", + "description": "Total amount for which the refund is to be initiated. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, this will default to the full payment amount", + "example": 6540, + "nullable": true, + "minimum": 100 }, "reason": { "type": "string", From 8ac5ecc55cdfc6ac129aa0c550b61fe8d8902cda Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Wed, 29 May 2024 18:52:50 +0530 Subject: [PATCH 48/82] refactor(router): fixed clippy issue --- crates/common_utils/src/types.rs | 21 +++++++++++-------- .../src/compatibility/stripe/refunds/types.rs | 2 +- crates/router/src/core/refunds.rs | 3 +-- crates/router/tests/connectors/utils.rs | 7 ++++++- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 08731e053ae..bcedbb1ddd1 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -350,13 +350,14 @@ impl MinorUnit { /// Paypal Connector accepts Zero and Two decimal currency but not three decimal and it should be updated as required for 3 decimal currencies. /// Paypal Ref - https://developer.paypal.com/docs/reports/reference/paypal-supported-currencies/ fn to_major_unit_as_string( - &self, + self, currency: enums::Currency, ) -> Result> { let amount_f64 = self.to_major_unit_as_f64(currency)?; - let amount_string = if currency.is_zero_decimal_currency() { + let amount_string = if currency.is_zero_decimal_currency(){ amount_f64.0.to_string() - } else if currency.is_three_decimal_currency() { + } + else if currency.is_three_decimal_currency() { format!("{:.3}", amount_f64.0) } else { format!("{:.2}", amount_f64.0) @@ -366,7 +367,7 @@ impl MinorUnit { /// Convert the amount to its major denomination based on Currency and return f64 fn to_major_unit_as_f64( - &self, + self, currency: enums::Currency, ) -> Result> { let amount_decimal = @@ -387,10 +388,11 @@ impl MinorUnit { ///Convert minor unit to string minor unit fn to_minor_unit_as_string( - &self, + self, ) -> Result> { Ok(StringMinorUnit::new(self.0.to_string())) } + } impl Display for MinorUnit { @@ -483,13 +485,13 @@ impl FloatMajorUnit { } /// forms a new major unit with zero amount - pub fn zero() -> Self { + pub fn zero() -> Self{ Self(0.0) } /// converts to minor unit as i64 from FloatMajorUnit fn to_minor_unit_as_i64( - &self, + self, currency: enums::Currency, ) -> Result> { let amount_decimal = @@ -581,12 +583,13 @@ mod amount_conversion_tests { let converted_amount = required_conversion .convert(request_amount, ZERO_DECIMAL_CURRENCY) .unwrap(); - assert_eq!(converted_amount.0, 999999999.0); + assert_eq!(converted_amount.0, 999999999.0); let converted_back_amount = required_conversion .convert_back(converted_amount, ZERO_DECIMAL_CURRENCY) .unwrap(); assert_eq!(converted_back_amount, request_amount); + } #[test] @@ -627,7 +630,7 @@ mod amount_conversion_tests { let converted_amount = required_conversion .convert(request_amount, ZERO_DECIMAL_CURRENCY) .unwrap(); - assert_eq!(converted_amount.0, "999999999".to_string()); + assert_eq!(converted_amount.0, "999999999".to_string()); let converted_back_amount = required_conversion .convert_back(converted_amount, ZERO_DECIMAL_CURRENCY) diff --git a/crates/router/src/compatibility/stripe/refunds/types.rs b/crates/router/src/compatibility/stripe/refunds/types.rs index 7205eeef739..3a52d39d72e 100644 --- a/crates/router/src/compatibility/stripe/refunds/types.rs +++ b/crates/router/src/compatibility/stripe/refunds/types.rs @@ -48,7 +48,7 @@ impl From for refunds::RefundRequest { refund_id: req.refund_id, amount: req .amount - .map(|amount| common_utils::types::MinorUnit::new(amount)), + .map(common_utils::types::MinorUnit::new), payment_id: req.payment_intent, reason: req.reason, refund_type: Some(refunds::RefundType::Instant), diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index 7eea2c0e188..17271938553 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -79,8 +79,7 @@ pub async fn refund_create_core( amount = req .amount .or(payment_intent - .amount_captured - .map(|capture_amount| capture_amount)) + .amount_captured) .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable("amount captured is none in a successful payment")?; diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index 9955cb77df7..62177aad028 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -11,7 +11,7 @@ use router::{ core::{errors::ConnectorError, payments}, db::StorageImpl, routes, services, - types::{self, storage::enums, AccessToken, PaymentAddress, RouterData}, + types::{self, storage::enums, AccessToken, MinorUnit, PaymentAddress, RouterData}, }; use test_utils::connector_auth::ConnectorAuthType; use tokio::sync::oneshot; @@ -414,11 +414,13 @@ pub trait ConnectorActions: Connector { let request = self.generate_data( payment_data.unwrap_or_else(|| types::RefundsData { payment_amount: 1000, + minor_payment_amount: MinorUnit::new(1000), currency: enums::Currency::USD, refund_id: uuid::Uuid::new_v4().to_string(), connector_transaction_id: "".to_string(), webhook_url: None, refund_amount: 100, + minor_refund_amount: MinorUnit::new(100), connector_metadata: None, reason: None, connector_refund_id: Some(refund_id), @@ -915,6 +917,7 @@ impl Default for PaymentAuthorizeType { let data = types::PaymentsAuthorizeData { payment_method_data: types::domain::PaymentMethodData::Card(CCardType::default().0), amount: 100, + minor_amount: MinorUnit::new(100), currency: enums::Currency::USD, confirm: true, statement_descriptor_suffix: None, @@ -1012,10 +1015,12 @@ impl Default for PaymentRefundType { fn default() -> Self { let data = types::RefundsData { payment_amount: 100, + minor_payment_amount: MinorUnit::new(100), currency: enums::Currency::USD, refund_id: uuid::Uuid::new_v4().to_string(), connector_transaction_id: String::new(), refund_amount: 100, + minor_refund_amount: MinorUnit::new(100), webhook_url: None, connector_metadata: None, reason: Some("Customer returned product".to_string()), From 97113c9e0bd48218d62d657415ecf2e676b051a3 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 13:23:45 +0000 Subject: [PATCH 49/82] chore: run formatter --- crates/common_utils/src/types.rs | 17 ++++++----------- .../src/compatibility/stripe/refunds/types.rs | 4 +--- crates/router/src/core/refunds.rs | 3 +-- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index bcedbb1ddd1..7ab78ce3257 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -354,10 +354,9 @@ impl MinorUnit { currency: enums::Currency, ) -> Result> { let amount_f64 = self.to_major_unit_as_f64(currency)?; - let amount_string = if currency.is_zero_decimal_currency(){ + let amount_string = if currency.is_zero_decimal_currency() { amount_f64.0.to_string() - } - else if currency.is_three_decimal_currency() { + } else if currency.is_three_decimal_currency() { format!("{:.3}", amount_f64.0) } else { format!("{:.2}", amount_f64.0) @@ -387,12 +386,9 @@ impl MinorUnit { } ///Convert minor unit to string minor unit - fn to_minor_unit_as_string( - self, - ) -> Result> { + fn to_minor_unit_as_string(self) -> Result> { Ok(StringMinorUnit::new(self.0.to_string())) } - } impl Display for MinorUnit { @@ -485,7 +481,7 @@ impl FloatMajorUnit { } /// forms a new major unit with zero amount - pub fn zero() -> Self{ + pub fn zero() -> Self { Self(0.0) } @@ -583,13 +579,12 @@ mod amount_conversion_tests { let converted_amount = required_conversion .convert(request_amount, ZERO_DECIMAL_CURRENCY) .unwrap(); - assert_eq!(converted_amount.0, 999999999.0); + assert_eq!(converted_amount.0, 999999999.0); let converted_back_amount = required_conversion .convert_back(converted_amount, ZERO_DECIMAL_CURRENCY) .unwrap(); assert_eq!(converted_back_amount, request_amount); - } #[test] @@ -630,7 +625,7 @@ mod amount_conversion_tests { let converted_amount = required_conversion .convert(request_amount, ZERO_DECIMAL_CURRENCY) .unwrap(); - assert_eq!(converted_amount.0, "999999999".to_string()); + assert_eq!(converted_amount.0, "999999999".to_string()); let converted_back_amount = required_conversion .convert_back(converted_amount, ZERO_DECIMAL_CURRENCY) diff --git a/crates/router/src/compatibility/stripe/refunds/types.rs b/crates/router/src/compatibility/stripe/refunds/types.rs index 3a52d39d72e..d00da0d8588 100644 --- a/crates/router/src/compatibility/stripe/refunds/types.rs +++ b/crates/router/src/compatibility/stripe/refunds/types.rs @@ -46,9 +46,7 @@ impl From for refunds::RefundRequest { fn from(req: StripeCreateRefundRequest) -> Self { Self { refund_id: req.refund_id, - amount: req - .amount - .map(common_utils::types::MinorUnit::new), + amount: req.amount.map(common_utils::types::MinorUnit::new), payment_id: req.payment_intent, reason: req.reason, refund_type: Some(refunds::RefundType::Instant), diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index 17271938553..9ab1ec0eb88 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -78,8 +78,7 @@ pub async fn refund_create_core( // Amount is not passed in request refer from payment intent. amount = req .amount - .or(payment_intent - .amount_captured) + .or(payment_intent.amount_captured) .ok_or(errors::ApiErrorResponse::InternalServerError) .attach_printable("amount captured is none in a successful payment")?; From 7fd1af9539d97c5848a3f442c5ef0e47ce3bbf6e Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Wed, 29 May 2024 19:18:55 +0530 Subject: [PATCH 50/82] refactor(router): fixed open-api specs --- crates/api_models/src/refunds.rs | 2 +- openapi/openapi_spec.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/api_models/src/refunds.rs b/crates/api_models/src/refunds.rs index 2cec4038703..c97344ff48b 100644 --- a/crates/api_models/src/refunds.rs +++ b/crates/api_models/src/refunds.rs @@ -115,7 +115,7 @@ pub struct RefundResponse { /// The payment id against which refund is initiated pub payment_id: String, /// The refund amount, which should be less than or equal to the total 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 - #[schema(value_type = Option , minimum = 100, example = 6540)] + #[schema(value_type = i64 , minimum = 100, example = 6540)] pub amount: MinorUnit, /// The three-letter ISO currency code pub currency: String, diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index d7a9b3121ac..024ec7fc174 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -17310,6 +17310,7 @@ "required": [ "refund_id", "payment_id", + "amount", "currency", "status", "connector" @@ -17328,7 +17329,6 @@ "format": "int64", "description": "The refund amount, which should be less than or equal to the total 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": 6540, - "nullable": true, "minimum": 100 }, "currency": { From c4bd128baa518e9ef14b872334b85d364aeb0093 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 14:16:05 +0000 Subject: [PATCH 51/82] chore: run formatter --- crates/hyperswitch_domain_models/src/router_request_types.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index 1543f755ff6..009993f8401 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -1,7 +1,9 @@ pub mod authentication; pub mod fraud_check; use api_models::payments::RequestSurchargeDetails; -use common_utils::{consts, errors, ext_traits::OptionExt, pii, types as common_types, types::MinorUnit}; +use common_utils::{ + consts, errors, ext_traits::OptionExt, pii, types as common_types, types::MinorUnit, +}; use diesel_models::enums as storage_enums; use error_stack::ResultExt; use masking::Secret; From 35c47fe96bf0f146634d4175fd34c32080ac82d8 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Wed, 29 May 2024 20:39:20 +0530 Subject: [PATCH 52/82] refactor(router): fixed cargo hack issue --- crates/router/src/core/utils.rs | 4 ++-- crates/router/src/db/refund.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index 369b5a66396..e585724e96a 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -5,8 +5,8 @@ use api_models::enums::{DisputeStage, DisputeStatus}; use api_models::payouts::PayoutVendorAccountDetails; use common_enums::{IntentStatus, RequestIncrementalAuthorization}; #[cfg(feature = "payouts")] -use common_utils::{crypto::Encryptable, pii::Email, types::MinorUnit}; -use common_utils::{errors::CustomResult, ext_traits::AsyncExt}; +use common_utils::{crypto::Encryptable, pii::Email}; +use common_utils::{errors::CustomResult, ext_traits::AsyncExt, types::MinorUnit}; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{payment_address::PaymentAddress, router_data::ErrorResponse}; #[cfg(feature = "payouts")] diff --git a/crates/router/src/db/refund.rs b/crates/router/src/db/refund.rs index b6db4fae72c..b712de820c3 100644 --- a/crates/router/src/db/refund.rs +++ b/crates/router/src/db/refund.rs @@ -1,6 +1,6 @@ #[cfg(feature = "olap")] use std::collections::HashSet; - +#[cfg(feature = "olap")] use common_utils::types::MinorUnit; use diesel_models::{errors::DatabaseError, refund::RefundUpdateInternal}; use error_stack::ResultExt; From 3135548a721bfa6e95323ef5bbbf266b5f50626b Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 15:10:13 +0000 Subject: [PATCH 53/82] chore: run formatter --- crates/router/src/db/refund.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/router/src/db/refund.rs b/crates/router/src/db/refund.rs index b712de820c3..c5edd863caf 100644 --- a/crates/router/src/db/refund.rs +++ b/crates/router/src/db/refund.rs @@ -1,5 +1,6 @@ #[cfg(feature = "olap")] use std::collections::HashSet; + #[cfg(feature = "olap")] use common_utils::types::MinorUnit; use diesel_models::{errors::DatabaseError, refund::RefundUpdateInternal}; From 4a259a4f2f361b840e8233793ac4a92e51afaa30 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Thu, 30 May 2024 14:42:29 +0530 Subject: [PATCH 54/82] refactor(connector): added amount frame work support for stripe --- .../src/router_request_types.rs | 8 +++++++- .../src/connector/stripe/transformers.rs | 20 +++++++++---------- crates/router/src/connector/utils.rs | 7 +++++++ .../router/src/core/payments/transformers.rs | 1 + 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index 009993f8401..b7b401c4561 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -67,7 +67,7 @@ pub struct PaymentsAuthorizeData { #[derive(Debug, serde::Deserialize, Clone)] pub struct PaymentCharges { pub charge_type: api_models::enums::PaymentChargeType, - pub fees: i64, + pub fees: MinorUnit, pub transfer_account_id: String, } @@ -236,6 +236,9 @@ pub struct PaymentsPreProcessingData { pub browser_info: Option, pub connector_transaction_id: Option, pub redirect_response: Option, + + // New amount for amount frame work + pub minor_amount: Option, } impl TryFrom for PaymentsPreProcessingData { @@ -245,6 +248,7 @@ impl TryFrom for PaymentsPreProcessingData { Ok(Self { payment_method_data: Some(data.payment_method_data), amount: Some(data.amount), + minor_amount: Some(data.minor_amount), email: data.email, currency: Some(data.currency), payment_method_type: data.payment_method_type, @@ -269,6 +273,7 @@ impl TryFrom for PaymentsPreProcessingData { Ok(Self { payment_method_data: data.payment_method_data, amount: Some(data.amount), + minor_amount: Some(data.minor_amount), email: data.email, currency: Some(data.currency), payment_method_type: None, @@ -282,6 +287,7 @@ impl TryFrom for PaymentsPreProcessingData { surcharge_details: None, connector_transaction_id: data.connector_transaction_id, redirect_response: data.redirect_response, + }) } } diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 259dd2a6a64..32efa701d07 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -1845,11 +1845,11 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest { let charges = match &charges.charge_type { api_enums::PaymentChargeType::Stripe(charge_type) => match charge_type { api_enums::StripeChargeType::Direct => Some(IntentCharges { - application_fee_amount: MinorUnit::new(charges.fees), + application_fee_amount: charges.fees, destination_account_id: None, }), api_enums::StripeChargeType::Destination => Some(IntentCharges { - application_fee_amount: MinorUnit::new(charges.fees), + application_fee_amount: charges.fees, destination_account_id: Some(charges.transfer_account_id.clone()), }), }, @@ -1860,7 +1860,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest { }; Ok(Self { - amount: MinorUnit::new(item.request.amount), //hopefully we don't loose some cents here + amount: item.request.minor_amount, //hopefully we don't loose some cents here currency: item.request.currency.to_string(), //we need to copy the value and not transfer ownership statement_descriptor_suffix: item.request.statement_descriptor_suffix.clone(), statement_descriptor: item.request.statement_descriptor.clone(), @@ -2863,10 +2863,10 @@ pub struct RefundRequest { impl TryFrom<&types::RefundsRouterData> for RefundRequest { type Error = error_stack::Report; fn try_from(item: &types::RefundsRouterData) -> Result { - let amount = item.request.refund_amount; + let amount = item.request.minor_refund_amount; let payment_intent = item.request.connector_transaction_id.clone(); Ok(Self { - amount: Some(MinorUnit::new(amount)), + amount: Some(amount), payment_intent, meta_data: StripeMetadata { order_id: Some(item.request.refund_id.clone()), @@ -2889,7 +2889,7 @@ pub struct ChargeRefundRequest { impl TryFrom<&types::RefundsRouterData> for ChargeRefundRequest { type Error = error_stack::Report; fn try_from(item: &types::RefundsRouterData) -> Result { - let amount = item.request.refund_amount; + let amount = item.request.minor_refund_amount; match item.request.charges.as_ref() { None => Err(errors::ConnectorError::MissingRequiredField { field_name: "charges", @@ -2909,7 +2909,7 @@ impl TryFrom<&types::RefundsRouterData> for ChargeRefundRequest { charge: charges.charge_id.clone(), refund_application_fee, reverse_transfer, - amount: Some(MinorUnit::new(amount)), + amount: Some(amount), meta_data: StripeMetadata { order_id: Some(item.request.refund_id.clone()), is_refund_id_as_reference: Some("true".to_string()), @@ -3184,7 +3184,7 @@ impl TryFrom<&types::PaymentsCaptureRouterData> for CaptureRequest { type Error = error_stack::Report; fn try_from(item: &types::PaymentsCaptureRouterData) -> Result { Ok(Self { - amount_to_capture: Some(MinorUnit::new(item.request.amount_to_capture)), + amount_to_capture: Some(item.request.minor_amount_to_capture), }) } } @@ -3193,7 +3193,7 @@ impl TryFrom<&types::PaymentsPreProcessingRouterData> for StripeCreditTransferSo type Error = error_stack::Report; fn try_from(item: &types::PaymentsPreProcessingRouterData) -> Result { let currency = item.request.get_currency()?; - let amount = item.request.get_amount()?; + let amount = item.request.get_minor_amount()?; match &item.request.payment_method_data { Some(domain::PaymentMethodData::BankTransfer(bank_transfer_data)) => { @@ -3205,7 +3205,7 @@ impl TryFrom<&types::PaymentsPreProcessingRouterData> for StripeCreditTransferSo payment_method_data: MultibancoTransferData { email: item.request.get_email()?, }, - amount: Some(MinorUnit::new(amount)), + amount: Some(amount), return_url: Some(item.get_return_url()?), }), ), diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index d12c680e738..9077064d5d2 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -450,6 +450,7 @@ pub trait PaymentsPreProcessingData { fn get_payment_method_type(&self) -> Result; fn get_currency(&self) -> Result; fn get_amount(&self) -> Result; + fn get_minor_amount(&self) -> Result; fn is_auto_capture(&self) -> Result; fn get_order_details(&self) -> Result, Error>; fn get_webhook_url(&self) -> Result; @@ -473,6 +474,12 @@ impl PaymentsPreProcessingData for types::PaymentsPreProcessingData { fn get_amount(&self) -> Result { self.amount.ok_or_else(missing_field_err("amount")) } + + // New minor amount function for amount framework + fn get_minor_amount(&self) -> Result { + self.minor_amount.ok_or_else(missing_field_err("amount")) + } + fn is_auto_capture(&self) -> Result { match self.capture_method { Some(enums::CaptureMethod::Automatic) | None => Ok(true), diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index a5859ea6dc6..fe420d5e445 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -1783,6 +1783,7 @@ impl TryFrom> for types::PaymentsPreProce email: payment_data.email, currency: Some(payment_data.currency), amount: Some(amount.get_amount_as_i64()), // need to change this once we move to connector module + minor_amount: Some(amount), payment_method_type: payment_data.payment_attempt.payment_method_type, setup_mandate_details: payment_data.setup_mandate, capture_method: payment_data.payment_attempt.capture_method, From 3366b2e2ed17723c9f60003aadd0b28ba646efb8 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 09:13:12 +0000 Subject: [PATCH 55/82] chore: run formatter --- crates/hyperswitch_domain_models/src/router_request_types.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index b7b401c4561..2ad15b91398 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -287,7 +287,6 @@ impl TryFrom for PaymentsPreProcessingData { surcharge_details: None, connector_transaction_id: data.connector_transaction_id, redirect_response: data.redirect_response, - }) } } From 88ea441bae07001b7fe2c3f3e34312f766892b75 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Thu, 30 May 2024 16:36:52 +0530 Subject: [PATCH 56/82] refactor(connector): added amount frame work to bluesnap --- crates/router/src/connector/bluesnap.rs | 55 +++++++++++++------ .../src/connector/bluesnap/transformers.rs | 18 +++--- crates/router/src/types/api.rs | 2 +- crates/router/src/types/api/disputes.rs | 1 + 4 files changed, 50 insertions(+), 26 deletions(-) diff --git a/crates/router/src/connector/bluesnap.rs b/crates/router/src/connector/bluesnap.rs index f2a903c91f3..1ce0e84122f 100644 --- a/crates/router/src/connector/bluesnap.rs +++ b/crates/router/src/connector/bluesnap.rs @@ -1,12 +1,12 @@ pub mod transformers; -use std::fmt::Debug; use base64::Engine; use common_utils::{ crypto, ext_traits::{StringExt, ValueExt}, request::RequestContent, + types::{StringMajorUnitForConnector,StringMajorUnit, AmountConvertor} }; use diesel_models::enums; use error_stack::{report, ResultExt}; @@ -41,8 +41,18 @@ use crate::{ pub const BLUESNAP_TRANSACTION_NOT_FOUND: &str = "is not authorized to view merchant-transaction:"; -#[derive(Debug, Clone)] -pub struct Bluesnap; +#[derive(Clone)] +pub struct Bluesnap { + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Bluesnap { + pub fn new() -> &'static Self { + &Self { + amount_converter: &StringMajorUnitForConnector + } + } +} impl ConnectorCommonExt for Bluesnap where @@ -111,7 +121,7 @@ impl ConnectorCommon for Bluesnap { bluesnap::BluesnapErrors::Payment(error_response) => { let error_list = error_response.message.clone(); let option_error_code_message = get_error_code_error_message_based_on_priority( - Self.clone(), + self.clone(), error_list.into_iter().map(|errors| errors.into()).collect(), ); let reason = error_response @@ -465,10 +475,13 @@ impl ConnectorIntegration CustomResult { + let amount_to_capture = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount_to_capture, + req.request.currency + )?; let connector_router_data = bluesnap::BluesnapRouterData::try_from(( - &self.get_currency_unit(), - req.request.currency, - req.request.amount_to_capture, + amount_to_capture, req, ))?; let connector_req = bluesnap::BluesnapCaptureRequest::try_from(&connector_router_data)?; @@ -652,10 +665,13 @@ impl ConnectorIntegration CustomResult { + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount, + req.request.currency + )?; let connector_router_data = bluesnap::BluesnapRouterData::try_from(( - &self.get_currency_unit(), - req.request.currency, - req.request.amount, + amount, req, ))?; match req.is_three_ds() && req.request.is_card() { @@ -792,10 +808,13 @@ impl req: &types::PaymentsCompleteAuthorizeRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = bluesnap::BluesnapRouterData::try_from(( - &self.get_currency_unit(), + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount, req.request.currency, - req.request.amount, + )?; + let connector_router_data = bluesnap::BluesnapRouterData::try_from(( + amount, req, ))?; let connector_req = @@ -889,10 +908,13 @@ impl ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = bluesnap::BluesnapRouterData::try_from(( - &self.get_currency_unit(), + let refund_amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_refund_amount, req.request.currency, - req.request.refund_amount, + )?; + let connector_router_data = bluesnap::BluesnapRouterData::try_from(( + refund_amount, req, ))?; let connector_req = bluesnap::BluesnapRefundRequest::try_from(&connector_router_data)?; @@ -1123,6 +1145,7 @@ impl api::IncomingWebhook for Bluesnap { let dispute_details: bluesnap::BluesnapDisputeWebhookBody = serde_urlencoded::from_bytes(request.body) .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?; + let dispute_amount = Ok(api::disputes::DisputePayload { amount: connector_utils::to_currency_lower_unit( dispute_details.invoice_charge_amount.abs().to_string(), diff --git a/crates/router/src/connector/bluesnap/transformers.rs b/crates/router/src/connector/bluesnap/transformers.rs index b8b5091fe5e..dfa88e911ff 100644 --- a/crates/router/src/connector/bluesnap/transformers.rs +++ b/crates/router/src/connector/bluesnap/transformers.rs @@ -6,6 +6,7 @@ use common_utils::{ errors::CustomResult, ext_traits::{ByteSliceExt, StringExt, ValueExt}, pii::Email, + types::StringMajorUnit }; use error_stack::ResultExt; use masking::{ExposeInterface, PeekInterface}; @@ -32,16 +33,15 @@ const DISPLAY_METADATA: &str = "Y"; #[derive(Debug, Serialize)] pub struct BluesnapRouterData { - pub amount: String, + pub amount: StringMajorUnit, pub router_data: T, } -impl TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for BluesnapRouterData { +impl TryFrom<(StringMajorUnit, T)> for BluesnapRouterData { type Error = error_stack::Report; fn try_from( - (currency_unit, currency, amount, item): (&api::CurrencyUnit, enums::Currency, i64, T), + (amount, item): (StringMajorUnit, T), ) -> Result { - let amount = utils::get_amount_as_string(currency_unit, amount, currency)?; Ok(Self { amount, router_data: item, @@ -52,7 +52,7 @@ impl TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for BluesnapRoute #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct BluesnapPaymentsRequest { - amount: String, + amount: StringMajorUnit, #[serde(flatten)] payment_method: PaymentMethodDetails, currency: enums::Currency, @@ -562,7 +562,7 @@ impl TryFrom, @@ -703,7 +703,7 @@ impl TryFrom<&types::PaymentsCancelRouterData> for BluesnapVoidRequest { pub struct BluesnapCaptureRequest { card_transaction_type: BluesnapTxnType, transaction_id: String, - amount: Option, + amount: Option, } impl TryFrom<&BluesnapRouterData<&types::PaymentsCaptureRouterData>> for BluesnapCaptureRequest { @@ -830,7 +830,7 @@ pub struct BluesnapWalletTokenResponse { #[serde(rename_all = "camelCase")] pub struct Refund { refund_transaction_id: String, - amount: String, + amount: StringMajorUnit, } #[derive(Default, Debug, Clone, Serialize, Deserialize)] @@ -878,7 +878,7 @@ impl #[derive(Default, Debug, Serialize)] pub struct BluesnapRefundRequest { - amount: Option, + amount: Option, reason: Option, } diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 22ef530f339..ed2a7030eec 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -326,7 +326,7 @@ impl ConnectorData { enums::Connector::Bankofamerica => Ok(Box::new(&connector::Bankofamerica)), enums::Connector::Billwerk => Ok(Box::new(&connector::Billwerk)), enums::Connector::Bitpay => Ok(Box::new(&connector::Bitpay)), - enums::Connector::Bluesnap => Ok(Box::new(&connector::Bluesnap)), + enums::Connector::Bluesnap => Ok(Box::new(connector::Bluesnap::new())), enums::Connector::Boku => Ok(Box::new(&connector::Boku)), enums::Connector::Braintree => Ok(Box::new(&connector::Braintree)), enums::Connector::Cashtocode => Ok(Box::new(&connector::Cashtocode)), diff --git a/crates/router/src/types/api/disputes.rs b/crates/router/src/types/api/disputes.rs index 85fdb307ed6..be4b06378f3 100644 --- a/crates/router/src/types/api/disputes.rs +++ b/crates/router/src/types/api/disputes.rs @@ -1,6 +1,7 @@ use masking::{Deserialize, Serialize}; use time::PrimitiveDateTime; + use crate::{services, types}; #[derive(Default, Debug, Deserialize, Serialize)] From 94f6f55484712982e88aaf2ead69077c79c306a6 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Thu, 30 May 2024 16:40:49 +0530 Subject: [PATCH 57/82] refactor(connector): addressed pr comments --- crates/router/src/connector/stripe/transformers.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 32efa701d07..7c9c8242f92 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -2100,7 +2100,7 @@ pub struct SepaAndBacsBankTransferInstructions { #[derive(Clone, Debug, Serialize)] pub struct QrCodeNextInstructions { pub image_data_url: Url, - pub display_to_timestamp: Option, + pub display_to_timestamp: Option, } #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] @@ -2820,7 +2820,7 @@ pub struct StripeCashappQrResponse { #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] pub struct QrCodeResponse { - pub expires_at: Option, + pub expires_at: Option, pub image_url_png: Url, pub image_url_svg: Url, } From 0dceb9138b0ce64ef0d97402e4ee8ba054ebdac3 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Thu, 30 May 2024 17:36:01 +0530 Subject: [PATCH 58/82] refactor(connector): added captured amount to router data --- crates/hyperswitch_domain_models/src/router_data.rs | 4 ++++ crates/router/src/connector/bluesnap.rs | 1 - crates/router/src/connector/stripe/transformers.rs | 13 ++++++++----- .../router/src/core/authentication/transformers.rs | 1 + .../src/core/fraud_check/flows/checkout_flow.rs | 1 + .../src/core/fraud_check/flows/fulfillment_flow.rs | 2 ++ .../src/core/fraud_check/flows/record_return.rs | 1 + .../router/src/core/fraud_check/flows/sale_flow.rs | 1 + .../src/core/fraud_check/flows/transaction_flow.rs | 1 + crates/router/src/core/mandate/utils.rs | 1 + crates/router/src/core/payments/helpers.rs | 1 + crates/router/src/core/payments/transformers.rs | 3 +++ crates/router/src/core/utils.rs | 11 +++++++++++ crates/router/src/core/webhooks/utils.rs | 1 + crates/router/src/types.rs | 2 ++ crates/router/src/types/api/verify_connector.rs | 1 + crates/router/tests/connectors/aci.rs | 2 ++ crates/router/tests/connectors/utils.rs | 1 + 18 files changed, 42 insertions(+), 6 deletions(-) diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs index d0481cecc53..98a930bf4f4 100644 --- a/crates/hyperswitch_domain_models/src/router_data.rs +++ b/crates/hyperswitch_domain_models/src/router_data.rs @@ -1,5 +1,6 @@ use std::{collections::HashMap, marker::PhantomData}; +use common_utils::types::MinorUnit; use masking::Secret; use crate::payment_address::PaymentAddress; @@ -65,6 +66,9 @@ pub struct RouterData { /// This field is used to store various data regarding the response from connector pub connector_response: Option, pub payment_method_status: Option, + + // minor amount for amount framework + pub minor_amount_captured: Option, } // Different patterns of authentication. diff --git a/crates/router/src/connector/bluesnap.rs b/crates/router/src/connector/bluesnap.rs index f2a903c91f3..ec294f5e1bb 100644 --- a/crates/router/src/connector/bluesnap.rs +++ b/crates/router/src/connector/bluesnap.rs @@ -74,7 +74,6 @@ impl ConnectorCommon for Bluesnap { fn common_get_content_type(&self) -> &'static str { "application/json" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { connectors.bluesnap.base_url.as_ref() } diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 7c9c8242f92..9193657a5a5 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -271,8 +271,8 @@ pub struct ChargesRequest { #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] pub struct ChargesResponse { pub id: String, - pub amount: u64, - pub amount_captured: u64, + pub amount: MinorUnit, + pub amount_captured: MinorUnit, pub currency: String, pub status: StripePaymentStatus, pub source: StripeSourceResponse, @@ -2417,10 +2417,10 @@ impl // statement_descriptor_suffix: item.response.statement_descriptor_suffix.map(|x| x.as_str()), // three_ds_form, response, - amount_captured: item + amount_captured : item.response.amount_received.map(|amount| amount.get_amount_as_i64()), + minor_amount_captured: item .response - .amount_received - .map(|amount| amount.get_amount_as_i64()), + .amount_received, connector_response: connector_response_data, ..item.data }) @@ -2606,6 +2606,9 @@ impl .response .amount_received .map(|amount| amount.get_amount_as_i64()), + minor_amount_captured : item + .response + .amount_received, connector_response: connector_response_data, ..item.data }) diff --git a/crates/router/src/core/authentication/transformers.rs b/crates/router/src/core/authentication/transformers.rs index e0e9ee0b526..679fbd50263 100644 --- a/crates/router/src/core/authentication/transformers.rs +++ b/crates/router/src/core/authentication/transformers.rs @@ -164,6 +164,7 @@ pub fn construct_router_data( auth_type: common_enums::AuthenticationType::NoThreeDs, connector_meta_data: merchant_connector_account.get_metadata(), amount_captured: None, + minor_amount_captured: None, access_token: None, session_token: None, reference_id: None, 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 c754682f72d..7bf72b5c9bd 100644 --- a/crates/router/src/core/fraud_check/flows/checkout_flow.rs +++ b/crates/router/src/core/fraud_check/flows/checkout_flow.rs @@ -68,6 +68,7 @@ impl ConstructFlowSpecificData( amount_captured: payment_intent .amount_captured .map(|amt| amt.get_amount_as_i64()), + minor_amount_captured: payment_intent + .amount_captured, payment_method_status: None, request: FraudCheckFulfillmentData { amount: payment_attempt.amount.get_amount_as_i64(), 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 b854a333770..df026cea1eb 100644 --- a/crates/router/src/core/fraud_check/flows/record_return.rs +++ b/crates/router/src/core/fraud_check/flows/record_return.rs @@ -66,6 +66,7 @@ impl ConstructFlowSpecificData( merchant_id: router_data.merchant_id, address: router_data.address, amount_captured: router_data.amount_captured, + minor_amount_captured:router_data.minor_amount_captured, auth_type: router_data.auth_type, connector: router_data.connector, connector_auth_type: router_data.connector_auth_type, diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index fe420d5e445..cc9e2e223b0 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -160,6 +160,9 @@ where .payment_intent .amount_captured .map(|amt| amt.get_amount_as_i64()), + minor_amount_captured: payment_data + .payment_intent + .amount_captured, access_token: None, session_token: None, reference_id: None, diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index e585724e96a..12fd65c4e61 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -165,6 +165,7 @@ pub async fn construct_payout_router_data<'a, F>( auth_type: enums::AuthenticationType::default(), connector_meta_data: merchant_connector_account.get_metadata(), amount_captured: None, + minor_amount_captured: None, payment_method_status: None, request: types::PayoutsData { payout_id: payouts.payout_id.to_owned(), @@ -320,6 +321,7 @@ pub async fn construct_refund_router_data<'a, F>( .amount_captured .map(|amt| amt.get_amount_as_i64()), payment_method_status: None, + minor_amount_captured : payment_intent.amount_captured, request: types::RefundsData { refund_id: refund.refund_id.clone(), connector_transaction_id: refund.connector_transaction_id.clone(), @@ -568,6 +570,8 @@ pub async fn construct_accept_dispute_router_data<'a>( amount_captured: payment_intent .amount_captured .map(|amt| amt.get_amount_as_i64()), + minor_amount_captured : payment_intent + .amount_captured, payment_method_status: None, request: types::AcceptDisputeRequestData { dispute_id: dispute.dispute_id.clone(), @@ -664,6 +668,8 @@ pub async fn construct_submit_evidence_router_data<'a>( amount_captured: payment_intent .amount_captured .map(|amt| amt.get_amount_as_i64()), + minor_amount_captured: payment_intent + .amount_captured, request: submit_evidence_request_data, response: Err(ErrorResponse::default()), access_token: None, @@ -758,6 +764,8 @@ pub async fn construct_upload_file_router_data<'a>( amount_captured: payment_intent .amount_captured .map(|amt| amt.get_amount_as_i64()), + minor_amount_captured: payment_intent + .amount_captured, payment_method_status: None, request: types::UploadFileRequestData { file_key, @@ -856,6 +864,8 @@ pub async fn construct_defend_dispute_router_data<'a>( amount_captured: payment_intent .amount_captured .map(|amt| amt.get_amount_as_i64()), + minor_amount_captured: payment_intent + .amount_captured, payment_method_status: None, request: types::DefendDisputeRequestData { dispute_id: dispute.dispute_id.clone(), @@ -943,6 +953,7 @@ pub async fn construct_retrieve_file_router_data<'a>( auth_type: diesel_models::enums::AuthenticationType::default(), connector_meta_data: merchant_connector_account.get_metadata(), amount_captured: None, + minor_amount_captured: None, payment_method_status: None, request: types::RetrieveFileRequestData { provider_file_id: file_metadata diff --git a/crates/router/src/core/webhooks/utils.rs b/crates/router/src/core/webhooks/utils.rs index ad1aafd3125..14c1d736997 100644 --- a/crates/router/src/core/webhooks/utils.rs +++ b/crates/router/src/core/webhooks/utils.rs @@ -87,6 +87,7 @@ pub async fn construct_webhook_router_data<'a>( auth_type: diesel_models::enums::AuthenticationType::default(), connector_meta_data: None, amount_captured: None, + minor_amount_captured: None, request: types::VerifyWebhookSourceRequestData { webhook_headers: request_details.headers.clone(), webhook_body: request_details.body.to_vec().clone(), diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs index e17ec791637..1d5242bdd6d 100644 --- a/crates/router/src/types.rs +++ b/crates/router/src/types.rs @@ -806,6 +806,7 @@ impl ForeignFrom<(&RouterData, T2) auth_type: data.auth_type, connector_meta_data: data.connector_meta_data.clone(), amount_captured: data.amount_captured, + minor_amount_captured: data.minor_amount_captured, access_token: data.access_token.clone(), response: data.response.clone(), payment_id: data.payment_id.clone(), @@ -866,6 +867,7 @@ impl auth_type: data.auth_type, connector_meta_data: data.connector_meta_data.clone(), amount_captured: data.amount_captured, + minor_amount_captured: data.minor_amount_captured, access_token: data.access_token.clone(), response: data.response.clone(), payment_id: data.payment_id.clone(), diff --git a/crates/router/src/types/api/verify_connector.rs b/crates/router/src/types/api/verify_connector.rs index 60749f64789..a952ae2bcd1 100644 --- a/crates/router/src/types/api/verify_connector.rs +++ b/crates/router/src/types/api/verify_connector.rs @@ -81,6 +81,7 @@ impl VerifyConnectorData { session_token: None, payment_method: storage_enums::PaymentMethod::Card, amount_captured: None, + minor_amount_captured: None, preprocessing_id: None, connector_customer: None, connector_auth_type: self.connector_auth.clone(), diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs index b4eafee4c83..0980c872c76 100644 --- a/crates/router/tests/connectors/aci.rs +++ b/crates/router/tests/connectors/aci.rs @@ -97,6 +97,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData { ), connector_meta_data: None, amount_captured: None, + minor_amount_captured: None, access_token: None, session_token: None, reference_id: None, @@ -159,6 +160,7 @@ fn construct_refund_router_data() -> types::RefundsRouterData { address: PaymentAddress::default(), connector_meta_data: None, amount_captured: None, + minor_amount_captured: None, access_token: None, session_token: None, reference_id: None, diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs index 62177aad028..c1cfda31e1c 100644 --- a/crates/router/tests/connectors/utils.rs +++ b/crates/router/tests/connectors/utils.rs @@ -529,6 +529,7 @@ pub trait ConnectorActions: Connector { .clone() .and_then(|a| a.connector_meta_data.map(Secret::new)), amount_captured: None, + minor_amount_captured: None, access_token: info.clone().and_then(|a| a.access_token), session_token: None, reference_id: None, From 2867fb6315cb83c3570956e6aacde54632e0af88 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Thu, 30 May 2024 12:06:46 +0000 Subject: [PATCH 59/82] chore: run formatter --- crates/router/src/connector/stripe/transformers.rs | 11 +++++------ .../src/core/fraud_check/flows/fulfillment_flow.rs | 3 +-- .../src/core/fraud_check/flows/record_return.rs | 2 +- .../router/src/core/fraud_check/flows/sale_flow.rs | 2 +- .../src/core/fraud_check/flows/transaction_flow.rs | 2 +- crates/router/src/core/payments/helpers.rs | 2 +- crates/router/src/core/payments/transformers.rs | 4 +--- crates/router/src/core/utils.rs | 14 +++++--------- 8 files changed, 16 insertions(+), 24 deletions(-) diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 9193657a5a5..34f04b673ef 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -2417,10 +2417,11 @@ impl // statement_descriptor_suffix: item.response.statement_descriptor_suffix.map(|x| x.as_str()), // three_ds_form, response, - amount_captured : item.response.amount_received.map(|amount| amount.get_amount_as_i64()), - minor_amount_captured: item + amount_captured: item .response - .amount_received, + .amount_received + .map(|amount| amount.get_amount_as_i64()), + minor_amount_captured: item.response.amount_received, connector_response: connector_response_data, ..item.data }) @@ -2606,9 +2607,7 @@ impl .response .amount_received .map(|amount| amount.get_amount_as_i64()), - minor_amount_captured : item - .response - .amount_received, + minor_amount_captured: item.response.amount_received, connector_response: connector_response_data, ..item.data }) diff --git a/crates/router/src/core/fraud_check/flows/fulfillment_flow.rs b/crates/router/src/core/fraud_check/flows/fulfillment_flow.rs index 6cfc2cf6897..8a1329d329a 100644 --- a/crates/router/src/core/fraud_check/flows/fulfillment_flow.rs +++ b/crates/router/src/core/fraud_check/flows/fulfillment_flow.rs @@ -75,8 +75,7 @@ pub async fn construct_fulfillment_router_data<'a>( amount_captured: payment_intent .amount_captured .map(|amt| amt.get_amount_as_i64()), - minor_amount_captured: payment_intent - .amount_captured, + minor_amount_captured: payment_intent.amount_captured, payment_method_status: None, request: FraudCheckFulfillmentData { amount: payment_attempt.amount.get_amount_as_i64(), 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 df026cea1eb..a5d537cae7b 100644 --- a/crates/router/src/core/fraud_check/flows/record_return.rs +++ b/crates/router/src/core/fraud_check/flows/record_return.rs @@ -66,7 +66,7 @@ impl ConstructFlowSpecificData( merchant_id: router_data.merchant_id, address: router_data.address, amount_captured: router_data.amount_captured, - minor_amount_captured:router_data.minor_amount_captured, + minor_amount_captured: router_data.minor_amount_captured, auth_type: router_data.auth_type, connector: router_data.connector, connector_auth_type: router_data.connector_auth_type, diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index cc9e2e223b0..0fd06b84aa7 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -160,9 +160,7 @@ where .payment_intent .amount_captured .map(|amt| amt.get_amount_as_i64()), - minor_amount_captured: payment_data - .payment_intent - .amount_captured, + minor_amount_captured: payment_data.payment_intent.amount_captured, access_token: None, session_token: None, reference_id: None, diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index 12fd65c4e61..0e118ec7264 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -321,7 +321,7 @@ pub async fn construct_refund_router_data<'a, F>( .amount_captured .map(|amt| amt.get_amount_as_i64()), payment_method_status: None, - minor_amount_captured : payment_intent.amount_captured, + minor_amount_captured: payment_intent.amount_captured, request: types::RefundsData { refund_id: refund.refund_id.clone(), connector_transaction_id: refund.connector_transaction_id.clone(), @@ -570,8 +570,7 @@ pub async fn construct_accept_dispute_router_data<'a>( amount_captured: payment_intent .amount_captured .map(|amt| amt.get_amount_as_i64()), - minor_amount_captured : payment_intent - .amount_captured, + minor_amount_captured: payment_intent.amount_captured, payment_method_status: None, request: types::AcceptDisputeRequestData { dispute_id: dispute.dispute_id.clone(), @@ -668,8 +667,7 @@ pub async fn construct_submit_evidence_router_data<'a>( amount_captured: payment_intent .amount_captured .map(|amt| amt.get_amount_as_i64()), - minor_amount_captured: payment_intent - .amount_captured, + minor_amount_captured: payment_intent.amount_captured, request: submit_evidence_request_data, response: Err(ErrorResponse::default()), access_token: None, @@ -764,8 +762,7 @@ pub async fn construct_upload_file_router_data<'a>( amount_captured: payment_intent .amount_captured .map(|amt| amt.get_amount_as_i64()), - minor_amount_captured: payment_intent - .amount_captured, + minor_amount_captured: payment_intent.amount_captured, payment_method_status: None, request: types::UploadFileRequestData { file_key, @@ -864,8 +861,7 @@ pub async fn construct_defend_dispute_router_data<'a>( amount_captured: payment_intent .amount_captured .map(|amt| amt.get_amount_as_i64()), - minor_amount_captured: payment_intent - .amount_captured, + minor_amount_captured: payment_intent.amount_captured, payment_method_status: None, request: types::DefendDisputeRequestData { dispute_id: dispute.dispute_id.clone(), From bf9393a4dcbeeb380621352018bb1e43500ca008 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Thu, 30 May 2024 17:50:54 +0530 Subject: [PATCH 60/82] refactor(connector):added amount framework to charged object --- crates/api_models/src/payments.rs | 6 ++++-- openapi/openapi_spec.json | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index c24193ef38b..16bd41eea73 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -487,7 +487,8 @@ pub struct PaymentChargeRequest { pub charge_type: api_enums::PaymentChargeType, /// Platform fees to be collected on the payment - pub fees: i64, + #[schema(value_type = i64, example = 6540)] + pub fees: MinorUnit, /// Identifier for the reseller's account to send the funds to pub transfer_account_id: String, @@ -3504,7 +3505,8 @@ pub struct PaymentChargeResponse { pub charge_type: api_enums::PaymentChargeType, /// Platform fees collected on the payment - pub application_fees: i64, + #[schema(value_type = i64, example = 6540)] + pub application_fees: MinorUnit, /// Identifier for the reseller's account where the funds were transferred pub transfer_account_id: String, diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 024ec7fc174..229b53a2379 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -12626,7 +12626,8 @@ "fees": { "type": "integer", "format": "int64", - "description": "Platform fees to be collected on the payment" + "description": "Platform fees to be collected on the payment", + "example": 6540 }, "transfer_account_id": { "type": "string", @@ -12653,7 +12654,8 @@ "application_fees": { "type": "integer", "format": "int64", - "description": "Platform fees collected on the payment" + "description": "Platform fees collected on the payment", + "example": 6540 }, "transfer_account_id": { "type": "string", From 8efa34e305338a19ad9e887d2e6462feab81728a Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Thu, 30 May 2024 18:05:56 +0530 Subject: [PATCH 61/82] refactor(connector): resolved pr comments --- crates/router/src/connector/stripe/transformers.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 34f04b673ef..978c30002de 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -260,7 +260,7 @@ pub struct StripeCustomerResponse { #[derive(Debug, Eq, PartialEq, Serialize)] pub struct ChargesRequest { - pub amount: String, + pub amount: MinorUnit, pub currency: String, pub customer: Secret, pub source: Secret, @@ -3308,7 +3308,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for ChargesRequest { order_id, )); Ok(Self { - amount: value.request.amount.to_string(), + amount: value.request.minor_amount, currency: value.request.currency.to_string(), customer: Secret::new(value.get_connector_customer_id()?), source: Secret::new(value.get_preprocessing_id()?), From 7c3467019014db68a90e7642ff36d700c4d63389 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 31 May 2024 14:01:55 +0530 Subject: [PATCH 62/82] refactor(connector): fixed compile issue --- crates/router/src/connector/bluesnap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/src/connector/bluesnap.rs b/crates/router/src/connector/bluesnap.rs index 86c19779dc3..973fb1df61d 100644 --- a/crates/router/src/connector/bluesnap.rs +++ b/crates/router/src/connector/bluesnap.rs @@ -1144,7 +1144,6 @@ impl api::IncomingWebhook for Bluesnap { let dispute_details: bluesnap::BluesnapDisputeWebhookBody = serde_urlencoded::from_bytes(request.body) .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?; - let dispute_amount = Ok(api::disputes::DisputePayload { amount: connector_utils::to_currency_lower_unit( dispute_details.invoice_charge_amount.abs().to_string(), @@ -1160,6 +1159,7 @@ impl api::IncomingWebhook for Bluesnap { created_at: None, updated_at: None, }) + } fn get_webhook_resource_object( From fcccf0b153d0643430fa178b45db1c6ffa6dabd9 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 08:33:05 +0000 Subject: [PATCH 63/82] chore: run formatter --- crates/router/src/connector/bluesnap.rs | 31 ++++++------------- .../src/connector/bluesnap/transformers.rs | 6 ++-- crates/router/src/types/api/disputes.rs | 1 - 3 files changed, 11 insertions(+), 27 deletions(-) diff --git a/crates/router/src/connector/bluesnap.rs b/crates/router/src/connector/bluesnap.rs index 973fb1df61d..b7da3d0da18 100644 --- a/crates/router/src/connector/bluesnap.rs +++ b/crates/router/src/connector/bluesnap.rs @@ -1,12 +1,11 @@ pub mod transformers; - use base64::Engine; use common_utils::{ crypto, ext_traits::{StringExt, ValueExt}, request::RequestContent, - types::{StringMajorUnitForConnector,StringMajorUnit, AmountConvertor} + types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector}, }; use diesel_models::enums; use error_stack::{report, ResultExt}; @@ -49,7 +48,7 @@ pub struct Bluesnap { impl Bluesnap { pub fn new() -> &'static Self { &Self { - amount_converter: &StringMajorUnitForConnector + amount_converter: &StringMajorUnitForConnector, } } } @@ -477,12 +476,10 @@ impl ConnectorIntegration { let connector_req = @@ -812,10 +806,7 @@ impl req.request.minor_amount, req.request.currency, )?; - let connector_router_data = bluesnap::BluesnapRouterData::try_from(( - amount, - req, - ))?; + let connector_router_data = bluesnap::BluesnapRouterData::try_from((amount, req))?; let connector_req = bluesnap::BluesnapCompletePaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -912,10 +903,7 @@ impl ConnectorIntegration { impl TryFrom<(StringMajorUnit, T)> for BluesnapRouterData { type Error = error_stack::Report; - fn try_from( - (amount, item): (StringMajorUnit, T), - ) -> Result { + fn try_from((amount, item): (StringMajorUnit, T)) -> Result { Ok(Self { amount, router_data: item, diff --git a/crates/router/src/types/api/disputes.rs b/crates/router/src/types/api/disputes.rs index ef279ff7392..a8107fe4c9d 100644 --- a/crates/router/src/types/api/disputes.rs +++ b/crates/router/src/types/api/disputes.rs @@ -1,7 +1,6 @@ use masking::{Deserialize, Serialize}; use time::PrimitiveDateTime; - use crate::{services, types}; #[derive(Default, Debug, Deserialize, Serialize)] From c28694074e147b941a1a57a60c9640a0ee667780 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 31 May 2024 14:31:08 +0530 Subject: [PATCH 64/82] refactor(connector): added amount framework to payme connector --- .../src/router_request_types.rs | 3 +++ crates/router/src/connector/payme.rs | 27 +++++-------------- .../src/connector/payme/transformers.rs | 16 +++++------ .../router/src/core/payments/transformers.rs | 1 + 4 files changed, 19 insertions(+), 28 deletions(-) diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index 0d446be9eb3..bf3cfca8739 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -358,6 +358,9 @@ pub struct PaymentsCancelData { pub browser_info: Option, pub metadata: Option, // This metadata is used to store the metadata shared during the payment intent request. + + // minor amount data for amount framework + pub minor_amount: Option } #[derive(Debug, Default, Clone)] diff --git a/crates/router/src/connector/payme.rs b/crates/router/src/connector/payme.rs index 397715d102d..c293463ef08 100644 --- a/crates/router/src/connector/payme.rs +++ b/crates/router/src/connector/payme.rs @@ -287,10 +287,9 @@ impl req: &types::PaymentsPreProcessingRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let amount = req.request.get_amount()?; - let currency = req.request.get_currency()?; + let amount = req.request.get_minor_amount()?; let connector_router_data = - payme::PaymeRouterData::try_from((&self.get_currency_unit(), currency, amount, req))?; + payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::GenerateSaleRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -537,9 +536,7 @@ impl ConnectorIntegration CustomResult { let connector_router_data = payme::PaymeRouterData::try_from(( - &self.get_currency_unit(), - req.request.currency, - req.request.amount, + req.request.minor_amount, req, ))?; let connector_req = payme::PaymePaymentRequest::try_from(&connector_router_data)?; @@ -725,9 +722,7 @@ impl ConnectorIntegration CustomResult { let connector_router_data = payme::PaymeRouterData::try_from(( - &self.get_currency_unit(), - req.request.currency, - req.request.amount_to_capture, + req.request.minor_amount_to_capture, req, ))?; let connector_req = payme::PaymentCaptureRequest::try_from(&connector_router_data)?; @@ -824,18 +819,12 @@ impl ConnectorIntegration CustomResult { let amount = req .request - .amount + .minor_amount .ok_or(errors::ConnectorError::MissingRequiredField { field_name: "amount", })?; - let currency = - req.request - .currency - .ok_or(errors::ConnectorError::MissingRequiredField { - field_name: "currency", - })?; let connector_router_data = - payme::PaymeRouterData::try_from((&self.get_currency_unit(), currency, amount, req))?; + payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::PaymeVoidRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -923,9 +912,7 @@ impl ConnectorIntegration CustomResult { let connector_router_data = payme::PaymeRouterData::try_from(( - &self.get_currency_unit(), - req.request.currency, - req.request.refund_amount, + req.request.minor_refund_amount, req, ))?; let connector_req = payme::PaymeRefundRequest::try_from(&connector_router_data)?; diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index 634c0a17c7a..56dc01548ce 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use api_models::enums::{AuthenticationType, PaymentMethod}; -use common_utils::pii; +use common_utils::{pii, types::MinorUnit}; use error_stack::ResultExt; use masking::{ExposeInterface, Secret}; use serde::{Deserialize, Serialize}; @@ -28,14 +28,14 @@ const LANGUAGE: &str = "en"; #[derive(Debug, Serialize)] pub struct PaymeRouterData { - pub amount: i64, + pub amount: MinorUnit, pub router_data: T, } -impl TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for PaymeRouterData { +impl TryFrom<(MinorUnit, T)> for PaymeRouterData { type Error = error_stack::Report; fn try_from( - (_currency_unit, _currency, amount, item): (&api::CurrencyUnit, enums::Currency, i64, T), + (amount, item): (MinorUnit, T), ) -> Result { Ok(Self { amount, @@ -57,7 +57,7 @@ pub struct PayRequest { #[derive(Debug, Serialize)] pub struct MandateRequest { currency: enums::Currency, - sale_price: i64, + sale_price: MinorUnit, transaction_id: String, product_name: String, sale_return_url: String, @@ -118,7 +118,7 @@ pub struct CaptureBuyerResponse { pub struct GenerateSaleRequest { currency: enums::Currency, sale_type: SaleType, - sale_price: i64, + sale_price: MinorUnit, transaction_id: String, product_name: String, sale_return_url: String, @@ -902,7 +902,7 @@ impl #[derive(Debug, Serialize)] pub struct PaymentCaptureRequest { payme_sale_id: String, - sale_price: i64, + sale_price: MinorUnit, } impl TryFrom<&PaymeRouterData<&types::PaymentsCaptureRouterData>> for PaymentCaptureRequest { @@ -927,7 +927,7 @@ impl TryFrom<&PaymeRouterData<&types::PaymentsCaptureRouterData>> for PaymentCap // Type definition for RefundRequest #[derive(Debug, Serialize)] pub struct PaymeRefundRequest { - sale_refund_amount: i64, + sale_refund_amount: MinorUnit, payme_sale_id: String, seller_payme_id: Secret, language: String, diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 0fd06b84aa7..387525489a7 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -1470,6 +1470,7 @@ impl TryFrom> for types::PaymentsCancelDa let amount = MinorUnit::from(payment_data.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), currency: Some(payment_data.currency), connector_transaction_id: connector .connector From 2a8e6289809c0c021d57541750a1ef77b75ba0ff Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 09:02:58 +0000 Subject: [PATCH 65/82] chore: run formatter --- .../src/router_request_types.rs | 2 +- crates/router/src/connector/payme.rs | 36 ++++++++----------- .../src/connector/payme/transformers.rs | 4 +-- 3 files changed, 16 insertions(+), 26 deletions(-) diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index bf3cfca8739..0b3393570c5 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -360,7 +360,7 @@ pub struct PaymentsCancelData { // This metadata is used to store the metadata shared during the payment intent request. // minor amount data for amount framework - pub minor_amount: Option + pub minor_amount: Option, } #[derive(Debug, Default, Clone)] diff --git a/crates/router/src/connector/payme.rs b/crates/router/src/connector/payme.rs index c293463ef08..c9d88694574 100644 --- a/crates/router/src/connector/payme.rs +++ b/crates/router/src/connector/payme.rs @@ -288,8 +288,7 @@ impl _connectors: &settings::Connectors, ) -> CustomResult { let amount = req.request.get_minor_amount()?; - let connector_router_data = - payme::PaymeRouterData::try_from((amount, req))?; + let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::GenerateSaleRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -535,10 +534,8 @@ impl ConnectorIntegration CustomResult { - let connector_router_data = payme::PaymeRouterData::try_from(( - req.request.minor_amount, - req, - ))?; + let connector_router_data = + payme::PaymeRouterData::try_from((req.request.minor_amount, req))?; let connector_req = payme::PaymePaymentRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -721,10 +718,8 @@ impl ConnectorIntegration CustomResult { - let connector_router_data = payme::PaymeRouterData::try_from(( - req.request.minor_amount_to_capture, - req, - ))?; + let connector_router_data = + payme::PaymeRouterData::try_from((req.request.minor_amount_to_capture, req))?; let connector_req = payme::PaymentCaptureRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -817,14 +812,13 @@ impl ConnectorIntegration CustomResult { - let amount = req - .request - .minor_amount - .ok_or(errors::ConnectorError::MissingRequiredField { - field_name: "amount", - })?; - let connector_router_data = - payme::PaymeRouterData::try_from((amount, req))?; + let amount = + req.request + .minor_amount + .ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "amount", + })?; + let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::PaymeVoidRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -911,10 +905,8 @@ impl ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = payme::PaymeRouterData::try_from(( - req.request.minor_refund_amount, - req, - ))?; + let connector_router_data = + payme::PaymeRouterData::try_from((req.request.minor_refund_amount, req))?; let connector_req = payme::PaymeRefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index 56dc01548ce..13c00924d80 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -34,9 +34,7 @@ pub struct PaymeRouterData { impl TryFrom<(MinorUnit, T)> for PaymeRouterData { type Error = error_stack::Report; - fn try_from( - (amount, item): (MinorUnit, T), - ) -> Result { + fn try_from((amount, item): (MinorUnit, T)) -> Result { Ok(Self { amount, router_data: item, From e9b59e704a5d68b341c7c256de0ad3accd05efd0 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 31 May 2024 14:49:33 +0530 Subject: [PATCH 66/82] refactor(connector): fixed clippy issue --- crates/router/tests/connectors/bluesnap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/tests/connectors/bluesnap.rs b/crates/router/tests/connectors/bluesnap.rs index 88b6fbec246..b8822ebcf97 100644 --- a/crates/router/tests/connectors/bluesnap.rs +++ b/crates/router/tests/connectors/bluesnap.rs @@ -18,7 +18,7 @@ impl utils::Connector for BluesnapTest { fn get_data(&self) -> types::api::ConnectorData { use router::connector::Bluesnap; types::api::ConnectorData { - connector: Box::new(&Bluesnap), + connector: Box::new(Bluesnap::new()), connector_name: types::Connector::Bluesnap, get_token: types::api::GetToken::Connector, merchant_connector_id: None, From b63687d6cec7ba6feb92168851b942685fa9c3af Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 31 May 2024 16:59:48 +0530 Subject: [PATCH 67/82] refactor(connector): added uniformity in stripe for amount framework --- crates/common_utils/src/types.rs | 25 +++++++++++ crates/router/src/connector/stripe.rs | 43 ++++++++++++++++--- .../src/connector/stripe/transformers.rs | 41 ++++++++++-------- crates/router/src/types/api.rs | 2 +- crates/router/tests/connectors/stripe.rs | 2 +- 5 files changed, 86 insertions(+), 27 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 7ab78ce3257..a1d204f5231 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -317,6 +317,31 @@ impl AmountConvertor for FloatMajorUnitForConnector { amount.to_minor_unit_as_i64(currency) } } + +/// Connector required amount type + +#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] +pub struct MinorUnitForConnector; + +impl AmountConvertor for MinorUnitForConnector { + type Output = MinorUnit; + fn convert( + &self, + amount: MinorUnit, + _currency: enums::Currency, + ) -> Result> { + Ok(amount) + } + fn convert_back( + &self, + amount: MinorUnit, + _currency: enums::Currency, + ) -> Result> { + Ok(amount) + } +} + + /// This Unit struct represents MinorUnit in which core amount works #[derive( Default, diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs index 171cde7bc9d..aedc85c7dad 100644 --- a/crates/router/src/connector/stripe.rs +++ b/crates/router/src/connector/stripe.rs @@ -2,7 +2,7 @@ pub mod transformers; use std::{collections::HashMap, ops::Deref}; -use common_utils::request::RequestContent; +use common_utils::{request::RequestContent, types::{AmountConvertor, MinorUnitForConnector, MinorUnit}}; use diesel_models::enums; use error_stack::ResultExt; use masking::PeekInterface; @@ -27,6 +27,7 @@ use crate::{ request::{self, Mask}, ConnectorValidation, }, + connector::utils::PaymentsPreProcessingData, types::{ self, api::{self, ConnectorCommon, ConnectorCommonExt}, @@ -35,8 +36,19 @@ use crate::{ utils::{crypto, ByteSliceExt, BytesExt, OptionExt}, }; -#[derive(Debug, Clone)] -pub struct Stripe; +#[derive(Clone)] +pub struct Stripe { + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Stripe { + pub const fn new() -> &'static Self { + &Self { + amount_converter: &MinorUnitForConnector, + } + } +} + impl ConnectorCommonExt for Stripe where @@ -223,7 +235,14 @@ impl req: &types::PaymentsPreProcessingRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_req = stripe::StripeCreditTransferSourceRequest::try_from(req)?; + let req_currency = req.request.get_currency()?; + let req_amount = req.request.get_minor_amount()?; + let amount = connector_utils::convert_amount( + self.amount_converter, + req_amount, + req_currency, + )?; + let connector_req = stripe::StripeCreditTransferSourceRequest::try_from((req,amount, req_currency))?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } @@ -618,7 +637,12 @@ impl req: &types::PaymentsCaptureRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_req = stripe::CaptureRequest::try_from(req)?; + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount_to_capture, + req.request.currency, + )?; + let connector_req = stripe::CaptureRequest::try_from(amount)?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } @@ -931,12 +955,17 @@ impl req: &types::PaymentsAuthorizeRouterData, _connectors: &settings::Connectors, ) -> CustomResult { + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount, + req.request.currency, + )?; match &req.request.payment_method_data { domain::PaymentMethodData::BankTransfer(bank_transfer_data) => { - stripe::get_bank_transfer_request_data(req, bank_transfer_data.deref()) + stripe::get_bank_transfer_request_data(req, bank_transfer_data.deref(), amount) } _ => { - let connector_req = stripe::PaymentIntentRequest::try_from(req)?; + let connector_req = stripe::PaymentIntentRequest::try_from((req, amount))?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 978c30002de..446a218ea12 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use time::PrimitiveDateTime; use url::Url; - +use diesel_models::enums as storage_enums; #[cfg(feature = "payouts")] pub mod connect; #[cfg(feature = "payouts")] @@ -1569,9 +1569,11 @@ impl TryFrom<&domain::GooglePayWalletData> for StripePaymentMethodData { } } -impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest { +impl TryFrom<(&types::PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest { type Error = error_stack::Report; - fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result { + fn try_from(data: (&types::PaymentsAuthorizeRouterData, MinorUnit)) -> Result { + let item = data.0; + let amount = data.1; let order_id = item.connector_request_reference_id.clone(); let shipping_address = match item.get_optional_shipping() { @@ -1860,7 +1862,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentIntentRequest { }; Ok(Self { - amount: item.request.minor_amount, //hopefully we don't loose some cents here + amount,//hopefully we don't loose some cents here currency: item.request.currency.to_string(), //we need to copy the value and not transfer ownership statement_descriptor_suffix: item.request.statement_descriptor_suffix.clone(), statement_descriptor: item.request.statement_descriptor.clone(), @@ -3182,21 +3184,21 @@ pub struct CaptureRequest { amount_to_capture: Option, } -impl TryFrom<&types::PaymentsCaptureRouterData> for CaptureRequest { +impl TryFrom for CaptureRequest { type Error = error_stack::Report; - fn try_from(item: &types::PaymentsCaptureRouterData) -> Result { + fn try_from(capture_amount: MinorUnit) -> Result { Ok(Self { - amount_to_capture: Some(item.request.minor_amount_to_capture), + amount_to_capture: Some(capture_amount), }) } } -impl TryFrom<&types::PaymentsPreProcessingRouterData> for StripeCreditTransferSourceRequest { +impl TryFrom<(&types::PaymentsPreProcessingRouterData, MinorUnit, storage_enums::Currency)> for StripeCreditTransferSourceRequest { type Error = error_stack::Report; - fn try_from(item: &types::PaymentsPreProcessingRouterData) -> Result { - let currency = item.request.get_currency()?; - let amount = item.request.get_minor_amount()?; - + fn try_from(data: (&types::PaymentsPreProcessingRouterData, MinorUnit, storage_enums::Currency)) -> Result { + let item = data.0; + let currency = data.2; + let amount = data.1; match &item.request.payment_method_data { Some(domain::PaymentMethodData::BankTransfer(bank_transfer_data)) => { match **bank_transfer_data { @@ -3297,18 +3299,20 @@ impl } } -impl TryFrom<&types::PaymentsAuthorizeRouterData> for ChargesRequest { +impl TryFrom<(&types::PaymentsAuthorizeRouterData, MinorUnit)> for ChargesRequest { type Error = error_stack::Report; - fn try_from(value: &types::PaymentsAuthorizeRouterData) -> Result { - { + fn try_from(data: (&types::PaymentsAuthorizeRouterData, MinorUnit)) -> Result { + { + let value = data.0; + let amount = data.1; let order_id = value.connector_request_reference_id.clone(); let meta_data = Some(get_transaction_metadata( value.request.metadata.clone(), order_id, )); Ok(Self { - amount: value.request.minor_amount, + amount, currency: value.request.currency.to_string(), customer: Secret::new(value.get_connector_customer_id()?), source: Secret::new(value.get_preprocessing_id()?), @@ -3718,15 +3722,16 @@ pub struct StripeGpayToken { pub fn get_bank_transfer_request_data( req: &types::PaymentsAuthorizeRouterData, bank_transfer_data: &domain::BankTransferData, + amount: MinorUnit ) -> CustomResult { match bank_transfer_data { domain::BankTransferData::AchBankTransfer { .. } | domain::BankTransferData::MultibancoBankTransfer { .. } => { - let req = ChargesRequest::try_from(req)?; + let req = ChargesRequest::try_from((req, amount))?; Ok(RequestContent::FormUrlEncoded(Box::new(req))) } _ => { - let req = PaymentIntentRequest::try_from(req)?; + let req = PaymentIntentRequest::try_from((req, amount))?; Ok(RequestContent::FormUrlEncoded(Box::new(req))) } } diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index c427f60cd1f..1149ad00502 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -371,7 +371,7 @@ impl ConnectorData { enums::Connector::Shift4 => Ok(Box::new(&connector::Shift4)), enums::Connector::Square => Ok(Box::new(&connector::Square)), enums::Connector::Stax => Ok(Box::new(&connector::Stax)), - enums::Connector::Stripe => Ok(Box::new(&connector::Stripe)), + enums::Connector::Stripe => Ok(Box::new(connector::Stripe::new())), enums::Connector::Wise => Ok(Box::new(&connector::Wise)), enums::Connector::Worldline => Ok(Box::new(&connector::Worldline)), enums::Connector::Worldpay => Ok(Box::new(&connector::Worldpay)), diff --git a/crates/router/tests/connectors/stripe.rs b/crates/router/tests/connectors/stripe.rs index 2d6b3e0cfd3..012f3a8ca43 100644 --- a/crates/router/tests/connectors/stripe.rs +++ b/crates/router/tests/connectors/stripe.rs @@ -14,7 +14,7 @@ impl utils::Connector for Stripe { fn get_data(&self) -> types::api::ConnectorData { use router::connector::Stripe; types::api::ConnectorData { - connector: Box::new(&Stripe), + connector: Box::new(Stripe::new()), connector_name: types::Connector::Stripe, get_token: types::api::GetToken::Connector, merchant_connector_id: None, From c5ff47f265bb650043b94d65d8347ab1fad4f732 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 11:30:28 +0000 Subject: [PATCH 68/82] chore: run formatter --- crates/common_utils/src/types.rs | 1 - crates/router/src/connector/stripe.rs | 18 +++++------ .../src/connector/stripe/transformers.rs | 32 ++++++++++++++----- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index a1d204f5231..8e15997de39 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -341,7 +341,6 @@ impl AmountConvertor for MinorUnitForConnector { } } - /// This Unit struct represents MinorUnit in which core amount works #[derive( Default, diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs index aedc85c7dad..0874c3b7c54 100644 --- a/crates/router/src/connector/stripe.rs +++ b/crates/router/src/connector/stripe.rs @@ -2,7 +2,10 @@ pub mod transformers; use std::{collections::HashMap, ops::Deref}; -use common_utils::{request::RequestContent, types::{AmountConvertor, MinorUnitForConnector, MinorUnit}}; +use common_utils::{ + request::RequestContent, + types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, +}; use diesel_models::enums; use error_stack::ResultExt; use masking::PeekInterface; @@ -15,6 +18,7 @@ use super::utils::{self as connector_utils, PaymentMethodDataType, RefundsReques use super::utils::{PayoutsData, RouterData}; use crate::{ configs::settings, + connector::utils::PaymentsPreProcessingData, consts, core::{ errors::{self, CustomResult}, @@ -27,7 +31,6 @@ use crate::{ request::{self, Mask}, ConnectorValidation, }, - connector::utils::PaymentsPreProcessingData, types::{ self, api::{self, ConnectorCommon, ConnectorCommonExt}, @@ -49,7 +52,6 @@ impl Stripe { } } - impl ConnectorCommonExt for Stripe where Self: services::ConnectorIntegration, @@ -237,12 +239,10 @@ impl ) -> CustomResult { let req_currency = req.request.get_currency()?; let req_amount = req.request.get_minor_amount()?; - let amount = connector_utils::convert_amount( - self.amount_converter, - req_amount, - req_currency, - )?; - let connector_req = stripe::StripeCreditTransferSourceRequest::try_from((req,amount, req_currency))?; + let amount = + connector_utils::convert_amount(self.amount_converter, req_amount, req_currency)?; + let connector_req = + stripe::StripeCreditTransferSourceRequest::try_from((req, amount, req_currency))?; Ok(RequestContent::FormUrlEncoded(Box::new(connector_req))) } diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 446a218ea12..08f36954989 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -8,6 +8,7 @@ use common_utils::{ request::RequestContent, types::MinorUnit, }; +use diesel_models::enums as storage_enums; use error_stack::ResultExt; use hyperswitch_domain_models::mandates::AcceptanceType; use masking::{ExposeInterface, ExposeOptionInterface, PeekInterface, Secret}; @@ -15,7 +16,6 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use time::PrimitiveDateTime; use url::Url; -use diesel_models::enums as storage_enums; #[cfg(feature = "payouts")] pub mod connect; #[cfg(feature = "payouts")] @@ -1571,7 +1571,9 @@ impl TryFrom<&domain::GooglePayWalletData> for StripePaymentMethodData { impl TryFrom<(&types::PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntentRequest { type Error = error_stack::Report; - fn try_from(data: (&types::PaymentsAuthorizeRouterData, MinorUnit)) -> Result { + fn try_from( + data: (&types::PaymentsAuthorizeRouterData, MinorUnit), + ) -> Result { let item = data.0; let amount = data.1; let order_id = item.connector_request_reference_id.clone(); @@ -1862,7 +1864,7 @@ impl TryFrom<(&types::PaymentsAuthorizeRouterData, MinorUnit)> for PaymentIntent }; Ok(Self { - amount,//hopefully we don't loose some cents here + amount, //hopefully we don't loose some cents here currency: item.request.currency.to_string(), //we need to copy the value and not transfer ownership statement_descriptor_suffix: item.request.statement_descriptor_suffix.clone(), statement_descriptor: item.request.statement_descriptor.clone(), @@ -3193,9 +3195,21 @@ impl TryFrom for CaptureRequest { } } -impl TryFrom<(&types::PaymentsPreProcessingRouterData, MinorUnit, storage_enums::Currency)> for StripeCreditTransferSourceRequest { +impl + TryFrom<( + &types::PaymentsPreProcessingRouterData, + MinorUnit, + storage_enums::Currency, + )> for StripeCreditTransferSourceRequest +{ type Error = error_stack::Report; - fn try_from(data: (&types::PaymentsPreProcessingRouterData, MinorUnit, storage_enums::Currency)) -> Result { + fn try_from( + data: ( + &types::PaymentsPreProcessingRouterData, + MinorUnit, + storage_enums::Currency, + ), + ) -> Result { let item = data.0; let currency = data.2; let amount = data.1; @@ -3302,8 +3316,10 @@ impl impl TryFrom<(&types::PaymentsAuthorizeRouterData, MinorUnit)> for ChargesRequest { type Error = error_stack::Report; - fn try_from(data: (&types::PaymentsAuthorizeRouterData, MinorUnit)) -> Result { - { + fn try_from( + data: (&types::PaymentsAuthorizeRouterData, MinorUnit), + ) -> Result { + { let value = data.0; let amount = data.1; let order_id = value.connector_request_reference_id.clone(); @@ -3722,7 +3738,7 @@ pub struct StripeGpayToken { pub fn get_bank_transfer_request_data( req: &types::PaymentsAuthorizeRouterData, bank_transfer_data: &domain::BankTransferData, - amount: MinorUnit + amount: MinorUnit, ) -> CustomResult { match bank_transfer_data { domain::BankTransferData::AchBankTransfer { .. } From 3ee29da9bfa5e02213cabc3a455310b1374ee10e Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 31 May 2024 17:26:21 +0530 Subject: [PATCH 69/82] refactor(connector): added convertion uniformity to payme for amount conversion frame work --- crates/router/src/connector/payme.rs | 39 ++++++++++++++----- .../src/connector/payme/transformers.rs | 2 +- crates/router/src/types/api.rs | 2 +- crates/router/tests/connectors/payme.rs | 2 +- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/crates/router/src/connector/payme.rs b/crates/router/src/connector/payme.rs index c9d88694574..768ef7b84bb 100644 --- a/crates/router/src/connector/payme.rs +++ b/crates/router/src/connector/payme.rs @@ -1,9 +1,8 @@ pub mod transformers; -use std::fmt::Debug; use api_models::enums::AuthenticationType; -use common_utils::{crypto, request::RequestContent}; +use common_utils::{crypto, request::RequestContent, types::{AmountConvertor, MinorUnit, MinorUnitForConnector}}; use diesel_models::enums; use error_stack::{Report, ResultExt}; use masking::ExposeInterface; @@ -27,8 +26,18 @@ use crate::{ utils::{handle_json_response_deserialization_failure, BytesExt}, }; -#[derive(Debug, Clone)] -pub struct Payme; +#[derive(Clone)] +pub struct Payme { + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Payme { + pub const fn new() -> &'static Self { + &Self { + amount_converter: &MinorUnitForConnector, + } + } +} impl api::Payment for Payme {} impl api::PaymentSession for Payme {} @@ -287,7 +296,9 @@ impl req: &types::PaymentsPreProcessingRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let amount = req.request.get_minor_amount()?; + let req_amount = req.request.get_minor_amount()?; + let req_currency = req.request.get_currency()?; + let amount = connector_utils::convert_amount(self.amount_converter, req_amount, req_currency)?; let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::GenerateSaleRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -534,8 +545,10 @@ impl ConnectorIntegration CustomResult { + let amount = + connector_utils::convert_amount(self.amount_converter, req.request.minor_amount, req.request.currency)?; let connector_router_data = - payme::PaymeRouterData::try_from((req.request.minor_amount, req))?; + payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::PaymePaymentRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -718,8 +731,10 @@ impl ConnectorIntegration CustomResult { + let amount = + connector_utils::convert_amount(self.amount_converter, req.request.minor_amount_to_capture, req.request.currency)?; let connector_router_data = - payme::PaymeRouterData::try_from((req.request.minor_amount_to_capture, req))?; + payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::PaymentCaptureRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -812,12 +827,16 @@ impl ConnectorIntegration CustomResult { - let amount = + let req_amount = req.request .minor_amount .ok_or(errors::ConnectorError::MissingRequiredField { field_name: "amount", })?; + let req_currency = req.request.currency.ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "amount", + })?; + let amount = connector_utils::convert_amount(self.amount_converter, req_amount, req_currency)?; let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::PaymeVoidRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -905,8 +924,10 @@ impl ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { + let amount = + connector_utils::convert_amount(self.amount_converter, req.request.minor_refund_amount, req.request.currency)?; let connector_router_data = - payme::PaymeRouterData::try_from((req.request.minor_refund_amount, req))?; + payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::PaymeRefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index 13c00924d80..0f94b58e728 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -908,7 +908,7 @@ impl TryFrom<&PaymeRouterData<&types::PaymentsCaptureRouterData>> for PaymentCap fn try_from( item: &PaymeRouterData<&types::PaymentsCaptureRouterData>, ) -> Result { - if item.router_data.request.amount_to_capture != item.router_data.request.payment_amount { + if item.router_data.request.minor_amount_to_capture != item.router_data.request.minor_payment_amount { Err(errors::ConnectorError::NotSupported { message: "Partial Capture".to_string(), connector: "Payme", diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index bd3462b3dbb..451d53ebcbf 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -361,7 +361,7 @@ impl ConnectorData { enums::Connector::Nuvei => Ok(Box::new(&connector::Nuvei)), enums::Connector::Opennode => Ok(Box::new(&connector::Opennode)), // "payeezy" => Ok(Box::new(&connector::Payeezy)), As psync and rsync are not supported by this connector, it is added as template code for future usage - enums::Connector::Payme => Ok(Box::new(&connector::Payme)), + enums::Connector::Payme => Ok(Box::new(connector::Payme::new())), enums::Connector::Payone => Ok(Box::new(&connector::Payone)), enums::Connector::Payu => Ok(Box::new(&connector::Payu)), enums::Connector::Placetopay => Ok(Box::new(&connector::Placetopay)), diff --git a/crates/router/tests/connectors/payme.rs b/crates/router/tests/connectors/payme.rs index 6554ddbefbf..cbebe540d0f 100644 --- a/crates/router/tests/connectors/payme.rs +++ b/crates/router/tests/connectors/payme.rs @@ -17,7 +17,7 @@ impl utils::Connector for PaymeTest { fn get_data(&self) -> types::api::ConnectorData { use router::connector::Payme; types::api::ConnectorData { - connector: Box::new(&Payme), + connector: Box::new(Payme::new()), connector_name: types::Connector::Payme, get_token: types::api::GetToken::Connector, merchant_connector_id: None, From 64b2a400cef24fe1a1f7c52d14e06b3333e25bf9 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 12:09:13 +0000 Subject: [PATCH 70/82] chore: run formatter --- crates/router/src/connector/payme.rs | 52 ++++++++++++------- .../src/connector/payme/transformers.rs | 4 +- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/crates/router/src/connector/payme.rs b/crates/router/src/connector/payme.rs index 768ef7b84bb..25a4bd83975 100644 --- a/crates/router/src/connector/payme.rs +++ b/crates/router/src/connector/payme.rs @@ -1,8 +1,11 @@ pub mod transformers; - use api_models::enums::AuthenticationType; -use common_utils::{crypto, request::RequestContent, types::{AmountConvertor, MinorUnit, MinorUnitForConnector}}; +use common_utils::{ + crypto, + request::RequestContent, + types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, +}; use diesel_models::enums; use error_stack::{Report, ResultExt}; use masking::ExposeInterface; @@ -298,7 +301,8 @@ impl ) -> CustomResult { let req_amount = req.request.get_minor_amount()?; let req_currency = req.request.get_currency()?; - let amount = connector_utils::convert_amount(self.amount_converter, req_amount, req_currency)?; + let amount = + connector_utils::convert_amount(self.amount_converter, req_amount, req_currency)?; let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::GenerateSaleRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -545,10 +549,12 @@ impl ConnectorIntegration CustomResult { - let amount = - connector_utils::convert_amount(self.amount_converter, req.request.minor_amount, req.request.currency)?; - let connector_router_data = - payme::PaymeRouterData::try_from((amount, req))?; + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount, + req.request.currency, + )?; + let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::PaymePaymentRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -731,10 +737,12 @@ impl ConnectorIntegration CustomResult { - let amount = - connector_utils::convert_amount(self.amount_converter, req.request.minor_amount_to_capture, req.request.currency)?; - let connector_router_data = - payme::PaymeRouterData::try_from((amount, req))?; + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount_to_capture, + req.request.currency, + )?; + let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::PaymentCaptureRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -833,10 +841,14 @@ impl ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { - let amount = - connector_utils::convert_amount(self.amount_converter, req.request.minor_refund_amount, req.request.currency)?; - let connector_router_data = - payme::PaymeRouterData::try_from((amount, req))?; + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_refund_amount, + req.request.currency, + )?; + let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::PaymeRefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index 0f94b58e728..1606190d986 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -908,7 +908,9 @@ impl TryFrom<&PaymeRouterData<&types::PaymentsCaptureRouterData>> for PaymentCap fn try_from( item: &PaymeRouterData<&types::PaymentsCaptureRouterData>, ) -> Result { - if item.router_data.request.minor_amount_to_capture != item.router_data.request.minor_payment_amount { + if item.router_data.request.minor_amount_to_capture + != item.router_data.request.minor_payment_amount + { Err(errors::ConnectorError::NotSupported { message: "Partial Capture".to_string(), connector: "Payme", From 64cdad811525a3907b20b7d04a820576e48fb494 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Fri, 31 May 2024 19:35:07 +0530 Subject: [PATCH 71/82] refactor(connector): added amount frame work for noon --- crates/router/src/connector/noon.rs | 84 +++++++++++++++-- .../router/src/connector/noon/transformers.rs | 93 +++++-------------- crates/router/src/types/api.rs | 2 +- crates/router/tests/connectors/noon.rs | 2 +- 4 files changed, 103 insertions(+), 78 deletions(-) diff --git a/crates/router/src/connector/noon.rs b/crates/router/src/connector/noon.rs index 23e15b2cfdc..a705796a084 100644 --- a/crates/router/src/connector/noon.rs +++ b/crates/router/src/connector/noon.rs @@ -1,9 +1,8 @@ pub mod transformers; -use std::fmt::Debug; use base64::Engine; -use common_utils::{crypto, ext_traits::ByteSliceExt, request::RequestContent}; +use common_utils::{crypto, ext_traits::ByteSliceExt, request::RequestContent, types::{StringMajorUnitForConnector, StringMajorUnit, AmountConvertor}}; use diesel_models::enums; use error_stack::{Report, ResultExt}; use masking::PeekInterface; @@ -12,11 +11,12 @@ use transformers as noon; use crate::{ configs::settings, - connector::utils::{self as connector_utils, PaymentMethodDataType}, + connector::utils::{self as connector_utils, PaymentMethodDataType, RouterData}, consts, core::{ errors::{self, CustomResult}, payments, + mandate::MandateBehaviour }, events::connector_api_logs::ConnectorEvent, headers, @@ -33,8 +33,18 @@ use crate::{ utils::{self, BytesExt}, }; -#[derive(Debug, Clone)] -pub struct Noon; +#[derive(Clone)] +pub struct Noon{ + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Noon { + pub const fn new() -> &'static Self { + &Self { + amount_converter: &StringMajorUnitForConnector, + } + } +} impl api::Payment for Noon {} impl api::PaymentSession for Noon {} @@ -260,10 +270,58 @@ impl ConnectorIntegration CustomResult { - let connector_req = noon::NoonPaymentsRequest::try_from(req)?; + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount, + req.request.currency, + )?; + + // The description should not have leading or trailing whitespaces, also it should not have double whitespaces and a max 50 chars according to Noon's Docs + let name: String = req + .get_description()? + .trim() + .replace(" ", " ") + .chars() + .take(50) + .collect(); + + let subscription: Option = req.request.get_setup_mandate_details().map(|mandate_data| + { + let max_amount = match &mandate_data.mandate_type { + Some(hyperswitch_domain_models::mandates::MandateDataType::SingleUse(mandate)) + | Some(hyperswitch_domain_models::mandates::MandateDataType::MultiUse(Some(mandate))) => { + connector_utils::convert_amount( + self.amount_converter, + mandate.amount, + mandate.currency, + ) + } + Some(hyperswitch_domain_models::mandates::MandateDataType::MultiUse(None)) => { + Err(errors::ConnectorError::MissingRequiredField { + field_name: "setup_future_usage.mandate_data.mandate_type.multi_use.amount", + }.into()) + }, + None => Err(errors::ConnectorError::MissingRequiredField { + field_name: "setup_future_usage.mandate_data.mandate_type", + }.into() + ), + }?; + Ok::>( + noon::NoonSubscriptionData { + subscription_type: noon::NoonSubscriptionType::Unscheduled, + name: name.clone(), + max_amount, + }, + ) + } + ) + .transpose()?; + + let connector_req = noon::NoonPaymentsRequest::try_from((req, amount, subscription, name))?; Ok(RequestContent::Json(Box::new(connector_req))) } + fn build_request( &self, req: &types::PaymentsAuthorizeRouterData, @@ -416,7 +474,12 @@ impl ConnectorIntegration CustomResult { - let connector_req = noon::NoonPaymentsActionRequest::try_from(req)?; + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount_to_capture, + req.request.currency, + )?; + let connector_req = noon::NoonPaymentsActionRequest::try_from((req, amount))?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -656,7 +719,12 @@ impl ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_req = noon::NoonPaymentsActionRequest::try_from(req)?; + let refund_amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_refund_amount, + req.request.currency, + )?; + let connector_req = noon::NoonPaymentsActionRequest::try_from((req, refund_amount))?; Ok(RequestContent::Json(Box::new(connector_req))) } diff --git a/crates/router/src/connector/noon/transformers.rs b/crates/router/src/connector/noon/transformers.rs index 7534d32a04a..259fcb775a3 100644 --- a/crates/router/src/connector/noon/transformers.rs +++ b/crates/router/src/connector/noon/transformers.rs @@ -1,4 +1,4 @@ -use common_utils::{ext_traits::Encode, pii}; +use common_utils::{ext_traits::Encode, pii, types::StringMajorUnit}; use error_stack::ResultExt; use masking::{ExposeInterface, PeekInterface, Secret}; use serde::{Deserialize, Serialize}; @@ -8,11 +8,12 @@ use crate::{ self as conn_utils, is_refund_failure, CardData, PaymentsAuthorizeRequestData, RevokeMandateRequestData, RouterData, WalletData, }, - core::{errors, mandate::MandateBehaviour}, + core::errors, services, types::{self, api, domain, storage::enums, transformers::ForeignFrom, ErrorResponse}, }; + // These needs to be accepted from SDK, need to be done after 1.0.0 stability as API contract will change const GOOGLEPAY_API_VERSION_MINOR: u8 = 0; const GOOGLEPAY_API_VERSION: u8 = 2; @@ -33,10 +34,10 @@ pub enum NoonSubscriptionType { #[serde(rename_all = "camelCase")] pub struct NoonSubscriptionData { #[serde(rename = "type")] - subscription_type: NoonSubscriptionType, + pub subscription_type: NoonSubscriptionType, //Short description about the subscription. - name: String, - max_amount: String, + pub name: String, + pub max_amount: StringMajorUnit, } #[derive(Debug, Serialize)] @@ -59,7 +60,7 @@ pub struct NoonBilling { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct NoonOrder { - amount: String, + amount: StringMajorUnit, currency: Option, channel: NoonChannels, category: Option, @@ -226,9 +227,13 @@ pub struct NoonPaymentsRequest { billing: Option, } -impl TryFrom<&types::PaymentsAuthorizeRouterData> for NoonPaymentsRequest { +impl TryFrom<(&types::PaymentsAuthorizeRouterData, StringMajorUnit, Option, String)> for NoonPaymentsRequest { type Error = error_stack::Report; - fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result { + fn try_from(data: (&types::PaymentsAuthorizeRouterData, StringMajorUnit , Option, String)) -> Result { + let item = data.0; + let amount = data.1; + let subscription = data.2; + let name = data.3; let (payment_data, currency, category) = match item.request.connector_mandate_id() { Some(mandate_id) => ( NoonPaymentData::Subscription(NoonSubscription { @@ -340,15 +345,6 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for NoonPaymentsRequest { ), }; - // The description should not have leading or trailing whitespaces, also it should not have double whitespaces and a max 50 chars according to Noon's Docs - let name: String = item - .get_description()? - .trim() - .replace(" ", " ") - .chars() - .take(50) - .collect(); - let ip_address = item.request.get_ip_address_as_optional(); let channel = NoonChannels::Web; @@ -368,47 +364,10 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for NoonPaymentsRequest { }, }); - let subscription: Option = item - .request - .get_setup_mandate_details() - .map(|mandate_data| { - let max_amount = match &mandate_data.mandate_type { - Some(hyperswitch_domain_models::mandates::MandateDataType::SingleUse( - mandate, - )) - | Some(hyperswitch_domain_models::mandates::MandateDataType::MultiUse(Some( - mandate, - ))) => conn_utils::to_currency_base_unit( - mandate.amount.get_amount_as_i64(), - mandate.currency, - ), - Some(hyperswitch_domain_models::mandates::MandateDataType::MultiUse(None)) => { - Err(errors::ConnectorError::MissingRequiredField { - field_name: - "setup_future_usage.mandate_data.mandate_type.multi_use.amount", - } - .into()) - } - None => Err(errors::ConnectorError::MissingRequiredField { - field_name: "setup_future_usage.mandate_data.mandate_type", - } - .into()), - }?; - - Ok::>( - NoonSubscriptionData { - subscription_type: NoonSubscriptionType::Unscheduled, - name: name.clone(), - max_amount, - }, - ) - }) - .transpose()?; - let tokenize_c_c = subscription.is_some().then_some(true); let order = NoonOrder { - amount: conn_utils::to_currency_base_unit(item.request.amount, item.request.currency)?, + amount, currency, channel, category, @@ -611,7 +570,7 @@ impl #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct NoonActionTransaction { - amount: String, + amount: StringMajorUnit, currency: diesel_models::enums::Currency, transaction_reference: Option, } @@ -630,17 +589,16 @@ pub struct NoonPaymentsActionRequest { transaction: NoonActionTransaction, } -impl TryFrom<&types::PaymentsCaptureRouterData> for NoonPaymentsActionRequest { +impl TryFrom<(&types::PaymentsCaptureRouterData, StringMajorUnit)> for NoonPaymentsActionRequest { type Error = error_stack::Report; - fn try_from(item: &types::PaymentsCaptureRouterData) -> Result { + fn try_from(data: (&types::PaymentsCaptureRouterData, StringMajorUnit)) -> Result { + let item = data.0; + let amount = data.1; let order = NoonActionOrder { id: item.request.connector_transaction_id.clone(), }; let transaction = NoonActionTransaction { - amount: conn_utils::to_currency_base_unit( - item.request.amount_to_capture, - item.request.currency, - )?, + amount, currency: item.request.currency, transaction_reference: None, }; @@ -691,17 +649,16 @@ impl TryFrom<&types::MandateRevokeRouterData> for NoonRevokeMandateRequest { } } -impl TryFrom<&types::RefundsRouterData> for NoonPaymentsActionRequest { +impl TryFrom<(&types::RefundsRouterData, StringMajorUnit)> for NoonPaymentsActionRequest { type Error = error_stack::Report; - fn try_from(item: &types::RefundsRouterData) -> Result { + fn try_from(data: (&types::RefundsRouterData, StringMajorUnit)) -> Result { + let item = data.0; + let refund_amount = data.1; let order = NoonActionOrder { id: item.request.connector_transaction_id.clone(), }; let transaction = NoonActionTransaction { - amount: conn_utils::to_currency_base_unit( - item.request.refund_amount, - item.request.currency, - )?, + amount: refund_amount, currency: item.request.currency, transaction_reference: Some(item.request.refund_id.clone()), }; diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 451d53ebcbf..4004f9fed16 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -357,7 +357,7 @@ impl ConnectorData { // enums::Connector::Mifinity => Ok(Box::new(&connector::Mifinity)), Added as template code for future usage enums::Connector::Mollie => Ok(Box::new(&connector::Mollie)), enums::Connector::Nmi => Ok(Box::new(connector::Nmi::new())), - enums::Connector::Noon => Ok(Box::new(&connector::Noon)), + enums::Connector::Noon => Ok(Box::new(connector::Noon::new())), enums::Connector::Nuvei => Ok(Box::new(&connector::Nuvei)), enums::Connector::Opennode => Ok(Box::new(&connector::Opennode)), // "payeezy" => Ok(Box::new(&connector::Payeezy)), As psync and rsync are not supported by this connector, it is added as template code for future usage diff --git a/crates/router/tests/connectors/noon.rs b/crates/router/tests/connectors/noon.rs index 47e76d5ec76..b9c2ace307a 100644 --- a/crates/router/tests/connectors/noon.rs +++ b/crates/router/tests/connectors/noon.rs @@ -15,7 +15,7 @@ impl utils::Connector for NoonTest { fn get_data(&self) -> types::api::ConnectorData { use router::connector::Noon; types::api::ConnectorData { - connector: Box::new(&Noon), + connector: Box::new(Noon::new()), connector_name: types::Connector::Noon, get_token: types::api::GetToken::Connector, merchant_connector_id: None, From 5f84aa5fdf0ffc793b66847d23b0f75a76586520 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Fri, 31 May 2024 14:06:52 +0000 Subject: [PATCH 72/82] chore: run formatter --- crates/router/src/connector/noon.rs | 54 +++++++++++-------- .../router/src/connector/noon/transformers.rs | 27 ++++++++-- crates/router/src/connector/payme.rs | 52 +++++++++++------- .../src/connector/payme/transformers.rs | 4 +- 4 files changed, 89 insertions(+), 48 deletions(-) diff --git a/crates/router/src/connector/noon.rs b/crates/router/src/connector/noon.rs index a705796a084..aaf7617af7b 100644 --- a/crates/router/src/connector/noon.rs +++ b/crates/router/src/connector/noon.rs @@ -1,8 +1,12 @@ pub mod transformers; - use base64::Engine; -use common_utils::{crypto, ext_traits::ByteSliceExt, request::RequestContent, types::{StringMajorUnitForConnector, StringMajorUnit, AmountConvertor}}; +use common_utils::{ + crypto, + ext_traits::ByteSliceExt, + request::RequestContent, + types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector}, +}; use diesel_models::enums; use error_stack::{Report, ResultExt}; use masking::PeekInterface; @@ -15,8 +19,8 @@ use crate::{ consts, core::{ errors::{self, CustomResult}, + mandate::MandateBehaviour, payments, - mandate::MandateBehaviour }, events::connector_api_logs::ConnectorEvent, headers, @@ -34,7 +38,7 @@ use crate::{ }; #[derive(Clone)] -pub struct Noon{ +pub struct Noon { amount_converter: &'static (dyn AmountConvertor + Sync), } @@ -285,26 +289,32 @@ impl ConnectorIntegration = req.request.get_setup_mandate_details().map(|mandate_data| - { + let subscription: Option = req + .request + .get_setup_mandate_details() + .map(|mandate_data| { let max_amount = match &mandate_data.mandate_type { - Some(hyperswitch_domain_models::mandates::MandateDataType::SingleUse(mandate)) - | Some(hyperswitch_domain_models::mandates::MandateDataType::MultiUse(Some(mandate))) => { - connector_utils::convert_amount( - self.amount_converter, - mandate.amount, - mandate.currency, - ) - } + Some(hyperswitch_domain_models::mandates::MandateDataType::SingleUse( + mandate, + )) + | Some(hyperswitch_domain_models::mandates::MandateDataType::MultiUse(Some( + mandate, + ))) => connector_utils::convert_amount( + self.amount_converter, + mandate.amount, + mandate.currency, + ), Some(hyperswitch_domain_models::mandates::MandateDataType::MultiUse(None)) => { Err(errors::ConnectorError::MissingRequiredField { - field_name: "setup_future_usage.mandate_data.mandate_type.multi_use.amount", - }.into()) - }, + field_name: + "setup_future_usage.mandate_data.mandate_type.multi_use.amount", + } + .into()) + } None => Err(errors::ConnectorError::MissingRequiredField { field_name: "setup_future_usage.mandate_data.mandate_type", - }.into() - ), + } + .into()), }?; Ok::>( noon::NoonSubscriptionData { @@ -313,15 +323,13 @@ impl ConnectorIntegration, } -impl TryFrom<(&types::PaymentsAuthorizeRouterData, StringMajorUnit, Option, String)> for NoonPaymentsRequest { +impl + TryFrom<( + &types::PaymentsAuthorizeRouterData, + StringMajorUnit, + Option, + String, + )> for NoonPaymentsRequest +{ type Error = error_stack::Report; - fn try_from(data: (&types::PaymentsAuthorizeRouterData, StringMajorUnit , Option, String)) -> Result { + fn try_from( + data: ( + &types::PaymentsAuthorizeRouterData, + StringMajorUnit, + Option, + String, + ), + ) -> Result { let item = data.0; let amount = data.1; let subscription = data.2; @@ -591,7 +604,9 @@ pub struct NoonPaymentsActionRequest { impl TryFrom<(&types::PaymentsCaptureRouterData, StringMajorUnit)> for NoonPaymentsActionRequest { type Error = error_stack::Report; - fn try_from(data: (&types::PaymentsCaptureRouterData, StringMajorUnit)) -> Result { + fn try_from( + data: (&types::PaymentsCaptureRouterData, StringMajorUnit), + ) -> Result { let item = data.0; let amount = data.1; let order = NoonActionOrder { @@ -651,7 +666,9 @@ impl TryFrom<&types::MandateRevokeRouterData> for NoonRevokeMandateRequest { impl TryFrom<(&types::RefundsRouterData, StringMajorUnit)> for NoonPaymentsActionRequest { type Error = error_stack::Report; - fn try_from(data: (&types::RefundsRouterData, StringMajorUnit)) -> Result { + fn try_from( + data: (&types::RefundsRouterData, StringMajorUnit), + ) -> Result { let item = data.0; let refund_amount = data.1; let order = NoonActionOrder { diff --git a/crates/router/src/connector/payme.rs b/crates/router/src/connector/payme.rs index 768ef7b84bb..25a4bd83975 100644 --- a/crates/router/src/connector/payme.rs +++ b/crates/router/src/connector/payme.rs @@ -1,8 +1,11 @@ pub mod transformers; - use api_models::enums::AuthenticationType; -use common_utils::{crypto, request::RequestContent, types::{AmountConvertor, MinorUnit, MinorUnitForConnector}}; +use common_utils::{ + crypto, + request::RequestContent, + types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, +}; use diesel_models::enums; use error_stack::{Report, ResultExt}; use masking::ExposeInterface; @@ -298,7 +301,8 @@ impl ) -> CustomResult { let req_amount = req.request.get_minor_amount()?; let req_currency = req.request.get_currency()?; - let amount = connector_utils::convert_amount(self.amount_converter, req_amount, req_currency)?; + let amount = + connector_utils::convert_amount(self.amount_converter, req_amount, req_currency)?; let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::GenerateSaleRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -545,10 +549,12 @@ impl ConnectorIntegration CustomResult { - let amount = - connector_utils::convert_amount(self.amount_converter, req.request.minor_amount, req.request.currency)?; - let connector_router_data = - payme::PaymeRouterData::try_from((amount, req))?; + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount, + req.request.currency, + )?; + let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::PaymePaymentRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -731,10 +737,12 @@ impl ConnectorIntegration CustomResult { - let amount = - connector_utils::convert_amount(self.amount_converter, req.request.minor_amount_to_capture, req.request.currency)?; - let connector_router_data = - payme::PaymeRouterData::try_from((amount, req))?; + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount_to_capture, + req.request.currency, + )?; + let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::PaymentCaptureRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -833,10 +841,14 @@ impl ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { - let amount = - connector_utils::convert_amount(self.amount_converter, req.request.minor_refund_amount, req.request.currency)?; - let connector_router_data = - payme::PaymeRouterData::try_from((amount, req))?; + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_refund_amount, + req.request.currency, + )?; + let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; let connector_req = payme::PaymeRefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index 0f94b58e728..1606190d986 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -908,7 +908,9 @@ impl TryFrom<&PaymeRouterData<&types::PaymentsCaptureRouterData>> for PaymentCap fn try_from( item: &PaymeRouterData<&types::PaymentsCaptureRouterData>, ) -> Result { - if item.router_data.request.minor_amount_to_capture != item.router_data.request.minor_payment_amount { + if item.router_data.request.minor_amount_to_capture + != item.router_data.request.minor_payment_amount + { Err(errors::ConnectorError::NotSupported { message: "Partial Capture".to_string(), connector: "Payme", From 3462c592149215bfa4ff9bfae59d62cc178962a3 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 3 Jun 2024 12:35:02 +0530 Subject: [PATCH 73/82] Refactor(connector): added amount framework for trustpay --- crates/router/src/connector/trustpay.rs | 48 ++++++++++++++----- .../src/connector/trustpay/transformers.rs | 26 +++++----- crates/router/src/types/api.rs | 2 +- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/crates/router/src/connector/trustpay.rs b/crates/router/src/connector/trustpay.rs index 1f9e77de9cd..02ac113a35c 100644 --- a/crates/router/src/connector/trustpay.rs +++ b/crates/router/src/connector/trustpay.rs @@ -5,13 +5,14 @@ use std::fmt::Debug; use base64::Engine; use common_utils::{ crypto, errors::ReportSwitchExt, ext_traits::ByteSliceExt, request::RequestContent, + types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector} }; use error_stack::{Report, ResultExt}; use masking::PeekInterface; use transformers as trustpay; use super::utils::{ - collect_and_sort_values_by_removing_signature, get_error_code_error_message_based_on_priority, + self as connector_utils, collect_and_sort_values_by_removing_signature, get_error_code_error_message_based_on_priority, ConnectorErrorType, ConnectorErrorTypeMapping, PaymentsPreProcessingData, }; use crate::{ @@ -36,8 +37,18 @@ use crate::{ utils::{self, BytesExt}, }; -#[derive(Debug, Clone)] -pub struct Trustpay; +#[derive(Clone)] +pub struct Trustpay { + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Trustpay { + pub fn new() -> &'static Self { + &Self { + amount_converter: &StringMajorUnitForConnector, + } + } +} impl ConnectorCommonExt for Trustpay where @@ -462,11 +473,16 @@ impl req: &types::PaymentsPreProcessingRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let currency = req.request.get_currency()?; - let amount = req.request.get_amount()?; + let req_currency = req.request.get_currency()?; + let req_amount = req.request.get_minor_amount()?; + + let amount = connector_utils::convert_amount( + self.amount_converter, + req_amount, + req_currency, + )?; + let connector_router_data = trustpay::TrustpayRouterData::try_from(( - &self.get_currency_unit(), - currency, amount, req, ))?; @@ -576,10 +592,12 @@ impl ConnectorIntegration CustomResult { - let amount = req.request.amount; - let connector_router_data = trustpay::TrustpayRouterData::try_from(( - &self.get_currency_unit(), + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_amount, req.request.currency, + )?; + let connector_router_data = trustpay::TrustpayRouterData::try_from(( amount, req, ))?; @@ -686,10 +704,14 @@ impl ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { - let connector_router_data = trustpay::TrustpayRouterData::try_from(( - &self.get_currency_unit(), + let amount = connector_utils::convert_amount( + self.amount_converter, + req.request.minor_refund_amount, req.request.currency, - req.request.refund_amount, + )?; + + let connector_router_data = trustpay::TrustpayRouterData::try_from(( + amount, req, ))?; let connector_req = trustpay::TrustpayRefundRequest::try_from(&connector_router_data)?; diff --git a/crates/router/src/connector/trustpay/transformers.rs b/crates/router/src/connector/trustpay/transformers.rs index f6c494170f2..e80ca3eeb5a 100644 --- a/crates/router/src/connector/trustpay/transformers.rs +++ b/crates/router/src/connector/trustpay/transformers.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use common_utils::{ errors::CustomResult, pii::{self, Email}, + types::StringMajorUnit }; use error_stack::{report, ResultExt}; use masking::{ExposeInterface, PeekInterface, Secret}; @@ -24,21 +25,18 @@ type Error = error_stack::Report; #[derive(Debug, Serialize)] pub struct TrustpayRouterData { - pub amount: String, + pub amount: StringMajorUnit, pub router_data: T, } -impl TryFrom<(&types::api::CurrencyUnit, enums::Currency, i64, T)> for TrustpayRouterData { +impl TryFrom<(StringMajorUnit, T)> for TrustpayRouterData { type Error = error_stack::Report; fn try_from( - (currency_unit, currency, amount, item): ( - &types::api::CurrencyUnit, - enums::Currency, - i64, + (amount, item): ( + StringMajorUnit, T, ), ) -> Result { - let amount = utils::get_amount_as_string(currency_unit, amount, currency)?; Ok(Self { amount, router_data: item, @@ -97,7 +95,7 @@ pub struct References { #[derive(Default, Debug, Serialize, Deserialize, Eq, PartialEq, Clone)] #[serde(rename_all = "PascalCase")] pub struct Amount { - pub amount: String, + pub amount: StringMajorUnit, pub currency: String, } @@ -272,7 +270,7 @@ fn get_card_request_data( item: &types::PaymentsAuthorizeRouterData, browser_info: &BrowserInformation, params: TrustpayMandatoryParams, - amount: String, + amount: StringMajorUnit, ccard: &domain::payments::Card, return_url: String, ) -> Result { @@ -352,7 +350,7 @@ fn get_bank_redirection_request_data( item: &types::PaymentsAuthorizeRouterData, bank_redirection_data: &domain::BankRedirectData, params: TrustpayMandatoryParams, - amount: String, + amount: StringMajorUnit, auth: TrustpayAuthType, ) -> Result> { let pm = TrustpayPaymentMethod::try_from(bank_redirection_data)?; @@ -1014,7 +1012,7 @@ impl TryFrom, @@ -1082,7 +1080,7 @@ pub struct GooglePayTransactionInfo { pub country_code: api_models::enums::CountryAlpha2, pub currency_code: api_models::enums::Currency, pub total_price_status: String, - pub total_price: String, + pub total_price: StringMajorUnit, } #[derive(Clone, Default, Debug, Deserialize, Serialize)] @@ -1152,7 +1150,7 @@ pub struct TrustpayApplePayResponse { #[serde(rename_all = "camelCase")] pub struct ApplePayTotalInfo { pub label: String, - pub amount: String, + pub amount: StringMajorUnit, } impl @@ -1388,7 +1386,7 @@ impl From for api_models::payments::AmountInfo { #[serde(rename_all = "camelCase")] pub struct TrustpayRefundRequestCards { instance_id: String, - amount: String, + amount: StringMajorUnit, currency: String, reference: String, } diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 4004f9fed16..cd2bd5feaab 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -378,7 +378,7 @@ impl ConnectorData { enums::Connector::Multisafepay => Ok(Box::new(&connector::Multisafepay)), enums::Connector::Nexinets => Ok(Box::new(&connector::Nexinets)), enums::Connector::Paypal => Ok(Box::new(&connector::Paypal)), - enums::Connector::Trustpay => Ok(Box::new(&connector::Trustpay)), + enums::Connector::Trustpay => Ok(Box::new(connector::Trustpay::new())), enums::Connector::Tsys => Ok(Box::new(&connector::Tsys)), enums::Connector::Volt => Ok(Box::new(&connector::Volt)), enums::Connector::Zen => Ok(Box::new(&connector::Zen)), From 161a013ab64d11ddb58699c46fb9b7b33c03734d Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 3 Jun 2024 15:40:14 +0530 Subject: [PATCH 74/82] refactor(connector): added applepay fix for connectors --- crates/api_models/src/payments.rs | 6 +-- .../src/router_request_types.rs | 3 ++ crates/router/src/connector/bluesnap.rs | 14 +++++- .../src/connector/bluesnap/transformers.rs | 8 ++-- crates/router/src/connector/payme.rs | 17 ++++++-- .../src/connector/payme/transformers.rs | 43 ++++++++++++++----- .../src/connector/trustpay/transformers.rs | 2 +- .../src/core/payments/flows/session_flow.rs | 16 +++---- .../router/src/core/payments/transformers.rs | 1 + 9 files changed, 79 insertions(+), 31 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 31b98e3371c..744ff982e14 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -11,7 +11,7 @@ use common_utils::{ ext_traits::{ConfigExt, Encode}, id_type, pii::{self, Email}, - types::MinorUnit, + types::{MinorUnit,StringMajorUnit} }; use masking::{PeekInterface, Secret}; use router_derive::Setter; @@ -4438,8 +4438,8 @@ pub struct AmountInfo { /// A value that indicates whether the line item(Ex: total, tax, discount, or grand total) is final or pending. #[serde(rename = "type")] pub total_type: Option, - /// The total amount for the payment - pub amount: String, + /// The total amount for the payment in majot unit string (Ex: 38.02) + pub amount: StringMajorUnit, } #[derive(Debug, Clone, serde::Deserialize)] diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index 0b3393570c5..b64e2da20a8 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -675,6 +675,9 @@ pub struct PaymentsSessionData { pub country: Option, pub surcharge_details: Option, pub order_details: Option>, + + // Minor Unit amount for amount frame work + pub minor_amount: MinorUnit } #[derive(Debug, Clone)] diff --git a/crates/router/src/connector/bluesnap.rs b/crates/router/src/connector/bluesnap.rs index b7da3d0da18..9cc015a13f3 100644 --- a/crates/router/src/connector/bluesnap.rs +++ b/crates/router/src/connector/bluesnap.rs @@ -34,6 +34,7 @@ use crate::{ self, api::{self, ConnectorCommon, ConnectorCommonExt}, ErrorResponse, Response, + transformers::ForeignTryFrom, }, utils::BytesExt, }; @@ -43,12 +44,14 @@ pub const BLUESNAP_TRANSACTION_NOT_FOUND: &str = "is not authorized to view merc #[derive(Clone)] pub struct Bluesnap { amount_converter: &'static (dyn AmountConvertor + Sync), + apple_pay_google_pay_amount_converter: &'static (dyn AmountConvertor + Sync) } impl Bluesnap { pub fn new() -> &'static Self { &Self { amount_converter: &StringMajorUnitForConnector, + apple_pay_google_pay_amount_converter: &StringMajorUnitForConnector, } } } @@ -603,11 +606,18 @@ impl ConnectorIntegration for BluesnapCreateWalletToken { } } -impl TryFrom> +impl ForeignTryFrom<(types::PaymentsSessionResponseRouterData, StringMajorUnit)> for types::PaymentsSessionRouterData { type Error = error_stack::Report; - fn try_from( - item: types::PaymentsSessionResponseRouterData, + fn foreign_try_from( + (item, apple_pay_amount): (types::PaymentsSessionResponseRouterData,StringMajorUnit) ) -> Result { let response = &item.response; @@ -531,7 +531,7 @@ impl TryFrom + Sync), + apple_pay_google_pay_amount_converter: &'static (dyn AmountConvertor + Sync) } impl Payme { pub const fn new() -> &'static Self { &Self { amount_converter: &MinorUnitForConnector, + apple_pay_google_pay_amount_converter: &StringMajorUnitForConnector, } } } @@ -342,14 +346,21 @@ impl .parse_struct("Payme GenerateSaleResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; + let req_amount = data.request.get_minor_amount()?; + let req_currency = data.request.get_currency()?; + + let apple_pay_amount = connector_utils::convert_amount(self.apple_pay_google_pay_amount_converter, req_amount, req_currency)?; + event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + types::RouterData::foreign_try_from((types::ResponseRouterData { response, data: data.clone(), http_code: res.status_code, - }) + }, + apple_pay_amount + )) } fn get_error_response( diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index 1606190d986..be56fe34b2c 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use api_models::enums::{AuthenticationType, PaymentMethod}; -use common_utils::{pii, types::MinorUnit}; +use common_utils::{pii, types::{MinorUnit, StringMajorUnit}}; use error_stack::ResultExt; use masking::{ExposeInterface, Secret}; use serde::{Deserialize, Serialize}; @@ -20,6 +20,7 @@ use crate::{ types::{ self, api, domain, domain::PaymentMethodData, storage::enums, transformers::ForeignFrom, MandateReference, + transformers::ForeignTryFrom }, unimplemented_payment_method, }; @@ -42,6 +43,25 @@ impl TryFrom<(MinorUnit, T)> for PaymeRouterData { } } +#[derive(Debug, Serialize)] +pub struct PaymeResponseRouterData { + pub amount: MinorUnit, + pub router_data: T, + pub apple_pay_amount: StringMajorUnit +} + +impl PaymeResponseRouterData { + // type Error = error_stack::Report; + pub fn new(amount: MinorUnit, item: T, apple_pay_amount: StringMajorUnit) -> Self { + Self { + amount, + router_data: item, + apple_pay_amount + } + } +} + + #[derive(Debug, Serialize)] pub struct PayRequest { buyer_name: Secret, @@ -469,23 +489,26 @@ impl TryFrom<&types::RefundSyncRouterData> for PaymeQueryTransactionRequest { } impl - TryFrom< +ForeignTryFrom<( types::ResponseRouterData< F, GenerateSaleResponse, types::PaymentsPreProcessingData, types::PaymentsResponseData, >, - > for types::RouterData + StringMajorUnit +)> for types::RouterData { type Error = error_stack::Report; - fn try_from( - item: types::ResponseRouterData< + fn foreign_try_from( + (item, apple_pay_amount):( + types::ResponseRouterData< F, GenerateSaleResponse, types::PaymentsPreProcessingData, - types::PaymentsResponseData, - >, + types::PaymentsResponseData>, + StringMajorUnit + ), ) -> Result { match item.data.payment_method { PaymentMethod::Card => { @@ -533,8 +556,8 @@ impl } _ => { let currency_code = item.data.request.get_currency()?; - let amount = item.data.request.get_amount()?; - let amount_in_base_unit = utils::to_currency_base_unit(amount, currency_code)?; + // let amount = item.data.request.get_amount()?; + // let amount_in_base_unit = utils::to_currency_base_unit(amount, currency_code)?; let pmd = item.data.request.payment_method_data.to_owned(); let payme_auth_type = PaymeAuthType::try_from(&item.data.connector_auth_type)?; @@ -552,7 +575,7 @@ impl total: api_models::payments::AmountInfo { label: "Apple Pay".to_string(), total_type: None, - amount: amount_in_base_unit, + amount: apple_pay_amount, }, merchant_capabilities: None, supported_networks: None, diff --git a/crates/router/src/connector/trustpay/transformers.rs b/crates/router/src/connector/trustpay/transformers.rs index f6c494170f2..56133aaf6ba 100644 --- a/crates/router/src/connector/trustpay/transformers.rs +++ b/crates/router/src/connector/trustpay/transformers.rs @@ -1375,7 +1375,7 @@ impl From for api_models::payments::SecretInfoToInitiateSdk { } impl From for api_models::payments::AmountInfo { - fn from(value: ApplePayTotalInfo) -> Self { + fn try_from(value: ApplePayTotalInfo) -> Self { Self { label: value.label, amount: value.amount, diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs index c74ed4bae15..b42b0aab58b 100644 --- a/crates/router/src/core/payments/flows/session_flow.rs +++ b/crates/router/src/core/payments/flows/session_flow.rs @@ -1,9 +1,8 @@ use api_models::payments as payment_types; use async_trait::async_trait; -use common_utils::{ext_traits::ByteSliceExt, request::RequestContent}; +use common_utils::{ext_traits::ByteSliceExt, request::RequestContent, types::{StringMajorUnitForConnector,AmountConvertor}}; use error_stack::{Report, ResultExt}; use masking::ExposeInterface; - use super::{ConstructFlowSpecificData, Feature}; use crate::{ core::{ @@ -391,15 +390,16 @@ fn get_apple_pay_amount_info( label: &str, session_data: types::PaymentsSessionData, ) -> RouterResult { + let converter = StringMajorUnitForConnector; + let apple_pay_amount = converter + .convert(session_data.minor_amount, session_data.currency) + .change_context(errors::ApiErrorResponse::PreconditionFailed { + message: "Failed to convert amount to string major unit for applePay".to_string(), + })?; let amount_info = payment_types::AmountInfo { label: label.to_string(), total_type: Some("final".to_string()), - amount: session_data - .currency - .to_currency_base_unit(session_data.amount) - .change_context(errors::ApiErrorResponse::PreconditionFailed { - message: "Failed to convert currency to base unit".to_string(), - })?, + amount: apple_pay_amount }; Ok(amount_info) diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 387525489a7..4d8892acaf7 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -1541,6 +1541,7 @@ impl TryFrom> for types::PaymentsSessionD Ok(Self { amount: 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( |billing_address| { From 875071b8931b8dd3fa4858e07569ae79be095851 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 10:12:54 +0000 Subject: [PATCH 75/82] chore: run formatter --- crates/api_models/src/payments.rs | 2 +- .../src/router_request_types.rs | 2 +- crates/router/src/connector/bluesnap.rs | 26 ++++++++------ .../src/connector/bluesnap/transformers.rs | 12 +++++-- crates/router/src/connector/payme.rs | 32 +++++++++++------ .../src/connector/payme/transformers.rs | 35 +++++++++++-------- .../src/core/payments/flows/session_flow.rs | 9 +++-- 7 files changed, 75 insertions(+), 43 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 744ff982e14..cd096c7031c 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -11,7 +11,7 @@ use common_utils::{ ext_traits::{ConfigExt, Encode}, id_type, pii::{self, Email}, - types::{MinorUnit,StringMajorUnit} + types::{MinorUnit, StringMajorUnit}, }; use masking::{PeekInterface, Secret}; use router_derive::Setter; diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index b64e2da20a8..a4fe9859eb3 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -677,7 +677,7 @@ pub struct PaymentsSessionData { pub order_details: Option>, // Minor Unit amount for amount frame work - pub minor_amount: MinorUnit + pub minor_amount: MinorUnit, } #[derive(Debug, Clone)] diff --git a/crates/router/src/connector/bluesnap.rs b/crates/router/src/connector/bluesnap.rs index 9cc015a13f3..c94fc0d4918 100644 --- a/crates/router/src/connector/bluesnap.rs +++ b/crates/router/src/connector/bluesnap.rs @@ -33,8 +33,8 @@ use crate::{ types::{ self, api::{self, ConnectorCommon, ConnectorCommonExt}, - ErrorResponse, Response, transformers::ForeignTryFrom, + ErrorResponse, Response, }, utils::BytesExt, }; @@ -44,7 +44,8 @@ pub const BLUESNAP_TRANSACTION_NOT_FOUND: &str = "is not authorized to view merc #[derive(Clone)] pub struct Bluesnap { amount_converter: &'static (dyn AmountConvertor + Sync), - apple_pay_google_pay_amount_converter: &'static (dyn AmountConvertor + Sync) + apple_pay_google_pay_amount_converter: + &'static (dyn AmountConvertor + Sync), } impl Bluesnap { @@ -609,15 +610,20 @@ impl ConnectorIntegration for BluesnapCreateWalletToken { } } -impl ForeignTryFrom<(types::PaymentsSessionResponseRouterData, StringMajorUnit)> - for types::PaymentsSessionRouterData +impl + ForeignTryFrom<( + types::PaymentsSessionResponseRouterData, + StringMajorUnit, + )> for types::PaymentsSessionRouterData { type Error = error_stack::Report; fn foreign_try_from( - (item, apple_pay_amount): (types::PaymentsSessionResponseRouterData,StringMajorUnit) + (item, apple_pay_amount): ( + types::PaymentsSessionResponseRouterData, + StringMajorUnit, + ), ) -> Result { let response = &item.response; diff --git a/crates/router/src/connector/payme.rs b/crates/router/src/connector/payme.rs index f657e8564c8..fc5157ddb8a 100644 --- a/crates/router/src/connector/payme.rs +++ b/crates/router/src/connector/payme.rs @@ -4,7 +4,10 @@ use api_models::enums::AuthenticationType; use common_utils::{ crypto, request::RequestContent, - types::{AmountConvertor, MinorUnit, StringMajorUnit, StringMajorUnitForConnector, MinorUnitForConnector}, + types::{ + AmountConvertor, MinorUnit, MinorUnitForConnector, StringMajorUnit, + StringMajorUnitForConnector, + }, }; use diesel_models::enums; use error_stack::{Report, ResultExt}; @@ -24,8 +27,9 @@ use crate::{ types::{ self, api::{self, ConnectorCommon, ConnectorCommonExt}, - domain, ErrorResponse, Response, + domain, transformers::ForeignTryFrom, + ErrorResponse, Response, }, // transformers::{ForeignFrom, ForeignTryFrom}, utils::{handle_json_response_deserialization_failure, BytesExt}, @@ -34,7 +38,8 @@ use crate::{ #[derive(Clone)] pub struct Payme { amount_converter: &'static (dyn AmountConvertor + Sync), - apple_pay_google_pay_amount_converter: &'static (dyn AmountConvertor + Sync) + apple_pay_google_pay_amount_converter: + &'static (dyn AmountConvertor + Sync), } impl Payme { @@ -349,18 +354,23 @@ impl let req_amount = data.request.get_minor_amount()?; let req_currency = data.request.get_currency()?; - let apple_pay_amount = connector_utils::convert_amount(self.apple_pay_google_pay_amount_converter, req_amount, req_currency)?; + let apple_pay_amount = connector_utils::convert_amount( + self.apple_pay_google_pay_amount_converter, + req_amount, + req_currency, + )?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::foreign_try_from((types::ResponseRouterData { - response, - data: data.clone(), - http_code: res.status_code, - }, - apple_pay_amount - )) + types::RouterData::foreign_try_from(( + types::ResponseRouterData { + response, + data: data.clone(), + http_code: res.status_code, + }, + apple_pay_amount, + )) } fn get_error_response( diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index be56fe34b2c..02d7eebc888 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -1,7 +1,10 @@ use std::collections::HashMap; use api_models::enums::{AuthenticationType, PaymentMethod}; -use common_utils::{pii, types::{MinorUnit, StringMajorUnit}}; +use common_utils::{ + pii, + types::{MinorUnit, StringMajorUnit}, +}; use error_stack::ResultExt; use masking::{ExposeInterface, Secret}; use serde::{Deserialize, Serialize}; @@ -18,9 +21,11 @@ use crate::{ core::errors, services, types::{ - self, api, domain, domain::PaymentMethodData, storage::enums, transformers::ForeignFrom, + self, api, domain, + domain::PaymentMethodData, + storage::enums, + transformers::{ForeignFrom, ForeignTryFrom}, MandateReference, - transformers::ForeignTryFrom }, unimplemented_payment_method, }; @@ -47,7 +52,7 @@ impl TryFrom<(MinorUnit, T)> for PaymeRouterData { pub struct PaymeResponseRouterData { pub amount: MinorUnit, pub router_data: T, - pub apple_pay_amount: StringMajorUnit + pub apple_pay_amount: StringMajorUnit, } impl PaymeResponseRouterData { @@ -56,12 +61,11 @@ impl PaymeResponseRouterData { Self { amount, router_data: item, - apple_pay_amount + apple_pay_amount, } } } - #[derive(Debug, Serialize)] pub struct PayRequest { buyer_name: Secret, @@ -489,25 +493,26 @@ impl TryFrom<&types::RefundSyncRouterData> for PaymeQueryTransactionRequest { } impl -ForeignTryFrom<( + ForeignTryFrom<( types::ResponseRouterData< F, GenerateSaleResponse, types::PaymentsPreProcessingData, types::PaymentsResponseData, >, - StringMajorUnit -)> for types::RouterData + StringMajorUnit, + )> for types::RouterData { type Error = error_stack::Report; fn foreign_try_from( - (item, apple_pay_amount):( + (item, apple_pay_amount): ( types::ResponseRouterData< - F, - GenerateSaleResponse, - types::PaymentsPreProcessingData, - types::PaymentsResponseData>, - StringMajorUnit + F, + GenerateSaleResponse, + types::PaymentsPreProcessingData, + types::PaymentsResponseData, + >, + StringMajorUnit, ), ) -> Result { match item.data.payment_method { diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs index b42b0aab58b..d4103b04897 100644 --- a/crates/router/src/core/payments/flows/session_flow.rs +++ b/crates/router/src/core/payments/flows/session_flow.rs @@ -1,8 +1,13 @@ use api_models::payments as payment_types; use async_trait::async_trait; -use common_utils::{ext_traits::ByteSliceExt, request::RequestContent, types::{StringMajorUnitForConnector,AmountConvertor}}; +use common_utils::{ + ext_traits::ByteSliceExt, + request::RequestContent, + types::{AmountConvertor, StringMajorUnitForConnector}, +}; use error_stack::{Report, ResultExt}; use masking::ExposeInterface; + use super::{ConstructFlowSpecificData, Feature}; use crate::{ core::{ @@ -399,7 +404,7 @@ fn get_apple_pay_amount_info( let amount_info = payment_types::AmountInfo { label: label.to_string(), total_type: Some("final".to_string()), - amount: apple_pay_amount + amount: apple_pay_amount, }; Ok(amount_info) From 66dba1dff0b45a07998c503e2c664c3c9c230031 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 3 Jun 2024 16:31:23 +0530 Subject: [PATCH 76/82] refactor(connector): fixed open-api specs --- crates/api_models/src/payments.rs | 2 ++ openapi/openapi_spec.json | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 1d4404f2243..8c9c56f0238 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -4083,6 +4083,7 @@ pub struct GpayTransactionInfo { /// The total price status (ex: 'FINAL') pub total_price_status: String, /// The total price + #[schema(value_type = String, example = "38.02")] pub total_price: StringMajorUnit, } @@ -4439,6 +4440,7 @@ pub struct AmountInfo { #[serde(rename = "type")] pub total_type: Option, /// The total amount for the payment in majot unit string (Ex: 38.02) + #[schema(value_type = String, example = "38.02")] pub amount: StringMajorUnit, } diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json index 620b8d29b01..5b4860e9971 100644 --- a/openapi/openapi_spec.json +++ b/openapi/openapi_spec.json @@ -5001,7 +5001,8 @@ }, "amount": { "type": "string", - "description": "The total amount for the payment" + "description": "The total amount for the payment in majot unit string (Ex: 38.02)", + "example": "38.02" } } }, @@ -9890,7 +9891,8 @@ }, "total_price": { "type": "string", - "description": "The total price" + "description": "The total price", + "example": "38.02" } } }, From f0b4593fbeb9d174f46318b42380c08272b38a24 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Wed, 5 Jun 2024 16:30:37 +0530 Subject: [PATCH 77/82] refactor(router): removed payme from noon --- crates/router/src/connector/payme.rs | 84 ++++++++----------- .../src/connector/payme/transformers.rs | 24 +++--- crates/router/src/types/api.rs | 2 +- 3 files changed, 48 insertions(+), 62 deletions(-) diff --git a/crates/router/src/connector/payme.rs b/crates/router/src/connector/payme.rs index 25a4bd83975..c7a51a6c8b4 100644 --- a/crates/router/src/connector/payme.rs +++ b/crates/router/src/connector/payme.rs @@ -1,11 +1,9 @@ pub mod transformers; +use std::fmt::Debug; + use api_models::enums::AuthenticationType; -use common_utils::{ - crypto, - request::RequestContent, - types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, -}; +use common_utils::{crypto, request::RequestContent}; use diesel_models::enums; use error_stack::{Report, ResultExt}; use masking::ExposeInterface; @@ -29,18 +27,8 @@ use crate::{ utils::{handle_json_response_deserialization_failure, BytesExt}, }; -#[derive(Clone)] -pub struct Payme { - amount_converter: &'static (dyn AmountConvertor + Sync), -} - -impl Payme { - pub const fn new() -> &'static Self { - &Self { - amount_converter: &MinorUnitForConnector, - } - } -} +#[derive(Debug, Clone)] +pub struct Payme; impl api::Payment for Payme {} impl api::PaymentSession for Payme {} @@ -299,11 +287,10 @@ impl req: &types::PaymentsPreProcessingRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let req_amount = req.request.get_minor_amount()?; - let req_currency = req.request.get_currency()?; - let amount = - connector_utils::convert_amount(self.amount_converter, req_amount, req_currency)?; - let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; + let amount = req.request.get_amount()?; + let currency = req.request.get_currency()?; + let connector_router_data = + payme::PaymeRouterData::try_from((&self.get_currency_unit(), currency, amount, req))?; let connector_req = payme::GenerateSaleRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -549,12 +536,12 @@ impl ConnectorIntegration CustomResult { - let amount = connector_utils::convert_amount( - self.amount_converter, - req.request.minor_amount, + let connector_router_data = payme::PaymeRouterData::try_from(( + &self.get_currency_unit(), req.request.currency, - )?; - let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; + req.request.amount, + req, + ))?; let connector_req = payme::PaymePaymentRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -737,12 +724,12 @@ impl ConnectorIntegration CustomResult { - let amount = connector_utils::convert_amount( - self.amount_converter, - req.request.minor_amount_to_capture, + let connector_router_data = payme::PaymeRouterData::try_from(( + &self.get_currency_unit(), req.request.currency, - )?; - let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; + req.request.amount_to_capture, + req, + ))?; let connector_req = payme::PaymentCaptureRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -835,21 +822,20 @@ impl ConnectorIntegration CustomResult { - let req_amount = - req.request - .minor_amount - .ok_or(errors::ConnectorError::MissingRequiredField { - field_name: "amount", - })?; - let req_currency = + let amount = req + .request + .amount + .ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "amount", + })?; + let currency = req.request .currency .ok_or(errors::ConnectorError::MissingRequiredField { - field_name: "amount", + field_name: "currency", })?; - let amount = - connector_utils::convert_amount(self.amount_converter, req_amount, req_currency)?; - let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; + let connector_router_data = + payme::PaymeRouterData::try_from((&self.get_currency_unit(), currency, amount, req))?; let connector_req = payme::PaymeVoidRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -936,12 +922,12 @@ impl ConnectorIntegration, _connectors: &settings::Connectors, ) -> CustomResult { - let amount = connector_utils::convert_amount( - self.amount_converter, - req.request.minor_refund_amount, + let connector_router_data = payme::PaymeRouterData::try_from(( + &self.get_currency_unit(), req.request.currency, - )?; - let connector_router_data = payme::PaymeRouterData::try_from((amount, req))?; + req.request.refund_amount, + req, + ))?; let connector_req = payme::PaymeRefundRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -1270,4 +1256,4 @@ impl api::IncomingWebhook for Payme { updated_at: None, }) } -} +} \ No newline at end of file diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index 1606190d986..9262a9d549e 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use api_models::enums::{AuthenticationType, PaymentMethod}; -use common_utils::{pii, types::MinorUnit}; +use common_utils::pii; use error_stack::ResultExt; use masking::{ExposeInterface, Secret}; use serde::{Deserialize, Serialize}; @@ -28,13 +28,15 @@ const LANGUAGE: &str = "en"; #[derive(Debug, Serialize)] pub struct PaymeRouterData { - pub amount: MinorUnit, + pub amount: i64, pub router_data: T, } -impl TryFrom<(MinorUnit, T)> for PaymeRouterData { +impl TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for PaymeRouterData { type Error = error_stack::Report; - fn try_from((amount, item): (MinorUnit, T)) -> Result { + fn try_from( + (_currency_unit, _currency, amount, item): (&api::CurrencyUnit, enums::Currency, i64, T), + ) -> Result { Ok(Self { amount, router_data: item, @@ -55,7 +57,7 @@ pub struct PayRequest { #[derive(Debug, Serialize)] pub struct MandateRequest { currency: enums::Currency, - sale_price: MinorUnit, + sale_price: i64, transaction_id: String, product_name: String, sale_return_url: String, @@ -116,7 +118,7 @@ pub struct CaptureBuyerResponse { pub struct GenerateSaleRequest { currency: enums::Currency, sale_type: SaleType, - sale_price: MinorUnit, + sale_price: i64, transaction_id: String, product_name: String, sale_return_url: String, @@ -900,7 +902,7 @@ impl #[derive(Debug, Serialize)] pub struct PaymentCaptureRequest { payme_sale_id: String, - sale_price: MinorUnit, + sale_price: i64, } impl TryFrom<&PaymeRouterData<&types::PaymentsCaptureRouterData>> for PaymentCaptureRequest { @@ -908,9 +910,7 @@ impl TryFrom<&PaymeRouterData<&types::PaymentsCaptureRouterData>> for PaymentCap fn try_from( item: &PaymeRouterData<&types::PaymentsCaptureRouterData>, ) -> Result { - if item.router_data.request.minor_amount_to_capture - != item.router_data.request.minor_payment_amount - { + if item.router_data.request.amount_to_capture != item.router_data.request.payment_amount { Err(errors::ConnectorError::NotSupported { message: "Partial Capture".to_string(), connector: "Payme", @@ -927,7 +927,7 @@ impl TryFrom<&PaymeRouterData<&types::PaymentsCaptureRouterData>> for PaymentCap // Type definition for RefundRequest #[derive(Debug, Serialize)] pub struct PaymeRefundRequest { - sale_refund_amount: MinorUnit, + sale_refund_amount: i64, payme_sale_id: String, seller_payme_id: Secret, language: String, @@ -1241,4 +1241,4 @@ impl From for api::IncomingWebhookEvent { NotifyType::SaleAuthorized => Self::EventNotSupported, } } -} +} \ No newline at end of file diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 4004f9fed16..7feba490e48 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -361,7 +361,7 @@ impl ConnectorData { enums::Connector::Nuvei => Ok(Box::new(&connector::Nuvei)), enums::Connector::Opennode => Ok(Box::new(&connector::Opennode)), // "payeezy" => Ok(Box::new(&connector::Payeezy)), As psync and rsync are not supported by this connector, it is added as template code for future usage - enums::Connector::Payme => Ok(Box::new(connector::Payme::new())), + enums::Connector::Payme => Ok(Box::new(&connector::Payme)), enums::Connector::Payone => Ok(Box::new(&connector::Payone)), enums::Connector::Payu => Ok(Box::new(&connector::Payu)), enums::Connector::Placetopay => Ok(Box::new(&connector::Placetopay)), From e651ecaa99b39cc62af72be89b74fc719bb346b5 Mon Sep 17 00:00:00 2001 From: "hyperswitch-bot[bot]" <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 11:01:32 +0000 Subject: [PATCH 78/82] chore: run formatter --- crates/router/src/connector/payme.rs | 2 +- crates/router/src/connector/payme/transformers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/router/src/connector/payme.rs b/crates/router/src/connector/payme.rs index c7a51a6c8b4..397715d102d 100644 --- a/crates/router/src/connector/payme.rs +++ b/crates/router/src/connector/payme.rs @@ -1256,4 +1256,4 @@ impl api::IncomingWebhook for Payme { updated_at: None, }) } -} \ No newline at end of file +} diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs index 9262a9d549e..634c0a17c7a 100644 --- a/crates/router/src/connector/payme/transformers.rs +++ b/crates/router/src/connector/payme/transformers.rs @@ -1241,4 +1241,4 @@ impl From for api::IncomingWebhookEvent { NotifyType::SaleAuthorized => Self::EventNotSupported, } } -} \ No newline at end of file +} From 4faa30b2df21337cd120b14b99da52f19d51806f Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Wed, 5 Jun 2024 16:32:28 +0530 Subject: [PATCH 79/82] refactor(connector): fixed test files --- crates/router/tests/connectors/payme.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/router/tests/connectors/payme.rs b/crates/router/tests/connectors/payme.rs index cbebe540d0f..6554ddbefbf 100644 --- a/crates/router/tests/connectors/payme.rs +++ b/crates/router/tests/connectors/payme.rs @@ -17,7 +17,7 @@ impl utils::Connector for PaymeTest { fn get_data(&self) -> types::api::ConnectorData { use router::connector::Payme; types::api::ConnectorData { - connector: Box::new(Payme::new()), + connector: Box::new(&Payme), connector_name: types::Connector::Payme, get_token: types::api::GetToken::Connector, merchant_connector_id: None, From 25ca6939c3fdeaf09bfac865004d897a685ce9f3 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 24 Jun 2024 15:33:25 +0530 Subject: [PATCH 80/82] refactor(connector): resolved pr comments: --- crates/router/src/connector/bluesnap.rs | 6 +++--- crates/router/src/connector/payme.rs | 8 ++++---- crates/router/src/connector/payme/transformers.rs | 2 -- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/crates/router/src/connector/bluesnap.rs b/crates/router/src/connector/bluesnap.rs index c94fc0d4918..bd853cfddf7 100644 --- a/crates/router/src/connector/bluesnap.rs +++ b/crates/router/src/connector/bluesnap.rs @@ -44,7 +44,7 @@ pub const BLUESNAP_TRANSACTION_NOT_FOUND: &str = "is not authorized to view merc #[derive(Clone)] pub struct Bluesnap { amount_converter: &'static (dyn AmountConvertor + Sync), - apple_pay_google_pay_amount_converter: + session_amount_converter: &'static (dyn AmountConvertor + Sync), } @@ -52,7 +52,7 @@ impl Bluesnap { pub fn new() -> &'static Self { &Self { amount_converter: &StringMajorUnitForConnector, - apple_pay_google_pay_amount_converter: &StringMajorUnitForConnector, + session_amount_converter: &StringMajorUnitForConnector, } } } @@ -611,7 +611,7 @@ impl ConnectorIntegration + Sync), - apple_pay_google_pay_amount_converter: + session_amount_converter: &'static (dyn AmountConvertor + Sync), } @@ -46,7 +46,7 @@ impl Payme { pub const fn new() -> &'static Self { &Self { amount_converter: &MinorUnitForConnector, - apple_pay_google_pay_amount_converter: &StringMajorUnitForConnector, + session_amount_converter: &StringMajorUnitForConnector, } } } @@ -355,7 +355,7 @@ impl let req_currency = data.request.get_currency()?; let apple_pay_amount = connector_utils::convert_amount( - self.apple_pay_google_pay_amount_converter, + self.session_amount_converter, req_amount, req_currency, )?; @@ -866,7 +866,7 @@ impl ConnectorIntegration } _ => { let currency_code = item.data.request.get_currency()?; - // let amount = item.data.request.get_amount()?; - // let amount_in_base_unit = utils::to_currency_base_unit(amount, currency_code)?; let pmd = item.data.request.payment_method_data.to_owned(); let payme_auth_type = PaymeAuthType::try_from(&item.data.connector_auth_type)?; From 1041fbfb76ed935c625a8f9e287f722257f94c5c Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 24 Jun 2024 16:21:15 +0530 Subject: [PATCH 81/82] refactor(connector): fixed ci checks failures --- crates/router/src/types/api.rs | 6 ++++-- crates/router/tests/connectors/payme.rs | 2 +- crates/router/tests/connectors/trustpay.rs | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 883693ff63a..5dcb8db05a5 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -437,7 +437,9 @@ impl ConnectorData { Ok(ConnectorEnum::Old(Box::new(&connector::Opennode))) } // "payeezy" => Ok(ConnectorIntegrationEnum::Old(Box::new(&connector::Payeezy)), As psync and rsync are not supported by this connector, it is added as template code for future usage - enums::Connector::Payme => Ok(ConnectorEnum::Old(Box::new(&connector::Payme))), + enums::Connector::Payme => { + Ok(ConnectorEnum::Old(Box::new(connector::Payme::new()))) + } enums::Connector::Payone => Ok(ConnectorEnum::Old(Box::new(&connector::Payone))), enums::Connector::Payu => Ok(ConnectorEnum::Old(Box::new(&connector::Payu))), enums::Connector::Placetopay => { @@ -477,7 +479,7 @@ impl ConnectorData { } enums::Connector::Paypal => Ok(ConnectorEnum::Old(Box::new(&connector::Paypal))), enums::Connector::Trustpay => { - Ok(ConnectorEnum::Old(Box::new(&connector::Trustpay))) + Ok(ConnectorEnum::Old(Box::new(connector::Trustpay::new()))) } enums::Connector::Tsys => Ok(ConnectorEnum::Old(Box::new(&connector::Tsys))), enums::Connector::Volt => Ok(ConnectorEnum::Old(Box::new(&connector::Volt))), diff --git a/crates/router/tests/connectors/payme.rs b/crates/router/tests/connectors/payme.rs index 7c8a7720cd0..590ad15d7f6 100644 --- a/crates/router/tests/connectors/payme.rs +++ b/crates/router/tests/connectors/payme.rs @@ -17,7 +17,7 @@ impl utils::Connector for PaymeTest { fn get_data(&self) -> types::api::ConnectorData { use router::connector::Payme; utils::construct_connector_data_old( - Box::new(&Payme), + Box::new(Payme::new()), types::Connector::Payme, types::api::GetToken::Connector, None, diff --git a/crates/router/tests/connectors/trustpay.rs b/crates/router/tests/connectors/trustpay.rs index 848797ebf15..bae62913a9a 100644 --- a/crates/router/tests/connectors/trustpay.rs +++ b/crates/router/tests/connectors/trustpay.rs @@ -15,7 +15,7 @@ impl utils::Connector for TrustpayTest { fn get_data(&self) -> api::ConnectorData { use router::connector::Trustpay; utils::construct_connector_data_old( - Box::new(&Trustpay), + Box::new(Trustpay::new()), types::Connector::Trustpay, api::GetToken::Connector, None, From ccba97251170515409cd46d8af5297c8af6a9813 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Tue, 25 Jun 2024 13:29:39 +0530 Subject: [PATCH 82/82] refactor(connector): adderessed pr comments --- crates/router/src/connector/bluesnap.rs | 9 ++------- crates/router/src/connector/payme.rs | 7 ++++--- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/crates/router/src/connector/bluesnap.rs b/crates/router/src/connector/bluesnap.rs index 9045bd8a971..7fb4869dc83 100644 --- a/crates/router/src/connector/bluesnap.rs +++ b/crates/router/src/connector/bluesnap.rs @@ -44,14 +44,12 @@ pub const BLUESNAP_TRANSACTION_NOT_FOUND: &str = "is not authorized to view merc #[derive(Clone)] pub struct Bluesnap { amount_converter: &'static (dyn AmountConvertor + Sync), - session_amount_converter: &'static (dyn AmountConvertor + Sync), } impl Bluesnap { pub fn new() -> &'static Self { &Self { amount_converter: &StringMajorUnitForConnector, - session_amount_converter: &StringMajorUnitForConnector, } } } @@ -609,11 +607,8 @@ impl ConnectorIntegration + Sync), - session_amount_converter: &'static (dyn AmountConvertor + Sync), + apple_pay_google_pay_amount_converter: + &'static (dyn AmountConvertor + Sync), } impl Payme { pub const fn new() -> &'static Self { &Self { amount_converter: &MinorUnitForConnector, - session_amount_converter: &StringMajorUnitForConnector, + apple_pay_google_pay_amount_converter: &StringMajorUnitForConnector, } } } @@ -354,7 +355,7 @@ impl let req_currency = data.request.get_currency()?; let apple_pay_amount = connector_utils::convert_amount( - self.session_amount_converter, + self.apple_pay_google_pay_amount_converter, req_amount, req_currency, )?;