mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-28 12:15:40 +08:00
refactor(connector): add amount conversion framework to cybersource (#6335)
Co-authored-by: DEEPANSHU BANSAL <41580413+deepanshu-iiitu@users.noreply.github.com>
This commit is contained in:
@ -601,7 +601,6 @@ impl StringMajorUnit {
|
|||||||
pub fn zero() -> Self {
|
pub fn zero() -> Self {
|
||||||
Self("0".to_string())
|
Self("0".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get string amount from struct to be removed in future
|
/// Get string amount from struct to be removed in future
|
||||||
pub fn get_amount_as_string(&self) -> String {
|
pub fn get_amount_as_string(&self) -> String {
|
||||||
self.0.clone()
|
self.0.clone()
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
pub mod transformers;
|
pub mod transformers;
|
||||||
|
|
||||||
use std::fmt::Debug;
|
|
||||||
|
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use common_utils::request::RequestContent;
|
use common_utils::{
|
||||||
|
request::RequestContent,
|
||||||
|
types::{AmountConvertor, MinorUnit, StringMajorUnit, StringMajorUnitForConnector},
|
||||||
|
};
|
||||||
use diesel_models::enums;
|
use diesel_models::enums;
|
||||||
use error_stack::{report, Report, ResultExt};
|
use error_stack::{report, Report, ResultExt};
|
||||||
use masking::{ExposeInterface, PeekInterface};
|
use masking::{ExposeInterface, PeekInterface};
|
||||||
@ -12,7 +13,7 @@ use time::OffsetDateTime;
|
|||||||
use transformers as cybersource;
|
use transformers as cybersource;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use super::utils::{PaymentsAuthorizeRequestData, RouterData};
|
use super::utils::{convert_amount, PaymentsAuthorizeRequestData, RouterData};
|
||||||
use crate::{
|
use crate::{
|
||||||
configs::settings,
|
configs::settings,
|
||||||
connector::{
|
connector::{
|
||||||
@ -36,9 +37,18 @@ use crate::{
|
|||||||
utils::BytesExt,
|
utils::BytesExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Cybersource;
|
pub struct Cybersource {
|
||||||
|
amount_converter: &'static (dyn AmountConvertor<Output = StringMajorUnit> + Sync),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cybersource {
|
||||||
|
pub fn new() -> &'static Self {
|
||||||
|
&Self {
|
||||||
|
amount_converter: &StringMajorUnitForConnector,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Cybersource {
|
impl Cybersource {
|
||||||
pub fn generate_digest(&self, payload: &[u8]) -> String {
|
pub fn generate_digest(&self, payload: &[u8]) -> String {
|
||||||
let payload_digest = digest::digest(&digest::SHA256, payload);
|
let payload_digest = digest::digest(&digest::SHA256, payload);
|
||||||
@ -617,20 +627,20 @@ impl
|
|||||||
req: &types::PaymentsPreProcessingRouterData,
|
req: &types::PaymentsPreProcessingRouterData,
|
||||||
_connectors: &settings::Connectors,
|
_connectors: &settings::Connectors,
|
||||||
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
||||||
let connector_router_data = cybersource::CybersourceRouterData::try_from((
|
let minor_amount =
|
||||||
&self.get_currency_unit(),
|
req.request
|
||||||
|
.minor_amount
|
||||||
|
.ok_or(errors::ConnectorError::MissingRequiredField {
|
||||||
|
field_name: "minor_amount",
|
||||||
|
})?;
|
||||||
|
let currency =
|
||||||
req.request
|
req.request
|
||||||
.currency
|
.currency
|
||||||
.ok_or(errors::ConnectorError::MissingRequiredField {
|
.ok_or(errors::ConnectorError::MissingRequiredField {
|
||||||
field_name: "currency",
|
field_name: "currency",
|
||||||
})?,
|
})?;
|
||||||
req.request
|
let amount = convert_amount(self.amount_converter, minor_amount, currency)?;
|
||||||
.amount
|
let connector_router_data = cybersource::CybersourceRouterData::from((amount, req));
|
||||||
.ok_or(errors::ConnectorError::MissingRequiredField {
|
|
||||||
field_name: "amount",
|
|
||||||
})?,
|
|
||||||
req,
|
|
||||||
))?;
|
|
||||||
let connector_req =
|
let connector_req =
|
||||||
cybersource::CybersourcePreProcessingRequest::try_from(&connector_router_data)?;
|
cybersource::CybersourcePreProcessingRequest::try_from(&connector_router_data)?;
|
||||||
Ok(RequestContent::Json(Box::new(connector_req)))
|
Ok(RequestContent::Json(Box::new(connector_req)))
|
||||||
@ -718,12 +728,12 @@ impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::Payme
|
|||||||
req: &types::PaymentsCaptureRouterData,
|
req: &types::PaymentsCaptureRouterData,
|
||||||
_connectors: &settings::Connectors,
|
_connectors: &settings::Connectors,
|
||||||
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
||||||
let connector_router_data = cybersource::CybersourceRouterData::try_from((
|
let amount = convert_amount(
|
||||||
&self.get_currency_unit(),
|
self.amount_converter,
|
||||||
|
req.request.minor_amount_to_capture,
|
||||||
req.request.currency,
|
req.request.currency,
|
||||||
req.request.amount_to_capture,
|
)?;
|
||||||
req,
|
let connector_router_data = cybersource::CybersourceRouterData::from((amount, req));
|
||||||
))?;
|
|
||||||
let connector_req =
|
let connector_req =
|
||||||
cybersource::CybersourcePaymentsCaptureRequest::try_from(&connector_router_data)?;
|
cybersource::CybersourcePaymentsCaptureRequest::try_from(&connector_router_data)?;
|
||||||
Ok(RequestContent::Json(Box::new(connector_req)))
|
Ok(RequestContent::Json(Box::new(connector_req)))
|
||||||
@ -922,12 +932,12 @@ impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::P
|
|||||||
req: &types::PaymentsAuthorizeRouterData,
|
req: &types::PaymentsAuthorizeRouterData,
|
||||||
_connectors: &settings::Connectors,
|
_connectors: &settings::Connectors,
|
||||||
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
||||||
let connector_router_data = cybersource::CybersourceRouterData::try_from((
|
let amount = convert_amount(
|
||||||
&self.get_currency_unit(),
|
self.amount_converter,
|
||||||
|
req.request.minor_amount,
|
||||||
req.request.currency,
|
req.request.currency,
|
||||||
req.request.amount,
|
)?;
|
||||||
req,
|
let connector_router_data = cybersource::CybersourceRouterData::from((amount, req));
|
||||||
))?;
|
|
||||||
if req.is_three_ds()
|
if req.is_three_ds()
|
||||||
&& req.request.is_card()
|
&& req.request.is_card()
|
||||||
&& (req.request.connector_mandate_id().is_none()
|
&& (req.request.connector_mandate_id().is_none()
|
||||||
@ -1068,12 +1078,12 @@ impl ConnectorIntegration<api::PoFulfill, types::PayoutsData, types::PayoutsResp
|
|||||||
req: &types::PayoutsRouterData<api::PoFulfill>,
|
req: &types::PayoutsRouterData<api::PoFulfill>,
|
||||||
_connectors: &settings::Connectors,
|
_connectors: &settings::Connectors,
|
||||||
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
||||||
let connector_router_data = cybersource::CybersourceRouterData::try_from((
|
let amount = convert_amount(
|
||||||
&self.get_currency_unit(),
|
self.amount_converter,
|
||||||
|
req.request.minor_amount,
|
||||||
req.request.destination_currency,
|
req.request.destination_currency,
|
||||||
req.request.amount,
|
)?;
|
||||||
req,
|
let connector_router_data = cybersource::CybersourceRouterData::from((amount, req));
|
||||||
))?;
|
|
||||||
let connector_req =
|
let connector_req =
|
||||||
cybersource::CybersourcePayoutFulfillRequest::try_from(&connector_router_data)?;
|
cybersource::CybersourcePayoutFulfillRequest::try_from(&connector_router_data)?;
|
||||||
Ok(RequestContent::Json(Box::new(connector_req)))
|
Ok(RequestContent::Json(Box::new(connector_req)))
|
||||||
@ -1193,12 +1203,12 @@ impl
|
|||||||
req: &types::PaymentsCompleteAuthorizeRouterData,
|
req: &types::PaymentsCompleteAuthorizeRouterData,
|
||||||
_connectors: &settings::Connectors,
|
_connectors: &settings::Connectors,
|
||||||
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
||||||
let connector_router_data = cybersource::CybersourceRouterData::try_from((
|
let amount = convert_amount(
|
||||||
&self.get_currency_unit(),
|
self.amount_converter,
|
||||||
|
req.request.minor_amount,
|
||||||
req.request.currency,
|
req.request.currency,
|
||||||
req.request.amount,
|
)?;
|
||||||
req,
|
let connector_router_data = cybersource::CybersourceRouterData::from((amount, req));
|
||||||
))?;
|
|
||||||
let connector_req =
|
let connector_req =
|
||||||
cybersource::CybersourcePaymentsRequest::try_from(&connector_router_data)?;
|
cybersource::CybersourcePaymentsRequest::try_from(&connector_router_data)?;
|
||||||
Ok(RequestContent::Json(Box::new(connector_req)))
|
Ok(RequestContent::Json(Box::new(connector_req)))
|
||||||
@ -1317,20 +1327,21 @@ impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsR
|
|||||||
req: &types::PaymentsCancelRouterData,
|
req: &types::PaymentsCancelRouterData,
|
||||||
_connectors: &settings::Connectors,
|
_connectors: &settings::Connectors,
|
||||||
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
||||||
let connector_router_data = cybersource::CybersourceRouterData::try_from((
|
let minor_amount =
|
||||||
&self.get_currency_unit(),
|
req.request
|
||||||
|
.minor_amount
|
||||||
|
.ok_or(errors::ConnectorError::MissingRequiredField {
|
||||||
|
field_name: "Amount",
|
||||||
|
})?;
|
||||||
|
let currency =
|
||||||
req.request
|
req.request
|
||||||
.currency
|
.currency
|
||||||
.ok_or(errors::ConnectorError::MissingRequiredField {
|
.ok_or(errors::ConnectorError::MissingRequiredField {
|
||||||
field_name: "Currency",
|
field_name: "Currency",
|
||||||
})?,
|
})?;
|
||||||
req.request
|
let amount = convert_amount(self.amount_converter, minor_amount, currency)?;
|
||||||
.amount
|
let connector_router_data = cybersource::CybersourceRouterData::from((amount, req));
|
||||||
.ok_or(errors::ConnectorError::MissingRequiredField {
|
|
||||||
field_name: "Amount",
|
|
||||||
})?,
|
|
||||||
req,
|
|
||||||
))?;
|
|
||||||
let connector_req = cybersource::CybersourceVoidRequest::try_from(&connector_router_data)?;
|
let connector_req = cybersource::CybersourceVoidRequest::try_from(&connector_router_data)?;
|
||||||
|
|
||||||
Ok(RequestContent::Json(Box::new(connector_req)))
|
Ok(RequestContent::Json(Box::new(connector_req)))
|
||||||
@ -1443,12 +1454,12 @@ impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsRespon
|
|||||||
req: &types::RefundExecuteRouterData,
|
req: &types::RefundExecuteRouterData,
|
||||||
_connectors: &settings::Connectors,
|
_connectors: &settings::Connectors,
|
||||||
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
||||||
let connector_router_data = cybersource::CybersourceRouterData::try_from((
|
let refund_amount = convert_amount(
|
||||||
&self.get_currency_unit(),
|
self.amount_converter,
|
||||||
|
req.request.minor_refund_amount,
|
||||||
req.request.currency,
|
req.request.currency,
|
||||||
req.request.refund_amount,
|
)?;
|
||||||
req,
|
let connector_router_data = cybersource::CybersourceRouterData::from((refund_amount, req));
|
||||||
))?;
|
|
||||||
let connector_req =
|
let connector_req =
|
||||||
cybersource::CybersourceRefundRequest::try_from(&connector_router_data)?;
|
cybersource::CybersourceRefundRequest::try_from(&connector_router_data)?;
|
||||||
Ok(RequestContent::Json(Box::new(connector_req)))
|
Ok(RequestContent::Json(Box::new(connector_req)))
|
||||||
@ -1609,12 +1620,14 @@ impl
|
|||||||
req: &types::PaymentsIncrementalAuthorizationRouterData,
|
req: &types::PaymentsIncrementalAuthorizationRouterData,
|
||||||
_connectors: &settings::Connectors,
|
_connectors: &settings::Connectors,
|
||||||
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
) -> CustomResult<RequestContent, errors::ConnectorError> {
|
||||||
let connector_router_data = cybersource::CybersourceRouterData::try_from((
|
let minor_additional_amount = MinorUnit::new(req.request.additional_amount);
|
||||||
&self.get_currency_unit(),
|
let additional_amount = convert_amount(
|
||||||
|
self.amount_converter,
|
||||||
|
minor_additional_amount,
|
||||||
req.request.currency,
|
req.request.currency,
|
||||||
req.request.additional_amount,
|
)?;
|
||||||
req,
|
let connector_router_data =
|
||||||
))?;
|
cybersource::CybersourceRouterData::from((additional_amount, req));
|
||||||
let connector_request =
|
let connector_request =
|
||||||
cybersource::CybersourcePaymentsIncrementalAuthorizationRequest::try_from(
|
cybersource::CybersourcePaymentsIncrementalAuthorizationRequest::try_from(
|
||||||
&connector_router_data,
|
&connector_router_data,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use common_enums::FutureUsage;
|
|||||||
use common_utils::{
|
use common_utils::{
|
||||||
ext_traits::{OptionExt, ValueExt},
|
ext_traits::{OptionExt, ValueExt},
|
||||||
pii,
|
pii,
|
||||||
types::SemanticVersion,
|
types::{SemanticVersion, StringMajorUnit},
|
||||||
};
|
};
|
||||||
use error_stack::ResultExt;
|
use error_stack::ResultExt;
|
||||||
#[cfg(feature = "payouts")]
|
#[cfg(feature = "payouts")]
|
||||||
@ -40,21 +40,16 @@ use crate::{
|
|||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct CybersourceRouterData<T> {
|
pub struct CybersourceRouterData<T> {
|
||||||
pub amount: String,
|
pub amount: StringMajorUnit,
|
||||||
pub router_data: T,
|
pub router_data: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for CybersourceRouterData<T> {
|
impl<T> From<(StringMajorUnit, T)> for CybersourceRouterData<T> {
|
||||||
type Error = error_stack::Report<errors::ConnectorError>;
|
fn from((amount, router_data): (StringMajorUnit, T)) -> Self {
|
||||||
fn try_from(
|
Self {
|
||||||
(currency_unit, currency, amount, item): (&api::CurrencyUnit, enums::Currency, i64, T),
|
|
||||||
) -> Result<Self, Self::Error> {
|
|
||||||
// This conversion function is used at different places in the file, if updating this, keep a check for those
|
|
||||||
let amount = utils::get_amount_as_string(currency_unit, amount, currency)?;
|
|
||||||
Ok(Self {
|
|
||||||
amount,
|
amount,
|
||||||
router_data: item,
|
router_data,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +87,7 @@ impl TryFrom<&types::SetupMandateRouterData> for CybersourceZeroMandateRequest {
|
|||||||
|
|
||||||
let order_information = OrderInformationWithBill {
|
let order_information = OrderInformationWithBill {
|
||||||
amount_details: Amount {
|
amount_details: Amount {
|
||||||
total_amount: "0".to_string(),
|
total_amount: StringMajorUnit::zero(),
|
||||||
currency: item.request.currency,
|
currency: item.request.currency,
|
||||||
},
|
},
|
||||||
bill_to: Some(bill_to),
|
bill_to: Some(bill_to),
|
||||||
@ -525,14 +520,14 @@ pub struct OrderInformation {
|
|||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Amount {
|
pub struct Amount {
|
||||||
total_amount: String,
|
total_amount: StringMajorUnit,
|
||||||
currency: api_models::enums::Currency,
|
currency: api_models::enums::Currency,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct AdditionalAmount {
|
pub struct AdditionalAmount {
|
||||||
additional_amount: String,
|
additional_amount: StringMajorUnit,
|
||||||
currency: String,
|
currency: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -367,7 +367,7 @@ impl ConnectorData {
|
|||||||
Ok(ConnectorEnum::Old(Box::new(connector::Cryptopay::new())))
|
Ok(ConnectorEnum::Old(Box::new(connector::Cryptopay::new())))
|
||||||
}
|
}
|
||||||
enums::Connector::Cybersource => {
|
enums::Connector::Cybersource => {
|
||||||
Ok(ConnectorEnum::Old(Box::new(&connector::Cybersource)))
|
Ok(ConnectorEnum::Old(Box::new(connector::Cybersource::new())))
|
||||||
}
|
}
|
||||||
enums::Connector::Datatrans => {
|
enums::Connector::Datatrans => {
|
||||||
Ok(ConnectorEnum::Old(Box::new(connector::Datatrans::new())))
|
Ok(ConnectorEnum::Old(Box::new(connector::Datatrans::new())))
|
||||||
|
|||||||
@ -15,7 +15,7 @@ impl utils::Connector for Cybersource {
|
|||||||
fn get_data(&self) -> api::ConnectorData {
|
fn get_data(&self) -> api::ConnectorData {
|
||||||
use router::connector::Cybersource;
|
use router::connector::Cybersource;
|
||||||
utils::construct_connector_data_old(
|
utils::construct_connector_data_old(
|
||||||
Box::new(&Cybersource),
|
Box::new(Cybersource::new()),
|
||||||
types::Connector::Cybersource,
|
types::Connector::Cybersource,
|
||||||
api::GetToken::Connector,
|
api::GetToken::Connector,
|
||||||
None,
|
None,
|
||||||
|
|||||||
Reference in New Issue
Block a user