From 99824e2617c19caf6e4764fbc7b2e834992e96a1 Mon Sep 17 00:00:00 2001 From: Sahkal Poddar Date: Mon, 3 Jun 2024 17:27:32 +0530 Subject: [PATCH] refactor(connector): added amount conversion framework for cryptopay --- crates/common_utils/src/types.rs | 5 ++ crates/router/src/connector/cryptopay.rs | 47 +++++++++++++++---- .../src/connector/cryptopay/transformers.rs | 43 ++++++++--------- crates/router/src/types/api.rs | 2 +- crates/router/tests/connectors/cryptopay.rs | 2 +- 5 files changed, 66 insertions(+), 33 deletions(-) diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 8e15997de396..f638b632ba29 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -565,6 +565,11 @@ impl StringMajorUnit { .ok_or(ParsingError::DecimalToI64ConversionFailure)?; Ok(MinorUnit::new(amount_i64)) } + + /// Get string amount from struct to be removed in future + pub fn get_amount_as_string(&self) -> String { + self.0.clone() + } } #[cfg(test)] diff --git a/crates/router/src/connector/cryptopay.rs b/crates/router/src/connector/cryptopay.rs index f7d137eff208..5b3b019a6bc6 100644 --- a/crates/router/src/connector/cryptopay.rs +++ b/crates/router/src/connector/cryptopay.rs @@ -1,13 +1,12 @@ pub mod transformers; -use std::fmt::Debug; - use base64::Engine; use common_utils::{ crypto::{self, GenerateDigest, SignMessage}, date_time, ext_traits::ByteSliceExt, request::RequestContent, + types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector}, }; use error_stack::ResultExt; use hex::encode; @@ -36,8 +35,18 @@ use crate::{ utils::BytesExt, }; -#[derive(Debug, Clone)] -pub struct Cryptopay; +#[derive(Clone)] +pub struct Cryptopay { + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Cryptopay { + pub fn new() -> &'static Self { + &Self { + amount_converter: &StringMajorUnitForConnector, + } + } +} impl api::Payment for Cryptopay {} impl api::PaymentSession for Cryptopay {} @@ -123,7 +132,7 @@ where (headers::DATE.to_string(), date.into()), ( headers::CONTENT_TYPE.to_string(), - Self.get_content_type().to_string().into(), + self.get_content_type().to_string().into(), ), ]; Ok(headers) @@ -244,12 +253,12 @@ impl ConnectorIntegration CustomResult { - let connector_router_data = cryptopay::CryptopayRouterData::try_from(( - &self.get_currency_unit(), + let amount = utils::convert_amount( + self.amount_converter, + req.request.minor_amount, req.request.currency, - req.request.amount, - req, - ))?; + )?; + let connector_router_data = cryptopay::CryptopayRouterData::try_from((amount, req))?; let connector_req = cryptopay::CryptopayPaymentsRequest::try_from(&connector_router_data)?; Ok(RequestContent::Json(Box::new(connector_req))) } @@ -288,6 +297,14 @@ impl ConnectorIntegration Some(utils::convert_back( + self.amount_converter, + amount.clone(), + data.request.currency, + )?), + None => None, + }; types::RouterData::foreign_try_from(( types::ResponseRouterData { response, @@ -295,6 +312,7 @@ impl ConnectorIntegration Some(utils::convert_back( + self.amount_converter, + amount.clone(), + data.request.currency, + )?), + None => None, + }; types::RouterData::foreign_try_from(( types::ResponseRouterData { response, @@ -382,6 +408,7 @@ impl ConnectorIntegration { - pub amount: String, + pub amount: StringMajorUnit, pub router_data: T, } -impl TryFrom<(&types::api::CurrencyUnit, enums::Currency, i64, T)> for CryptopayRouterData { +impl TryFrom<(StringMajorUnit, T)> for CryptopayRouterData { type Error = error_stack::Report; - fn try_from( - (currency_unit, currency, amount, item): ( - &types::api::CurrencyUnit, - enums::Currency, - i64, - T, - ), - ) -> Result { - let amount = utils::get_amount_as_string(currency_unit, amount, currency)?; + fn try_from((amount, item): (StringMajorUnit, T)) -> Result { Ok(Self { amount, router_data: item, @@ -39,7 +34,7 @@ impl TryFrom<(&types::api::CurrencyUnit, enums::Currency, i64, T)> for Crypto #[derive(Default, Debug, Serialize)] pub struct CryptopayPaymentsRequest { - price_amount: String, + price_amount: StringMajorUnit, price_currency: enums::Currency, pay_currency: String, #[serde(skip_serializing_if = "Option::is_none")] @@ -62,7 +57,7 @@ impl TryFrom<&CryptopayRouterData<&types::PaymentsAuthorizeRouterData>> domain::PaymentMethodData::Crypto(ref cryptodata) => { let pay_currency = cryptodata.get_pay_currency()?; Ok(Self { - price_amount: item.amount.to_owned(), + price_amount: item.amount.clone(), price_currency: item.router_data.request.currency, pay_currency, network: cryptodata.network.to_owned(), @@ -140,20 +135,22 @@ impl From for enums::AttemptStatus { #[derive(Debug, Serialize, Deserialize)] pub struct CryptopayPaymentsResponse { - data: CryptopayPaymentResponseData, + pub data: CryptopayPaymentResponseData, } impl ForeignTryFrom<( types::ResponseRouterData, diesel_models::enums::Currency, + Option, )> for types::RouterData { type Error = error_stack::Report; fn foreign_try_from( - (item, currency): ( + (item, currency, amount_captured_core): ( types::ResponseRouterData, diesel_models::enums::Currency, + Option, ), ) -> Result { let status = enums::AttemptStatus::from(item.response.data.status.clone()); @@ -200,15 +197,19 @@ impl match item.response.data.price_amount { Some(price_amount) => { let amount_captured = Some( - connector_utils::to_currency_lower_unit(price_amount, currency)? - .parse::() - .change_context(errors::ConnectorError::ParsingFailed)?, + connector_utils::to_currency_lower_unit( + price_amount.get_amount_as_string(), + currency, + )? + .parse::() + .change_context(errors::ConnectorError::ParsingFailed)?, ); Ok(Self { status, response, amount_captured, + minor_amount_captured: amount_captured_core, ..item.data }) } @@ -243,9 +244,9 @@ pub struct CryptopayPaymentResponseData { pub address: Option>, pub network: Option, pub uri: Option, - pub price_amount: Option, + pub price_amount: Option, pub price_currency: Option, - pub pay_amount: Option, + pub pay_amount: Option, pub pay_currency: Option, pub fee: Option, pub fee_currency: Option, diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index feee7f3c071f..f73c643e0c6f 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -328,7 +328,7 @@ impl ConnectorData { 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::Cryptopay => Ok(Box::new(connector::Cryptopay::new())), enums::Connector::Cybersource => Ok(Box::new(&connector::Cybersource)), enums::Connector::Dlocal => Ok(Box::new(&connector::Dlocal)), #[cfg(feature = "dummy_connector")] diff --git a/crates/router/tests/connectors/cryptopay.rs b/crates/router/tests/connectors/cryptopay.rs index 20c727756e76..988c704249af 100644 --- a/crates/router/tests/connectors/cryptopay.rs +++ b/crates/router/tests/connectors/cryptopay.rs @@ -13,7 +13,7 @@ impl utils::Connector for CryptopayTest { fn get_data(&self) -> api::ConnectorData { use router::connector::Cryptopay; api::ConnectorData { - connector: Box::new(&Cryptopay), + connector: Box::new(Cryptopay::new()), connector_name: types::Connector::Cryptopay, get_token: api::GetToken::Connector, merchant_connector_id: None,