mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-31 01:57:45 +08:00
refactor(router): include currency conversion utility functions as Currency methods (#1790)
This commit is contained in:
@ -1,3 +1,5 @@
|
|||||||
|
use std::num::TryFromIntError;
|
||||||
|
|
||||||
use router_derive;
|
use router_derive;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
@ -289,6 +291,40 @@ pub enum Currency {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Currency {
|
impl Currency {
|
||||||
|
/// Convert the amount to its base denomination based on Currency and return String
|
||||||
|
pub fn to_currency_base_unit(&self, amount: i64) -> Result<String, TryFromIntError> {
|
||||||
|
let amount_f64 = self.to_currency_base_unit_asf64(amount)?;
|
||||||
|
Ok(format!("{amount_f64:.2}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the amount to its base denomination based on Currency and return f64
|
||||||
|
pub fn to_currency_base_unit_asf64(&self, amount: i64) -> Result<f64, TryFromIntError> {
|
||||||
|
let amount_f64: f64 = u32::try_from(amount)?.into();
|
||||||
|
let amount = if self.is_zero_decimal_currency() {
|
||||||
|
amount_f64
|
||||||
|
} else if self.is_three_decimal_currency() {
|
||||||
|
amount_f64 / 1000.00
|
||||||
|
} else {
|
||||||
|
amount_f64 / 100.00
|
||||||
|
};
|
||||||
|
Ok(amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert the amount to its base 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_currency_base_unit_with_zero_decimal_check(
|
||||||
|
&self,
|
||||||
|
amount: i64,
|
||||||
|
) -> Result<String, TryFromIntError> {
|
||||||
|
let amount_f64 = self.to_currency_base_unit_asf64(amount)?;
|
||||||
|
if self.is_zero_decimal_currency() {
|
||||||
|
Ok(amount_f64.to_string())
|
||||||
|
} else {
|
||||||
|
Ok(format!("{amount_f64:.2}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn iso_4217(&self) -> &'static str {
|
pub fn iso_4217(&self) -> &'static str {
|
||||||
match *self {
|
match *self {
|
||||||
Self::AED => "784",
|
Self::AED => "784",
|
||||||
|
|||||||
@ -21,7 +21,7 @@ use crate::{
|
|||||||
core::errors::{self, CustomResult},
|
core::errors::{self, CustomResult},
|
||||||
pii::PeekInterface,
|
pii::PeekInterface,
|
||||||
types::{self, api, transformers::ForeignTryFrom, PaymentsCancelData, ResponseId},
|
types::{self, api, transformers::ForeignTryFrom, PaymentsCancelData, ResponseId},
|
||||||
utils::{self, OptionExt, ValueExt},
|
utils::{OptionExt, ValueExt},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn missing_field_err(
|
pub fn missing_field_err(
|
||||||
@ -924,7 +924,9 @@ pub fn to_currency_base_unit(
|
|||||||
amount: i64,
|
amount: i64,
|
||||||
currency: diesel_models::enums::Currency,
|
currency: diesel_models::enums::Currency,
|
||||||
) -> Result<String, error_stack::Report<errors::ConnectorError>> {
|
) -> Result<String, error_stack::Report<errors::ConnectorError>> {
|
||||||
utils::to_currency_base_unit(amount, currency)
|
currency
|
||||||
|
.to_currency_base_unit(amount)
|
||||||
|
.into_report()
|
||||||
.change_context(errors::ConnectorError::RequestEncodingFailed)
|
.change_context(errors::ConnectorError::RequestEncodingFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -932,7 +934,9 @@ pub fn to_currency_base_unit_with_zero_decimal_check(
|
|||||||
amount: i64,
|
amount: i64,
|
||||||
currency: diesel_models::enums::Currency,
|
currency: diesel_models::enums::Currency,
|
||||||
) -> Result<String, error_stack::Report<errors::ConnectorError>> {
|
) -> Result<String, error_stack::Report<errors::ConnectorError>> {
|
||||||
utils::to_currency_base_unit_with_zero_decimal_check(amount, currency)
|
currency
|
||||||
|
.to_currency_base_unit_with_zero_decimal_check(amount)
|
||||||
|
.into_report()
|
||||||
.change_context(errors::ConnectorError::RequestEncodingFailed)
|
.change_context(errors::ConnectorError::RequestEncodingFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -940,7 +944,9 @@ pub fn to_currency_base_unit_asf64(
|
|||||||
amount: i64,
|
amount: i64,
|
||||||
currency: diesel_models::enums::Currency,
|
currency: diesel_models::enums::Currency,
|
||||||
) -> Result<f64, error_stack::Report<errors::ConnectorError>> {
|
) -> Result<f64, error_stack::Report<errors::ConnectorError>> {
|
||||||
utils::to_currency_base_unit_asf64(amount, currency)
|
currency
|
||||||
|
.to_currency_base_unit_asf64(amount)
|
||||||
|
.into_report()
|
||||||
.change_context(errors::ConnectorError::RequestEncodingFailed)
|
.change_context(errors::ConnectorError::RequestEncodingFailed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
use api_models::payments as payment_types;
|
use api_models::payments as payment_types;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use common_utils::ext_traits::ByteSliceExt;
|
use common_utils::ext_traits::ByteSliceExt;
|
||||||
use error_stack::{Report, ResultExt};
|
use error_stack::{IntoReport, Report, ResultExt};
|
||||||
|
|
||||||
use super::{ConstructFlowSpecificData, Feature};
|
use super::{ConstructFlowSpecificData, Feature};
|
||||||
use crate::{
|
use crate::{
|
||||||
connector,
|
|
||||||
core::{
|
core::{
|
||||||
errors::{self, ConnectorErrorExt, RouterResult},
|
errors::{self, ConnectorErrorExt, RouterResult},
|
||||||
payments::{self, access_token, transformers, PaymentData},
|
payments::{self, access_token, transformers, PaymentData},
|
||||||
@ -172,10 +171,11 @@ async fn create_applepay_session_token(
|
|||||||
let amount_info = payment_types::AmountInfo {
|
let amount_info = payment_types::AmountInfo {
|
||||||
label: applepay_metadata.data.payment_request_data.label,
|
label: applepay_metadata.data.payment_request_data.label,
|
||||||
total_type: Some("final".to_string()),
|
total_type: Some("final".to_string()),
|
||||||
amount: connector::utils::to_currency_base_unit(
|
amount: router_data
|
||||||
router_data.request.amount,
|
.request
|
||||||
router_data.request.currency,
|
.currency
|
||||||
)
|
.to_currency_base_unit(router_data.request.amount)
|
||||||
|
.into_report()
|
||||||
.change_context(errors::ApiErrorResponse::PreconditionFailed {
|
.change_context(errors::ApiErrorResponse::PreconditionFailed {
|
||||||
message: "Failed to convert currency to base unit".to_string(),
|
message: "Failed to convert currency to base unit".to_string(),
|
||||||
})?,
|
})?,
|
||||||
@ -324,10 +324,11 @@ fn create_gpay_session_token(
|
|||||||
country_code: session_data.country.unwrap_or_default(),
|
country_code: session_data.country.unwrap_or_default(),
|
||||||
currency_code: router_data.request.currency,
|
currency_code: router_data.request.currency,
|
||||||
total_price_status: "Final".to_string(),
|
total_price_status: "Final".to_string(),
|
||||||
total_price: utils::to_currency_base_unit(
|
total_price: router_data
|
||||||
router_data.request.amount,
|
.request
|
||||||
router_data.request.currency,
|
.currency
|
||||||
)
|
.to_currency_base_unit(router_data.request.amount)
|
||||||
|
.into_report()
|
||||||
.attach_printable(
|
.attach_printable(
|
||||||
"Cannot convert given amount to base currency denomination".to_string(),
|
"Cannot convert given amount to base currency denomination".to_string(),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use std::{fmt::Debug, marker::PhantomData};
|
|||||||
|
|
||||||
use common_utils::fp_utils;
|
use common_utils::fp_utils;
|
||||||
use diesel_models::{ephemeral_key, payment_attempt::PaymentListFilters};
|
use diesel_models::{ephemeral_key, payment_attempt::PaymentListFilters};
|
||||||
use error_stack::ResultExt;
|
use error_stack::{IntoReport, ResultExt};
|
||||||
use router_env::{instrument, tracing};
|
use router_env::{instrument, tracing};
|
||||||
|
|
||||||
use super::{flows::Feature, PaymentAddress, PaymentData};
|
use super::{flows::Feature, PaymentAddress, PaymentData};
|
||||||
@ -21,7 +21,7 @@ use crate::{
|
|||||||
storage::{self, enums},
|
storage::{self, enums},
|
||||||
transformers::{ForeignFrom, ForeignInto},
|
transformers::{ForeignFrom, ForeignInto},
|
||||||
},
|
},
|
||||||
utils::{self, OptionExt, ValueExt},
|
utils::{OptionExt, ValueExt},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
@ -303,11 +303,12 @@ where
|
|||||||
.currency
|
.currency
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.get_required_value("currency")?;
|
.get_required_value("currency")?;
|
||||||
let amount = utils::to_currency_base_unit(payment_attempt.amount, *currency).change_context(
|
let amount = currency
|
||||||
errors::ApiErrorResponse::InvalidDataValue {
|
.to_currency_base_unit(payment_attempt.amount)
|
||||||
|
.into_report()
|
||||||
|
.change_context(errors::ApiErrorResponse::InvalidDataValue {
|
||||||
field_name: "amount",
|
field_name: "amount",
|
||||||
},
|
})?;
|
||||||
)?;
|
|
||||||
let mandate_id = payment_attempt.mandate_id.clone();
|
let mandate_id = payment_attempt.mandate_id.clone();
|
||||||
let refunds_response = if refunds.is_empty() {
|
let refunds_response = if refunds.is_empty() {
|
||||||
None
|
None
|
||||||
|
|||||||
@ -129,51 +129,6 @@ impl<E> ConnectorResponseExt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert the amount to its base denomination based on Currency and return String
|
|
||||||
pub fn to_currency_base_unit(
|
|
||||||
amount: i64,
|
|
||||||
currency: diesel_models::enums::Currency,
|
|
||||||
) -> Result<String, error_stack::Report<errors::ValidationError>> {
|
|
||||||
let amount_f64 = to_currency_base_unit_asf64(amount, currency)?;
|
|
||||||
Ok(format!("{amount_f64:.2}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert the amount to its base 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_currency_base_unit_with_zero_decimal_check(
|
|
||||||
amount: i64,
|
|
||||||
currency: diesel_models::enums::Currency,
|
|
||||||
) -> Result<String, error_stack::Report<errors::ValidationError>> {
|
|
||||||
let amount_f64 = to_currency_base_unit_asf64(amount, currency)?;
|
|
||||||
if currency.is_zero_decimal_currency() {
|
|
||||||
Ok(amount_f64.to_string())
|
|
||||||
} else {
|
|
||||||
Ok(format!("{amount_f64:.2}"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert the amount to its base denomination based on Currency and return f64
|
|
||||||
pub fn to_currency_base_unit_asf64(
|
|
||||||
amount: i64,
|
|
||||||
currency: diesel_models::enums::Currency,
|
|
||||||
) -> Result<f64, error_stack::Report<errors::ValidationError>> {
|
|
||||||
let amount_u32 = u32::try_from(amount).into_report().change_context(
|
|
||||||
errors::ValidationError::InvalidValue {
|
|
||||||
message: amount.to_string(),
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
let amount_f64 = f64::from(amount_u32);
|
|
||||||
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(amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_payment_attempt_id(payment_id: impl std::fmt::Display, attempt_count: i16) -> String {
|
pub fn get_payment_attempt_id(payment_id: impl std::fmt::Display, attempt_count: i16) -> String {
|
||||||
format!("{payment_id}_{attempt_count}")
|
format!("{payment_id}_{attempt_count}")
|
||||||
|
|||||||
Reference in New Issue
Block a user