refactor(connector): [CRYPTOPAY] amount conversion framework added (#4928)

Co-authored-by: Sahkal Poddar <sahkal.poddar@juspay.in>
Co-authored-by: Deepanshu Bansal <deepanshu.bansal@Deepanshu-Bansal-K3PYF02LFW.local>
This commit is contained in:
DEEPANSHU BANSAL
2024-06-10 17:19:44 +05:30
committed by GitHub
parent 7085a46271
commit adb9b11f69
4 changed files with 59 additions and 48 deletions

View File

@ -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<Output = StringMajorUnit> + 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<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::from((amount, req));
let connector_req = cryptopay::CryptopayPaymentsRequest::try_from(&connector_router_data)?;
Ok(RequestContent::Json(Box::new(connector_req)))
}
@ -288,13 +297,21 @@ 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_in_minor_units = 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_in_minor_units,
))
}
@ -375,13 +392,21 @@ 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_in_minor_units = 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_in_minor_units,
))
}

View File

@ -1,10 +1,11 @@
use common_utils::pii;
use error_stack::ResultExt;
use common_utils::{
pii,
types::{MinorUnit, StringMajorUnit},
};
use masking::Secret;
use reqwest::Url;
use serde::{Deserialize, Serialize};
use super::utils as connector_utils;
use crate::{
connector::utils::{self, is_payment_failure, CryptoData, PaymentsAuthorizeRequestData},
consts,
@ -15,31 +16,22 @@ 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> {
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)?;
Ok(Self {
impl<T> From<(StringMajorUnit, T)> for CryptopayRouterData<T> {
fn from((amount, item): (StringMajorUnit, T)) -> Self {
Self {
amount,
router_data: item,
})
}
}
}
#[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 +54,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 +132,20 @@ 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, amount_captured_in_minor_units): (
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());
@ -196,15 +188,9 @@ impl<F, T>
charge_id: None,
})
};
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)?,
);
match amount_captured_in_minor_units {
Some(minor_amount) => {
let amount_captured = Some(minor_amount.get_amount_as_i64());
Ok(Self {
status,
response,
@ -243,9 +229,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>,

View File

@ -329,7 +329,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")]

View File

@ -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,