Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(connector): added amount conversion framework for klarna and change type of amount to MinorUnit for OrderDetailsWithAmount #4979

Merged
merged 20 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
19d54b0
do-amount-conversion-for-klarna
KiranKBR Jun 12, 2024
bc0a254
Merge branch 'main' of https://github.com/juspay/hyperswitch into do-…
KiranKBR Jul 25, 2024
5c2ac69
club the amount changes
KiranKBR Jul 25, 2024
9efa745
docs(openapi): re-generate OpenAPI specification
hyperswitch-bot[bot] Jul 25, 2024
2ea710f
Merge remote-tracking branch 'origin' into do-amount-conversion-for-k…
swangi-kumari Oct 16, 2024
25d5d55
docs(openapi): re-generate OpenAPI specification
hyperswitch-bot[bot] Oct 16, 2024
7eced57
refactor: resolve clippy
swangi-kumari Oct 17, 2024
77f2160
Merge branch 'do-amount-conversion-for-klarna' of https://github.com/…
swangi-kumari Oct 17, 2024
8e87bc0
refactor: make amount minorunit
swangi-kumari Oct 22, 2024
ad23263
refactor: merge mai
swangi-kumari Oct 22, 2024
a4c4bed
Merge branch 'main' into do-amount-conversion-for-klarna
swangi-kumari Oct 22, 2024
db1709e
chore: run formatter
hyperswitch-bot[bot] Oct 22, 2024
5f2e22d
docs(openapi): re-generate OpenAPI specification
hyperswitch-bot[bot] Oct 22, 2024
da7f36f
refactor: resolve comments
swangi-kumari Oct 22, 2024
f728958
Merge branch 'do-amount-conversion-for-klarna' of https://github.com/…
swangi-kumari Oct 22, 2024
2f9c031
refactor: add comments
swangi-kumari Oct 23, 2024
1adb70a
Merge branch 'main' into do-amount-conversion-for-klarna
swangi-kumari Oct 23, 2024
8e25c51
refactor: resolve comments
swangi-kumari Oct 24, 2024
c2ce1e2
refactor: resolve comments
swangi-kumari Oct 24, 2024
b49a3b9
refactor: mul impl
swangi-kumari Oct 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions api-reference-v2/openapi_spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -10749,9 +10749,7 @@
"minimum": 0
},
"amount": {
"type": "integer",
"format": "int64",
"description": "the amount per quantity of product"
"$ref": "#/components/schemas/MinorUnit"
},
"requires_shipping": {
"type": "boolean",
Expand Down
4 changes: 1 addition & 3 deletions api-reference/openapi_spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -14317,9 +14317,7 @@
"minimum": 0
},
"amount": {
"type": "integer",
"format": "int64",
"description": "the amount per quantity of product"
"$ref": "#/components/schemas/MinorUnit"
},
"requires_shipping": {
"type": "boolean",
Expand Down
2 changes: 1 addition & 1 deletion crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4928,7 +4928,7 @@ pub struct OrderDetailsWithAmount {
#[schema(example = 1)]
pub quantity: u16,
/// the amount per quantity of product
pub amount: i64,
pub amount: MinorUnit,
// Does the order includes shipping
pub requires_shipping: Option<bool>,
/// The image URL of the product
Expand Down
17 changes: 16 additions & 1 deletion crates/common_utils/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ pub mod authentication;
use std::{
borrow::Cow,
fmt::Display,
ops::{Add, Sub},
iter::Sum,
ops::{Add, Mul, Sub},
primitive::i64,
str::FromStr,
};
Expand Down Expand Up @@ -483,6 +484,20 @@ impl Sub for MinorUnit {
}
}

impl Mul for MinorUnit {
type Output = Self;

fn mul(self, a2: Self) -> Self::Output {
Self(self.0 * a2.0)
}
}

impl Sum for MinorUnit {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add is already there why is Sum needed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.sum() function is required to accumulate the elements of an iterator for OrderDetails.

fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self(0), |a, b| a + b)
}
}

/// Connector specific types to send

#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq)]
Expand Down
15 changes: 13 additions & 2 deletions crates/hyperswitch_connectors/src/connectors/taxjar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,22 @@ impl ConnectorIntegration<CalculateTax, PaymentsTaxCalculationData, TaxCalculati

