Skip to content

Commit

Permalink
refactor(router): resolved merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
sahkal committed Oct 12, 2023
2 parents 1a66e0f + 1ee1184 commit b6cda40
Show file tree
Hide file tree
Showing 57 changed files with 738 additions and 83 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/api_models/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mime = "0.3.17"
reqwest = { version = "0.11.18", optional = true }
serde = { version = "1.0.163", features = ["derive"] }
serde_json = "1.0.96"
serde_with = "3.0.0"
strum = { version = "0.24.1", features = ["derive"] }
time = { version = "0.3.21", features = ["serde", "serde-well-known", "std"] }
url = { version = "2.4.0", features = ["serde"] }
Expand Down
1 change: 0 additions & 1 deletion crates/api_models/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,5 @@ pub mod payments;
#[cfg(feature = "payouts")]
pub mod payouts;
pub mod refunds;
pub mod types;
pub mod verifications;
pub mod webhooks;
46 changes: 38 additions & 8 deletions crates/api_models/src/payment_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ use std::collections::HashMap;
use cards::CardNumber;
use common_utils::{
consts::SURCHARGE_PERCENTAGE_PRECISION_LENGTH, crypto::OptionalEncryptableName, pii,
types::Percentage,
};
use serde::de;
use serde_with::serde_as;
use utoipa::ToSchema;

#[cfg(feature = "payouts")]
use crate::payouts;
use crate::{
admin, enums as api_enums,
payments::{self, BankCodeResponse},
types::Percentage,
};

