Skip to content

Commit 4352101

Browse files
itsharshvbHarshvardhan Bahukhandi
andauthored
refactor(connector): [FISERV, HELCIM] Add amount conversion framework to Fiserv, Helcim (#7336)
Co-authored-by: Harshvardhan Bahukhandi <[email protected]>
1 parent 833da1c commit 4352101

File tree

8 files changed

+93
-92
lines changed

8 files changed

+93
-92
lines changed

crates/hyperswitch_connectors/src/connectors/fiserv.rs

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
pub mod transformers;
22

3-
use std::fmt::Debug;
4-
53
use base64::Engine;
64
use common_enums::enums;
75
use common_utils::{
86
errors::CustomResult,
97
ext_traits::BytesExt,
108
request::{Method, Request, RequestBuilder, RequestContent},
9+
types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector},
1110
};
1211
use error_stack::{report, ResultExt};
1312
use hyperswitch_domain_models::{
@@ -44,12 +43,23 @@ use time::OffsetDateTime;
4443
use transformers as fiserv;
4544
use uuid::Uuid;
4645

47-
use crate::{constants::headers, types::ResponseRouterData, utils};
46+
use crate::{
47+
constants::headers,
48+
types::ResponseRouterData,
49+
utils::{construct_not_implemented_error_report, convert_amount},
50+
};
4851

49-
#[derive(Debug, Clone)]
50-
pub struct Fiserv;
52+
#[derive(Clone)]
53+
pub struct Fiserv {
54+
amount_converter: &'static (dyn AmountConvertor<Output = FloatMajorUnit> + Sync),
55+
}
5156

5257
impl Fiserv {
58+
pub fn new() -> &'static Self {
59+
&Self {
60+
amount_converter: &FloatMajorUnitForConnector,
61+
}
62+
}
5363
pub fn generate_authorization_signature(
5464
&self,
5565
auth: fiserv::FiservAuthType,
@@ -194,7 +204,7 @@ impl ConnectorValidation for Fiserv {
194204
| enums::CaptureMethod::Manual
195205
| enums::CaptureMethod::SequentialAutomatic => Ok(()),
196206
enums::CaptureMethod::ManualMultiple | enums::CaptureMethod::Scheduled => Err(
197-
utils::construct_not_implemented_error_report(capture_method, self.id()),
207+
construct_not_implemented_error_report(capture_method, self.id()),
198208
),
199209
}
200210
}
@@ -421,12 +431,12 @@ impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> fo
421431
req: &PaymentsCaptureRouterData,
422432
_connectors: &Connectors,
423433
) -> CustomResult<RequestContent, errors::ConnectorError> {
424-
let router_obj = fiserv::FiservRouterData::try_from((
425-
&self.get_currency_unit(),
434+
let amount_to_capture = convert_amount(
435+
self.amount_converter,
436+
req.request.minor_amount_to_capture,
426437
req.request.currency,
427-
req.request.amount_to_capture,
428-
req,
429-
))?;
438+
)?;
439+
let router_obj = fiserv::FiservRouterData::try_from((amount_to_capture, req))?;
430440
let connector_req = fiserv::FiservCaptureRequest::try_from(&router_obj)?;
431441
Ok(RequestContent::Json(Box::new(connector_req)))
432442
}
@@ -530,12 +540,12 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
530540
req: &PaymentsAuthorizeRouterData,
531541
_connectors: &Connectors,
532542
) -> CustomResult<RequestContent, errors::ConnectorError> {
533-
let router_obj = fiserv::FiservRouterData::try_from((
534-
&self.get_currency_unit(),
543+
let amount = convert_amount(
544+
self.amount_converter,
545+
req.request.minor_amount,
535546
req.request.currency,
536-
req.request.amount,
537-
req,
538-
))?;
547+
)?;
548+
let router_obj = fiserv::FiservRouterData::try_from((amount, req))?;
539549
let connector_req = fiserv::FiservPaymentsRequest::try_from(&router_obj)?;
540550
Ok(RequestContent::Json(Box::new(connector_req)))
541551
}
@@ -624,12 +634,12 @@ impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Fiserv
624634
req: &RefundsRouterData<Execute>,
625635
_connectors: &Connectors,
626636
) -> CustomResult<RequestContent, errors::ConnectorError> {
627-
let router_obj = fiserv::FiservRouterData::try_from((
628-
&self.get_currency_unit(),
637+
let refund_amount = convert_amount(
638+
self.amount_converter,
639+
req.request.minor_refund_amount,
629640
req.request.currency,
630-
req.request.refund_amount,
631-
req,
632-
))?;
641+
)?;
642+
let router_obj = fiserv::FiservRouterData::try_from((refund_amount, req))?;
633643
let connector_req = fiserv::FiservRefundRequest::try_from(&router_obj)?;
634644
Ok(RequestContent::Json(Box::new(connector_req)))
635645
}