let shipping = utils::convert_amount(
self.amount_converter,
req.request.shipping_cost.unwrap_or(MinorUnit::new(0)),
req.request.shipping_cost.unwrap_or(MinorUnit::zero()),
req.request.currency,
)?;

let connector_router_data = taxjar::TaxjarRouterData::from((amount, shipping, req));
let order_amount = utils::convert_amount(
self.amount_converter,
req.request
.order_details
.as_ref()
.map(|details| details.iter().map(|item| item.amount).sum())
.unwrap_or(MinorUnit::zero()),
req.request.currency,
)?;

let connector_router_data =
taxjar::TaxjarRouterData::from((amount, order_amount, shipping, req));
let connector_req = taxjar::TaxjarPaymentsRequest::try_from(&connector_router_data)?;
Ok(RequestContent::Json(Box::new(connector_req)))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use hyperswitch_domain_models::{
router_response_types::TaxCalculationResponseData,
types,
};
use hyperswitch_interfaces::{api, errors};
use hyperswitch_interfaces::errors;
use masking::Secret;
use serde::{Deserialize, Serialize};

Expand All @@ -18,14 +18,18 @@ use crate::{

pub struct TaxjarRouterData<T> {
pub amount: FloatMajorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
pub order_amount: FloatMajorUnit,
pub shipping: FloatMajorUnit,
pub router_data: T,
}

impl<T> From<(FloatMajorUnit, FloatMajorUnit, T)> for TaxjarRouterData<T> {
fn from((amount, shipping, item): (FloatMajorUnit, FloatMajorUnit, T)) -> Self {
impl<T> From<(FloatMajorUnit, FloatMajorUnit, FloatMajorUnit, T)> for TaxjarRouterData<T> {
fn from(
(amount, order_amount, shipping, item): (FloatMajorUnit, FloatMajorUnit, FloatMajorUnit, T),
) -> Self {
Self {
amount,
order_amount,
shipping,
router_data: item,
}
Expand All @@ -49,7 +53,7 @@ pub struct LineItem {
id: Option<String>,
quantity: Option<u16>,
product_tax_code: Option<String>,
unit_price: Option<f64>,
unit_price: Option<FloatMajorUnit>,
}

#[derive(Default, Debug, Serialize, Eq, PartialEq)]
Expand All @@ -69,8 +73,6 @@ impl TryFrom<&TaxjarRouterData<&types::PaymentsTaxCalculationRouterData>>
item: &TaxjarRouterData<&types::PaymentsTaxCalculationRouterData>,
) -> Result<Self, Self::Error> {
let request = &item.router_data.request;
let currency = item.router_data.request.currency;
let currency_unit = &api::CurrencyUnit::Base;
let shipping = &item
.router_data
.request
Expand All @@ -87,16 +89,11 @@ impl TryFrom<&TaxjarRouterData<&types::PaymentsTaxCalculationRouterData>>
order_details
.iter()
.map(|line_item| {
let unit_price = utils::get_amount_as_f64(
currency_unit,
line_item.amount,
currency,
)?;
Ok(LineItem {
id: line_item.product_id.clone(),
quantity: Some(line_item.quantity),
product_tax_code: line_item.product_tax_code.clone(),
unit_price: Some(unit_price),
unit_price: Some(item.order_amount),
})
})
.collect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -624,11 +624,14 @@ fn get_item_object(
name: data.product_name.clone(),
quantity: data.quantity,
price: utils::to_currency_base_unit_with_zero_decimal_check(
data.amount,
data.amount.get_amount_as_i64(), // This should be changed to MinorUnit when we implement amount conversion for this connector. Additionally, the function get_amount_as_i64() should be avoided in the future.
item.request.currency,
)?,
line_amount_total: (f64::from(data.quantity)
* utils::to_currency_base_unit_asf64(data.amount, item.request.currency)?)
* utils::to_currency_base_unit_asf64(
data.amount.get_amount_as_i64(), // This should be changed to MinorUnit when we implement amount conversion for this connector. Additionally, the function get_amount_as_i64() should be avoided in the future.
item.request.currency,
)?)
.to_string(),
})
})
Expand Down
4 changes: 2 additions & 2 deletions crates/router/src/connector/adyen/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1770,8 +1770,8 @@ fn get_line_items(item: &AdyenRouterData<&types::PaymentsAuthorizeRouterData>) -
.iter()
.enumerate()
.map(|(i, data)| LineItem {
amount_including_tax: Some(MinorUnit::new(data.amount)),
amount_excluding_tax: Some(MinorUnit::new(data.amount)),
amount_including_tax: Some(data.amount),
amount_excluding_tax: Some(data.amount),
description: Some(data.product_name.clone()),
id: Some(format!("Items #{i}")),
tax_amount: None,
Expand Down
60 changes: 36 additions & 24 deletions crates/router/src/connector/klarna.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
pub mod transformers;
use std::fmt::Debug;

use api_models::enums;
use base64::Engine;
use common_utils::request::RequestContent;
use common_utils::{
request::RequestContent,
types::{AmountConvertor, MinorUnit, MinorUnitForConnector},
};
use error_stack::{report, ResultExt};
use masking::PeekInterface;
use router_env::logger;
Expand All @@ -29,8 +31,18 @@ use crate::{
utils::BytesExt,
};

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

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

impl ConnectorCommon for Klarna {
fn id(&self) -> &'static str {
Expand Down Expand Up @@ -215,12 +227,12 @@ impl
req: &types::PaymentsSessionRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<RequestContent, errors::ConnectorError> {
let connector_router_data = klarna::KlarnaRouterData::try_from((
&self.get_currency_unit(),
let amount = connector_utils::convert_amount(
self.amount_converter,
req.request.minor_amount,
req.request.currency,
req.request.amount,
req,
))?;
)?;
let connector_router_data = klarna::KlarnaRouterData::from((amount, req));

let connector_req = klarna::KlarnaSessionRequest::try_from(&connector_router_data)?;
// encode only for for urlencoded things.
Expand Down Expand Up @@ -342,12 +354,12 @@ impl
req: &types::PaymentsCaptureRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<RequestContent, errors::ConnectorError> {
let connector_router_data = klarna::KlarnaRouterData::try_from((
&self.get_currency_unit(),
let amount = connector_utils::convert_amount(
self.amount_converter,
req.request.minor_amount_to_capture,
req.request.currency,
req.request.amount_to_capture,
req,
))?;
)?;
let connector_router_data = klarna::KlarnaRouterData::from((amount, req));
let connector_req = klarna::KlarnaCaptureRequest::try_from(&connector_router_data)?;
Ok(RequestContent::Json(Box::new(connector_req)))
}
Expand Down Expand Up @@ -670,12 +682,12 @@ impl
req: &types::PaymentsAuthorizeRouterData,
_connectors: &settings::Connectors,
) -> CustomResult<RequestContent, errors::ConnectorError> {
let connector_router_data = klarna::KlarnaRouterData::try_from((
&self.get_currency_unit(),
let amount = connector_utils::convert_amount(
self.amount_converter,
req.request.minor_amount,
req.request.currency,
req.request.amount,
req,
))?;
)?;
let connector_router_data = klarna::KlarnaRouterData::from((amount, req));
let connector_req = klarna::KlarnaPaymentsRequest::try_from(&connector_router_data)?;

Ok(RequestContent::Json(Box::new(connector_req)))
Expand Down Expand Up @@ -847,12 +859,12 @@ impl services::ConnectorIntegration<api::Execute, types::RefundsData, types::Ref
req: &types::RefundsRouterData<api::Execute>,
_connectors: &settings::Connectors,
) -> CustomResult<RequestContent, errors::ConnectorError> {
let connector_router_data = klarna::KlarnaRouterData::try_from((
&self.get_currency_unit(),
let amount = connector_utils::convert_amount(
self.amount_converter,
req.request.minor_refund_amount,
req.request.currency,
req.request.refund_amount,
req,
))?;
)?;
let connector_router_data = klarna::KlarnaRouterData::from((amount, req));
let connector_req = klarna::KlarnaRefundRequest::try_from(&connector_router_data)?;
Ok(RequestContent::Json(Box::new(connector_req)))
}
Expand Down
37 changes: 14 additions & 23 deletions crates/router/src/connector/klarna/transformers.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use api_models::payments;
use common_utils::pii;
use common_utils::{pii, types::MinorUnit};
use error_stack::{report, ResultExt};
use hyperswitch_domain_models::router_data::KlarnaSdkResponse;
use masking::{ExposeInterface, Secret};
Expand All @@ -15,25 +15,16 @@ use crate::{

#[derive(Debug, Serialize)]
pub struct KlarnaRouterData<T> {
amount: i64,
amount: MinorUnit,
router_data: T,
}

impl<T> TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for KlarnaRouterData<T> {
type Error = error_stack::Report<errors::ConnectorError>;

fn try_from(
(_currency_unit, _currency, amount, router_data): (
&api::CurrencyUnit,
enums::Currency,
i64,
T,
),
) -> Result<Self, Self::Error> {
Ok(Self {
impl<T> From<(MinorUnit, T)> for KlarnaRouterData<T> {
fn from((amount, router_data): (MinorUnit, T)) -> Self {
Self {
amount,
router_data,
})
}
}
}

Expand Down Expand Up @@ -74,7 +65,7 @@ impl TryFrom<&Option<pii::SecretSerdeValue>> for KlarnaConnectorMetadataObject {
pub struct KlarnaPaymentsRequest {
auto_capture: bool,
order_lines: Vec<OrderLines>,
order_amount: i64,
order_amount: MinorUnit,
purchase_country: enums::CountryAlpha2,
purchase_currency: enums::Currency,
merchant_reference1: Option<String>,
Expand Down Expand Up @@ -110,7 +101,7 @@ pub struct KlarnaSessionRequest {
intent: KlarnaSessionIntent,
purchase_country: enums::CountryAlpha2,
purchase_currency: enums::Currency,
order_amount: i64,
order_amount: MinorUnit,
order_lines: Vec<OrderLines>,
shipping_address: Option<KlarnaShippingAddress>,
}
Expand Down Expand Up @@ -157,7 +148,7 @@ impl TryFrom<&KlarnaRouterData<&types::PaymentsSessionRouterData>> for KlarnaSes
name: data.product_name.clone(),
quantity: data.quantity,
unit_price: data.amount,
total_amount: i64::from(data.quantity) * (data.amount),
total_amount: MinorUnit::new(i64::from(data.quantity)) * (data.amount),
})
.collect(),
shipping_address: get_address_info(item.router_data.get_optional_shipping())
Expand Down Expand Up @@ -210,7 +201,7 @@ impl TryFrom<&KlarnaRouterData<&types::PaymentsAuthorizeRouterData>> for KlarnaP
name: data.product_name.clone(),
quantity: data.quantity,
unit_price: data.amount,
total_amount: i64::from(data.quantity) * (data.amount),
total_amount: MinorUnit::new(i64::from(data.quantity)) * (data.amount),
})
.collect(),
merchant_reference1: Some(item.router_data.connector_request_reference_id.clone()),
Expand Down Expand Up @@ -294,8 +285,8 @@ impl TryFrom<types::PaymentsResponseRouterData<KlarnaPaymentsResponse>>
pub struct OrderLines {
name: String,
quantity: u16,
unit_price: i64,
total_amount: i64,
unit_price: MinorUnit,
total_amount: MinorUnit,
}

#[derive(Debug, Serialize)]
Expand Down Expand Up @@ -412,7 +403,7 @@ impl<F, T>

#[derive(Debug, Serialize)]
pub struct KlarnaCaptureRequest {
captured_amount: i64,
captured_amount: MinorUnit,
reference: Option<String>,
}

Expand Down Expand Up @@ -490,7 +481,7 @@ impl<F>

#[derive(Default, Debug, Serialize)]
pub struct KlarnaRefundRequest {
refunded_amount: i64,
refunded_amount: MinorUnit,
reference: Option<String>,
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ impl TryFrom<&frm_types::FrmCheckoutRouterData> for RiskifiedPaymentsCheckoutReq
.get_order_details()?
.iter()
.map(|order_detail| LineItem {
price: order_detail.amount,
price: order_detail.amount.get_amount_as_i64(), // This should be changed to MinorUnit when we implement amount conversion for this connector. Additionally, the function get_amount_as_i64() should be avoided in the future.
quantity: i32::from(order_detail.quantity),
title: order_detail.product_name.clone(),
product_type: order_detail.product_type.clone(),
Expand Down
Loading
Loading