#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
Expand Down Expand Up @@ -251,12 +252,28 @@ pub struct PaymentExperienceTypes {
pub eligible_connectors: Vec<String>,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema, PartialEq, Eq)]
#[derive(Debug, Clone, serde::Serialize, ToSchema, PartialEq)]
pub struct CardNetworkTypes {
/// The card network enabled
#[schema(value_type = Option<CardNetwork>, example = "Visa")]
pub card_network: api_enums::CardNetwork,

/// surcharge details for this card network
#[schema(example = r#"
{
"surcharge": {
"type": "rate",
"value": {
"percentage": 2.5
}
},
"tax_on_surcharge": {
"percentage": 1.5
}
}
"#)]
pub surcharge_details: Option<SurchargeDetailsResponse>,

/// The list of eligible connectors for a given card network
#[schema(example = json!(["stripe", "adyen"]))]
pub eligible_connectors: Vec<String>,
Expand Down Expand Up @@ -304,18 +321,31 @@ pub struct ResponsePaymentMethodTypes {
}
}
"#)]
pub surcharge_details: Option<SurchargeDetails>,
pub surcharge_details: Option<SurchargeDetailsResponse>,
}
#[derive(Clone, Debug, PartialEq, serde::Serialize, ToSchema)]
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub struct SurchargeDetails {
pub struct SurchargeDetailsResponse {
/// surcharge value
surcharge: Surcharge,
pub surcharge: Surcharge,
/// tax on surcharge value
tax_on_surcharge: Option<Percentage<SURCHARGE_PERCENTAGE_PRECISION_LENGTH>>,
pub tax_on_surcharge: Option<Percentage<SURCHARGE_PERCENTAGE_PRECISION_LENGTH>>,
/// surcharge amount for this payment
pub surcharge_amount: i64,
/// tax on surcharge amount for this payment
pub tax_on_surcharge_amount: i64,
/// sum of original amount,
pub final_amount: i64,
}

#[serde_as]
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct SurchargeMetadata {
#[serde_as(as = "HashMap<_, _>")]
pub surcharge_results: HashMap<String, SurchargeDetailsResponse>,
}

#[derive(Clone, Debug, PartialEq, serde::Serialize, ToSchema)]
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)]
#[serde(rename_all = "snake_case", tag = "type", content = "value")]
pub enum Surcharge {
/// Fixed Surcharge value
Expand Down
162 changes: 162 additions & 0 deletions crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,168 @@ pub enum PaymentMethodData {
GiftCard(Box<GiftCardData>),
}

pub trait GetPaymentMethodType {
fn get_payment_method_type(&self) -> api_enums::PaymentMethodType;
}

impl GetPaymentMethodType for CardRedirectData {
fn get_payment_method_type(&self) -> api_enums::PaymentMethodType {
match self {
Self::Knet {} => api_enums::PaymentMethodType::Knet,
Self::Benefit {} => api_enums::PaymentMethodType::Benefit,
Self::MomoAtm {} => api_enums::PaymentMethodType::MomoAtm,
}
}
}

impl GetPaymentMethodType for WalletData {
fn get_payment_method_type(&self) -> api_enums::PaymentMethodType {
match self {
Self::AliPayQr(_) | Self::AliPayRedirect(_) => api_enums::PaymentMethodType::AliPay,
Self::AliPayHkRedirect(_) => api_enums::PaymentMethodType::AliPayHk,
Self::MomoRedirect(_) => api_enums::PaymentMethodType::Momo,
Self::KakaoPayRedirect(_) => api_enums::PaymentMethodType::KakaoPay,
Self::GoPayRedirect(_) => api_enums::PaymentMethodType::GoPay,
Self::GcashRedirect(_) => api_enums::PaymentMethodType::Gcash,
Self::ApplePay(_) | Self::ApplePayRedirect(_) | Self::ApplePayThirdPartySdk(_) => {
api_enums::PaymentMethodType::ApplePay
}
Self::DanaRedirect {} => api_enums::PaymentMethodType::Dana,
Self::GooglePay(_) | Self::GooglePayRedirect(_) | Self::GooglePayThirdPartySdk(_) => {
api_enums::PaymentMethodType::GooglePay
}
Self::MbWayRedirect(_) => api_enums::PaymentMethodType::MbWay,
Self::MobilePayRedirect(_) => api_enums::PaymentMethodType::MobilePay,
Self::PaypalRedirect(_) | Self::PaypalSdk(_) => api_enums::PaymentMethodType::Paypal,
Self::SamsungPay(_) => api_enums::PaymentMethodType::SamsungPay,
Self::TwintRedirect {} => api_enums::PaymentMethodType::Twint,
Self::VippsRedirect {} => api_enums::PaymentMethodType::Vipps,
Self::TouchNGoRedirect(_) => api_enums::PaymentMethodType::TouchNGo,
Self::WeChatPayRedirect(_) | Self::WeChatPayQr(_) => {
api_enums::PaymentMethodType::WeChatPay
}
Self::CashappQr(_) => api_enums::PaymentMethodType::Cashapp,
Self::SwishQr(_) => api_enums::PaymentMethodType::Swish,
}
}
}

impl GetPaymentMethodType for PayLaterData {
fn get_payment_method_type(&self) -> api_enums::PaymentMethodType {
match self {
Self::KlarnaRedirect { .. } => api_enums::PaymentMethodType::Klarna,
Self::KlarnaSdk { .. } => api_enums::PaymentMethodType::Klarna,
Self::AffirmRedirect {} => api_enums::PaymentMethodType::Affirm,
Self::AfterpayClearpayRedirect { .. } => api_enums::PaymentMethodType::AfterpayClearpay,
Self::PayBrightRedirect {} => api_enums::PaymentMethodType::PayBright,
Self::WalleyRedirect {} => api_enums::PaymentMethodType::Walley,
Self::AlmaRedirect {} => api_enums::PaymentMethodType::Alma,
Self::AtomeRedirect {} => api_enums::PaymentMethodType::Atome,
}
}
}

impl GetPaymentMethodType for BankRedirectData {
fn get_payment_method_type(&self) -> api_enums::PaymentMethodType {
match self {
Self::BancontactCard { .. } => api_enums::PaymentMethodType::BancontactCard,
Self::Bizum {} => api_enums::PaymentMethodType::Bizum,
Self::Blik { .. } => api_enums::PaymentMethodType::Blik,
Self::Eps { .. } => api_enums::PaymentMethodType::Eps,
Self::Giropay { .. } => api_enums::PaymentMethodType::Giropay,
Self::Ideal { .. } => api_enums::PaymentMethodType::Ideal,
Self::Interac { .. } => api_enums::PaymentMethodType::Interac,
Self::OnlineBankingCzechRepublic { .. } => {
api_enums::PaymentMethodType::OnlineBankingCzechRepublic
}
Self::OnlineBankingFinland { .. } => api_enums::PaymentMethodType::OnlineBankingFinland,
Self::OnlineBankingPoland { .. } => api_enums::PaymentMethodType::OnlineBankingPoland,
Self::OnlineBankingSlovakia { .. } => {
api_enums::PaymentMethodType::OnlineBankingSlovakia
}
Self::OpenBankingUk { .. } => api_enums::PaymentMethodType::OpenBankingUk,
Self::Przelewy24 { .. } => api_enums::PaymentMethodType::Przelewy24,
Self::Sofort { .. } => api_enums::PaymentMethodType::Sofort,
Self::Trustly { .. } => api_enums::PaymentMethodType::Trustly,
Self::OnlineBankingFpx { .. } => api_enums::PaymentMethodType::OnlineBankingFpx,
Self::OnlineBankingThailand { .. } => {
api_enums::PaymentMethodType::OnlineBankingThailand
}
}
}
}

impl GetPaymentMethodType for BankDebitData {
fn get_payment_method_type(&self) -> api_enums::PaymentMethodType {
match self {
Self::AchBankDebit { .. } => api_enums::PaymentMethodType::Ach,
Self::SepaBankDebit { .. } => api_enums::PaymentMethodType::Sepa,
Self::BecsBankDebit { .. } => api_enums::PaymentMethodType::Becs,
Self::BacsBankDebit { .. } => api_enums::PaymentMethodType::Bacs,
}
}
}

impl GetPaymentMethodType for BankTransferData {
fn get_payment_method_type(&self) -> api_enums::PaymentMethodType {
match self {
Self::AchBankTransfer { .. } => api_enums::PaymentMethodType::Ach,
Self::SepaBankTransfer { .. } => api_enums::PaymentMethodType::Sepa,
Self::BacsBankTransfer { .. } => api_enums::PaymentMethodType::Bacs,
Self::MultibancoBankTransfer { .. } => api_enums::PaymentMethodType::Multibanco,
Self::PermataBankTransfer { .. } => api_enums::PaymentMethodType::PermataBankTransfer,
Self::BcaBankTransfer { .. } => api_enums::PaymentMethodType::BcaBankTransfer,
Self::BniVaBankTransfer { .. } => api_enums::PaymentMethodType::BniVa,
Self::BriVaBankTransfer { .. } => api_enums::PaymentMethodType::BriVa,
Self::CimbVaBankTransfer { .. } => api_enums::PaymentMethodType::CimbVa,
Self::DanamonVaBankTransfer { .. } => api_enums::PaymentMethodType::DanamonVa,
Self::MandiriVaBankTransfer { .. } => api_enums::PaymentMethodType::MandiriVa,
Self::Pix {} => api_enums::PaymentMethodType::Pix,
Self::Pse {} => api_enums::PaymentMethodType::Pse,
}
}
}

impl GetPaymentMethodType for CryptoData {
fn get_payment_method_type(&self) -> api_enums::PaymentMethodType {
api_enums::PaymentMethodType::CryptoCurrency
}
}

impl GetPaymentMethodType for UpiData {
fn get_payment_method_type(&self) -> api_enums::PaymentMethodType {
api_enums::PaymentMethodType::UpiCollect
}
}
impl GetPaymentMethodType for VoucherData {
fn get_payment_method_type(&self) -> api_enums::PaymentMethodType {
match self {
Self::Boleto(_) => api_enums::PaymentMethodType::Boleto,
Self::Efecty => api_enums::PaymentMethodType::Efecty,
Self::PagoEfectivo => api_enums::PaymentMethodType::PagoEfectivo,
Self::RedCompra => api_enums::PaymentMethodType::RedCompra,
Self::RedPagos => api_enums::PaymentMethodType::RedPagos,
Self::Alfamart(_) => api_enums::PaymentMethodType::Alfamart,
Self::Indomaret(_) => api_enums::PaymentMethodType::Indomaret,
Self::Oxxo => api_enums::PaymentMethodType::Oxxo,
Self::SevenEleven(_) => api_enums::PaymentMethodType::SevenEleven,
Self::Lawson(_) => api_enums::PaymentMethodType::Lawson,
Self::MiniStop(_) => api_enums::PaymentMethodType::MiniStop,
Self::FamilyMart(_) => api_enums::PaymentMethodType::FamilyMart,
Self::Seicomart(_) => api_enums::PaymentMethodType::Seicomart,
Self::PayEasy(_) => api_enums::PaymentMethodType::PayEasy,
}
}
}
impl GetPaymentMethodType for GiftCardData {
fn get_payment_method_type(&self) -> api_enums::PaymentMethodType {
match self {
Self::Givex(_) => api_enums::PaymentMethodType::Givex,
Self::PaySafeCard {} => api_enums::PaymentMethodType::PaySafeCard,
}
}
}

#[derive(serde::Deserialize, serde::Serialize, Debug, Clone, ToSchema, Eq, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum GiftCardData {
Expand Down
1 change: 1 addition & 0 deletions crates/common_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod pii;
pub mod request;
#[cfg(feature = "signals")]
pub mod signals;
pub mod types;
pub mod validation;

/// Date-time utilities.
Expand Down
62 changes: 42 additions & 20 deletions crates/api_models/src/types.rs → crates/common_utils/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,68 @@
use common_utils::errors::{ApiModelsError, CustomResult};
use error_stack::ResultExt;
//! Types that can be used in other crates
use error_stack::{IntoReport, ResultExt};
use serde::{de::Visitor, Deserialize, Deserializer};
use utoipa::ToSchema;

#[derive(Clone, Default, Debug, PartialEq, serde::Serialize, ToSchema)]
use crate::errors::{ApiModelsError, CustomResult};

/// Represents Percentage Value between 0 and 100 both inclusive
#[derive(Clone, Default, Debug, PartialEq, serde::Serialize)]
pub struct Percentage<const PRECISION: u8> {
// this value will range from 0 to 100, decimal length defined by precision macro
/// Percentage value ranging between 0 and 100
#[schema(example = 2.5)]
percentage: f32,
}

fn get_invalid_percentage_error_message(precision: u8) -> String {
format!(
"value should be between 0 to 100 and precise to only upto {} decimal digits",
"value should be a float between 0 to 100 and precise to only upto {} decimal digits",
precision
)
}

impl<const PRECISION: u8> Percentage<PRECISION> {
pub fn from_float(value: f32) -> CustomResult<Self, ApiModelsError> {
if Self::is_valid_value(value) {
Ok(Self { percentage: value })
/// construct percentage using a string representation of float value
pub fn from_string(value: String) -> CustomResult<Self, ApiModelsError> {
if Self::is_valid_string_value(&value)? {
Ok(Self {
percentage: value
.parse()
.into_report()
.change_context(ApiModelsError::InvalidPercentageValue)?,
})
} else {
Err(ApiModelsError::InvalidPercentageValue.into())
.attach_printable(get_invalid_percentage_error_message(PRECISION))
}
}
/// function to get percentage value
pub fn get_percentage(&self) -> f32 {
self.percentage
}
fn is_valid_value(value: f32) -> bool {
Self::is_valid_range(value) && Self::is_valid_precision_length(value)
fn is_valid_string_value(value: &str) -> CustomResult<bool, ApiModelsError> {
let float_value = Self::is_valid_float_string(value)?;
Ok(Self::is_valid_range(float_value) && Self::is_valid_precision_length(value))
}
fn is_valid_float_string(value: &str) -> CustomResult<f32, ApiModelsError> {
value
.parse()
.into_report()
.change_context(ApiModelsError::InvalidPercentageValue)
}
fn is_valid_range(value: f32) -> bool {
(0.0..=100.0).contains(&value)
}
fn is_valid_precision_length(value: f32) -> bool {
let multiplier = f32::powf(10.0, PRECISION.into());
let multiplied_value = value * multiplier;
// if fraction part is 0, then the percentage value is valid
multiplied_value.fract() == 0.0
fn is_valid_precision_length(value: &str) -> bool {
if value.contains('.') {
// if string has '.' then take the decimal part and verify precision length
match value.split('.').last() {
Some(decimal_part) => decimal_part.trim_end_matches('0').len() <= PRECISION.into(),
// will never be None
None => false,
}
} else {
// if there is no '.' then it is a whole number with no decimal part. So return true
true
}
}
}

Expand All @@ -62,17 +84,17 @@ impl<'de, const PRECISION: u8> Visitor<'de> for PercentageVisitor<PRECISION> {
if percentage_value.is_some() {
return Err(serde::de::Error::duplicate_field("percentage"));
}
percentage_value = Some(map.next_value::<f32>()?);
percentage_value = Some(map.next_value::<serde_json::Value>()?);
} else {
// Ignore unknown fields
let _: serde::de::IgnoredAny = map.next_value()?;
}
}
if let Some(value) = percentage_value {
let str_value = value.to_string();
Ok(Percentage::from_float(value).map_err(|_| {
let string_value = value.to_string();
Ok(Percentage::from_string(string_value.clone()).map_err(|_| {
serde::de::Error::invalid_value(
serde::de::Unexpected::Other(&format!("percentage value `{}`", str_value)),
serde::de::Unexpected::Other(&format!("percentage value {}", string_value)),
&&*get_invalid_percentage_error_message(PRECISION),
)
})?)
Expand Down
Loading

0 comments on commit b6cda40

Please sign in to comment.