Skip to content

Commit

Permalink
refactor(connector): added amount conversion framework for cryptopay
Browse files Browse the repository at this point in the history
  • Loading branch information
sahkal committed Jun 3, 2024
1 parent 66dba1d commit 99824e2
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 33 deletions.
5 changes: 5 additions & 0 deletions crates/common_utils/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
47 changes: 37 additions & 10 deletions crates/router/src/connector/cryptopay.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -36,8 +35,18 @@ use crate::{
utils::BytesExt,
};

#[derive(Debug, Clone)]
pub struct Cryptopay;
#[derive(Clone)]
pub struct Cryptopay {
amount_converter: &'static (dyn AmountConvertor<Output = StringMajorUnit> + Sync),
}

impl Cryptopay {
pub fn new() -> &'static Self {
&Self {
amount_converter: &StringMajorUnitForConnector,
}
}
}

impl api::Payment for Cryptopay {}
impl api::PaymentSession for Cryptopay {}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -244,12 +253,12 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
req: &types::PaymentsAuthorizeRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<RequestContent, errors::ConnectorError> {
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)))
}
Expand Down Expand Up @@ -288,13 +297,22 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);
let capture_amount_core = match response.data.price_amount {
Some(ref amount) => Some(utils::convert_back(
self.amount_converter,
amount.clone(),
data.request.currency,
)?),
None => None,
};
types::RouterData::foreign_try_from((
types::ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
},
data.request.currency,
capture_amount_core,
))
}

Expand Down Expand Up @@ -375,13 +393,22 @@ impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsRe
.change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
event_builder.map(|i| i.set_response_body(&response));
router_env::logger::info!(connector_response=?response);
let capture_amount_core = match response.data.price_amount {
Some(ref amount) => Some(utils::convert_back(
self.amount_converter,
amount.clone(),
data.request.currency,
)?),
None => None,
};
types::RouterData::foreign_try_from((
types::ResponseRouterData {
response,
data: data.clone(),
http_code: res.status_code,
},
data.request.currency,
capture_amount_core,
))
}

Expand Down
43 changes: 22 additions & 21 deletions crates/router/src/connector/cryptopay/transformers.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use common_utils::pii;
use common_utils::{
pii,
types::{MinorUnit, StringMajorUnit},
};
use error_stack::ResultExt;
use masking::Secret;
use reqwest::Url;
Expand All @@ -15,21 +18,13 @@ use crate::{

#[derive(Debug, Serialize)]
pub struct CryptopayRouterData<T> {
pub amount: String,
pub amount: StringMajorUnit,
pub router_data: T,
}

impl<T> TryFrom<(&types::api::CurrencyUnit, enums::Currency, i64, T)> for CryptopayRouterData<T> {
impl<T> TryFrom<(StringMajorUnit, T)> for CryptopayRouterData<T> {
type Error = error_stack::Report<errors::ConnectorError>;
fn try_from(
(currency_unit, currency, amount, item): (
&types::api::CurrencyUnit,
enums::Currency,
i64,
T,
),
) -> Result<Self, Self::Error> {
let amount = utils::get_amount_as_string(currency_unit, amount, currency)?;
fn try_from((amount, item): (StringMajorUnit, T)) -> Result<Self, Self::Error> {
Ok(Self {
amount,
router_data: item,
Expand All @@ -39,7 +34,7 @@ impl<T> 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")]
Expand All @@ -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(),
Expand Down Expand Up @@ -140,20 +135,22 @@ impl From<CryptopayPaymentStatus> for enums::AttemptStatus {

#[derive(Debug, Serialize, Deserialize)]
pub struct CryptopayPaymentsResponse {
data: CryptopayPaymentResponseData,
pub data: CryptopayPaymentResponseData,
}

impl<F, T>
ForeignTryFrom<(
types::ResponseRouterData<F, CryptopayPaymentsResponse, T, types::PaymentsResponseData>,
diesel_models::enums::Currency,
Option<MinorUnit>,
)> for types::RouterData<F, T, types::PaymentsResponseData>
{
type Error = error_stack::Report<errors::ConnectorError>;
fn foreign_try_from(
(item, currency): (
(item, currency, amount_captured_core): (
types::ResponseRouterData<F, CryptopayPaymentsResponse, T, types::PaymentsResponseData>,
diesel_models::enums::Currency,
Option<MinorUnit>,
),
) -> Result<Self, Self::Error> {
let status = enums::AttemptStatus::from(item.response.data.status.clone());
Expand Down Expand Up @@ -200,15 +197,19 @@ impl<F, T>
match item.response.data.price_amount {
Some(price_amount) => {
let amount_captured = Some(
connector_utils::to_currency_lower_unit(price_amount, currency)?
.parse::<i64>()
.change_context(errors::ConnectorError::ParsingFailed)?,
connector_utils::to_currency_lower_unit(
price_amount.get_amount_as_string(),
currency,
)?
.parse::<i64>()
.change_context(errors::ConnectorError::ParsingFailed)?,
);

Ok(Self {
status,
response,
amount_captured,
minor_amount_captured: amount_captured_core,
..item.data
})
}
Expand Down Expand Up @@ -243,9 +244,9 @@ pub struct CryptopayPaymentResponseData {
pub address: Option<Secret<String>>,
pub network: Option<String>,
pub uri: Option<String>,
pub price_amount: Option<String>,
pub price_amount: Option<StringMajorUnit>,
pub price_currency: Option<String>,
pub pay_amount: Option<String>,
pub pay_amount: Option<StringMajorUnit>,
pub pay_currency: Option<String>,
pub fee: Option<String>,
pub fee_currency: Option<String>,
Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/types/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
2 changes: 1 addition & 1 deletion crates/router/tests/connectors/cryptopay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 99824e2

Please sign in to comment.