crates/hyperswitch_connectors/src/connectors/fiserv/transformers.rs

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use common_enums::enums;
2-
use common_utils::{ext_traits::ValueExt, pii};
2+
use common_utils::{ext_traits::ValueExt, pii, types::FloatMajorUnit};
33
use error_stack::ResultExt;
44
use hyperswitch_domain_models::{
55
payment_method_data::PaymentMethodData,
@@ -9,7 +9,7 @@ use hyperswitch_domain_models::{
99
router_response_types::{PaymentsResponseData, RefundsResponseData},
1010
types,
1111
};
12-
use hyperswitch_interfaces::{api, errors};
12+
use hyperswitch_interfaces::errors;
1313
use masking::Secret;
1414
use serde::{Deserialize, Serialize};
1515

@@ -23,22 +23,14 @@ use crate::{
2323

2424
#[derive(Debug, Serialize)]
2525
pub struct FiservRouterData<T> {
26-
pub amount: String,
26+
pub amount: FloatMajorUnit,
2727
pub router_data: T,
2828
}
2929

30-
impl<T> TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for FiservRouterData<T> {
30+
impl<T> TryFrom<(FloatMajorUnit, T)> for FiservRouterData<T> {
3131
type Error = error_stack::Report<errors::ConnectorError>;
3232

33-
fn try_from(
34-
(currency_unit, currency, amount, router_data): (
35-
&api::CurrencyUnit,
36-
enums::Currency,
37-
i64,
38-
T,
39-
),
40-
) -> Result<Self, Self::Error> {
41-
let amount = utils::get_amount_as_string(currency_unit, amount, currency)?;
33+
fn try_from((amount, router_data): (FloatMajorUnit, T)) -> Result<Self, Self::Error> {
4234
Ok(Self {
4335
amount,
4436
router_data,
@@ -89,8 +81,7 @@ pub struct GooglePayToken {
8981

9082
#[derive(Default, Debug, Serialize)]
9183
pub struct Amount {
92-
#[serde(serialize_with = "utils::str_to_f32")]
93-
total: String,
84+
total: FloatMajorUnit,
9485
currency: String,
9586
}
9687

@@ -143,7 +134,7 @@ impl TryFrom<&FiservRouterData<&types::PaymentsAuthorizeRouterData>> for FiservP
143134
) -> Result<Self, Self::Error> {
144135
let auth: FiservAuthType = FiservAuthType::try_from(&item.router_data.connector_auth_type)?;
145136
let amount = Amount {
146-
total: item.amount.clone(),
137+
total: item.amount,
147138
currency: item.router_data.request.currency.to_string(),
148139
};
149140
let transaction_details = TransactionDetails {
@@ -484,7 +475,7 @@ impl TryFrom<&FiservRouterData<&types::PaymentsCaptureRouterData>> for FiservCap
484475
})?;
485476
Ok(Self {
486477
amount: Amount {
487-
total: item.amount.clone(),
478+
total: item.amount,
488479
currency: item.router_data.request.currency.to_string(),
489480
},
490481
transaction_details: TransactionDetails {
@@ -579,7 +570,7 @@ impl<F> TryFrom<&FiservRouterData<&types::RefundsRouterData<F>>> for FiservRefun
579570
})?;
580571
Ok(Self {
581572
amount: Amount {
582-
total: item.amount.clone(),
573+
total: item.amount,
583574
currency: item.router_data.request.currency.to_string(),
584575
},
585576
merchant_details: MerchantDetails {

crates/hyperswitch_connectors/src/connectors/helcim.rs

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
pub mod transformers;
2-
use std::fmt::Debug;
32

43
use api_models::webhooks::IncomingWebhookEvent;
54
use common_enums::enums;
65
use common_utils::{
76
errors::CustomResult,
87
ext_traits::BytesExt,
98
request::{Method, Request, RequestBuilder, RequestContent},
9+
types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector},
1010
};
1111
use error_stack::{report, ResultExt};
1212
use hyperswitch_domain_models::{
@@ -49,11 +49,21 @@ use transformers as helcim;
4949
use crate::{
5050
constants::headers,
5151
types::ResponseRouterData,
52-
utils::{to_connector_meta, PaymentsAuthorizeRequestData},
52+
utils::{convert_amount, to_connector_meta, PaymentsAuthorizeRequestData},
5353
};
5454

55-
#[derive(Debug, Clone)]
56-
pub struct Helcim;
55+
#[derive(Clone)]
56+
pub struct Helcim {
57+
amount_convertor: &'static (dyn AmountConvertor<Output = FloatMajorUnit> + Sync),
58+
}
59+
60+
impl Helcim {
61+
pub fn new() -> &'static Self {
62+
&Self {
63+
amount_convertor: &FloatMajorUnitForConnector,
64+
}
65+
}
66+
}
5767

5868
impl api::Payment for Helcim {}
5969
impl api::PaymentSession for Helcim {}
@@ -305,13 +315,13 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
305315
req: &PaymentsAuthorizeRouterData,
306316
_connectors: &Connectors,
307317
) -> CustomResult<RequestContent, errors::ConnectorError> {
308-
let connector_router_data = helcim::HelcimRouterData::try_from((
309-
&self.get_currency_unit(),
318+
let connector_router_data = convert_amount(
319+
self.amount_convertor,
320+
req.request.minor_amount,
310321
req.request.currency,
311-
req.request.amount,
312-
req,
313-
))?;
314-
let connector_req = helcim::HelcimPaymentsRequest::try_from(&connector_router_data)?;
322+
)?;
323+
let router_obj = helcim::HelcimRouterData::try_from((connector_router_data, req))?;
324+
let connector_req = helcim::HelcimPaymentsRequest::try_from(&router_obj)?;
315325
Ok(RequestContent::Json(Box::new(connector_req)))
316326
}
317327

@@ -484,13 +494,13 @@ impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> fo
484494
req: &PaymentsCaptureRouterData,
485495
_connectors: &Connectors,
486496
) -> CustomResult<RequestContent, errors::ConnectorError> {
487-
let connector_router_data = helcim::HelcimRouterData::try_from((
488-
&self.get_currency_unit(),
497+
let connector_router_data = convert_amount(
498+
self.amount_convertor,
499+
req.request.minor_amount_to_capture,
489500
req.request.currency,
490-
req.request.amount_to_capture,
491-
req,
492-
))?;
493-
let connector_req = helcim::HelcimCaptureRequest::try_from(&connector_router_data)?;
501+
)?;
502+
let router_obj = helcim::HelcimRouterData::try_from((connector_router_data, req))?;
503+
let connector_req = helcim::HelcimCaptureRequest::try_from(&router_obj)?;
494504
Ok(RequestContent::Json(Box::new(connector_req)))
495505
}
496506

@@ -651,13 +661,13 @@ impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Helcim
651661
req: &RefundsRouterData<Execute>,
652662
_connectors: &Connectors,
653663
) -> CustomResult<RequestContent, errors::ConnectorError> {
654-
let connector_router_data = helcim::HelcimRouterData::try_from((
655-
&self.get_currency_unit(),
664+
let connector_router_data = convert_amount(
665+
self.amount_convertor,
666+
req.request.minor_refund_amount,
656667
req.request.currency,
657-
req.request.refund_amount,
658-
req,
659-
))?;
660-
let connector_req = helcim::HelcimRefundRequest::try_from(&connector_router_data)?;
668+
)?;
669+
let router_obj = helcim::HelcimRouterData::try_from((connector_router_data, req))?;
670+
let connector_req = helcim::HelcimRefundRequest::try_from(&router_obj)?;
661671
Ok(RequestContent::Json(Box::new(connector_req)))
662672
}
663673

crates/hyperswitch_connectors/src/connectors/helcim/transformers.rs

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use common_enums::enums;
2-
use common_utils::pii::{Email, IpAddress};
2+
use common_utils::{
3+
pii::{Email, IpAddress},
4+
types::FloatMajorUnit,
5+
};
36
use error_stack::ResultExt;
47
use hyperswitch_domain_models::{
58
payment_method_data::{Card, PaymentMethodData},
@@ -15,10 +18,7 @@ use hyperswitch_domain_models::{
1518
RefundsRouterData, SetupMandateRouterData,
1619
},
1720
};
18-
use hyperswitch_interfaces::{
19-
api::{self},
20-
errors,
21-
};
21+
use hyperswitch_interfaces::errors;
2222
use masking::Secret;
2323
use serde::{Deserialize, Serialize};
2424

@@ -33,16 +33,13 @@ use crate::{
3333

3434
#[derive(Debug, Serialize)]
3535
pub struct HelcimRouterData<T> {
36-
pub amount: f64,
36+
pub amount: FloatMajorUnit,
3737
pub router_data: T,
3838
}
3939

40-
impl<T> TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for HelcimRouterData<T> {
40+
impl<T> TryFrom<(FloatMajorUnit, T)> for HelcimRouterData<T> {
4141
type Error = error_stack::Report<errors::ConnectorError>;
42-
fn try_from(
43-
(currency_unit, currency, amount, item): (&api::CurrencyUnit, enums::Currency, i64, T),
44-
) -> Result<Self, Self::Error> {
45-
let amount = crate::utils::get_amount_as_f64(currency_unit, amount, currency)?;
42+
fn try_from((amount, item): (FloatMajorUnit, T)) -> Result<Self, Self::Error> {
4643
Ok(Self {
4744
amount,
4845
router_data: item,
@@ -77,7 +74,7 @@ pub struct HelcimVerifyRequest {
7774
#[derive(Debug, Serialize)]
7875
#[serde(rename_all = "camelCase")]
7976
pub struct HelcimPaymentsRequest {
80-
amount: f64,
77+
amount: FloatMajorUnit,
8178
currency: enums::Currency,
8279
ip_address: Secret<String, IpAddress>,
8380
card_data: HelcimCard,
@@ -115,8 +112,8 @@ pub struct HelcimInvoice {
115112
pub struct HelcimLineItems {
116113
description: String,
117114
quantity: u8,
118-
price: f64,
119-
total: f64,
115+
price: FloatMajorUnit,
116+
total: FloatMajorUnit,
120117
}
121118

122119
#[derive(Debug, Serialize)]
@@ -514,7 +511,7 @@ impl<F>
514511
#[serde(rename_all = "camelCase")]
515512
pub struct HelcimCaptureRequest {
516513
pre_auth_transaction_id: u64,
517-
amount: f64,
514+
amount: FloatMajorUnit,
518515
ip_address: Secret<String, IpAddress>,
519516
#[serde(skip_serializing_if = "Option::is_none")]
520517
ecommerce: Option<bool>,
@@ -637,7 +634,7 @@ impl<F>
637634
#[derive(Debug, Serialize)]
638635
#[serde(rename_all = "camelCase")]
639636
pub struct HelcimRefundRequest {
640-
amount: f64,
637+
amount: FloatMajorUnit,
641638
original_transaction_id: u64,
642639
ip_address: Secret<String, IpAddress>,
643640
#[serde(skip_serializing_if = "Option::is_none")]

crates/hyperswitch_connectors/src/utils.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ use masking::{ExposeInterface, PeekInterface, Secret};
5757
use once_cell::sync::Lazy;
5858
use regex::Regex;
5959
use router_env::logger;
60-
use serde::Serializer;
6160
use serde_json::Value;
6261
use time::PrimitiveDateTime;
6362

@@ -344,16 +343,6 @@ pub(crate) fn construct_not_implemented_error_report(
344343
.into()
345344
}
346345

347-
pub(crate) fn str_to_f32<S>(value: &str, serializer: S) -> Result<S::Ok, S::Error>
348-
where
349-
S: Serializer,
350-
{
351-
let float_value = value.parse::<f64>().map_err(|_| {
352-
serde::ser::Error::custom("Invalid string, cannot be converted to float value")
353-
})?;
354-
serializer.serialize_f64(float_value)
355-
}
356-
357346
pub(crate) const SELECTED_PAYMENT_METHOD: &str = "Selected payment method";
358347

359348
pub(crate) fn get_unimplemented_payment_method_error_message(connector: &str) -> String {

0 commit comments

Comments
 (0)