Skip to content

Commit 1d0551a

Browse files
feat(nuvei): L2L3 Data (#9290)
1 parent 75bf58d commit 1d0551a

File tree

1 file changed

+152
-30
lines changed

1 file changed

+152
-30
lines changed

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

Lines changed: 152 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use hyperswitch_domain_models::{
1919
},
2020
router_data::{
2121
AdditionalPaymentMethodConnectorResponse, ConnectorAuthType, ConnectorResponseData,
22-
ErrorResponse, RouterData,
22+
ErrorResponse, L2L3Data, RouterData,
2323
},
2424
router_flow_types::{
2525
refunds::{Execute, RSync},
@@ -94,9 +94,6 @@ trait NuveiAuthorizePreprocessingCommon {
9494
&self,
9595
) -> Result<PaymentMethodData, error_stack::Report<errors::ConnectorError>>;
9696
fn get_is_partial_approval(&self) -> Option<PartialApprovalFlag>;
97-
fn get_order_tax_amount(
98-
&self,
99-
) -> Result<Option<MinorUnit>, error_stack::Report<errors::ConnectorError>>;
10097
fn is_customer_initiated_mandate_payment(&self) -> bool;
10198
}
10299

@@ -158,11 +155,6 @@ impl NuveiAuthorizePreprocessingCommon for SetupMandateRequestData {
158155
) -> Result<PaymentMethodData, error_stack::Report<errors::ConnectorError>> {
159156
Ok(self.payment_method_data.clone())
160157
}
161-
fn get_order_tax_amount(
162-
&self,
163-
) -> Result<Option<MinorUnit>, error_stack::Report<errors::ConnectorError>> {
164-
Ok(None)
165-
}
166158

167159
fn get_minor_amount_required(
168160
&self,
@@ -243,11 +235,6 @@ impl NuveiAuthorizePreprocessingCommon for PaymentsAuthorizeData {
243235
) -> Result<PaymentMethodData, error_stack::Report<errors::ConnectorError>> {
244236
Ok(self.payment_method_data.clone())
245237
}
246-
fn get_order_tax_amount(
247-
&self,
248-
) -> Result<Option<MinorUnit>, error_stack::Report<errors::ConnectorError>> {
249-
Ok(self.order_tax_amount)
250-
}
251238

252239
fn get_email_required(&self) -> Result<Email, error_stack::Report<errors::ConnectorError>> {
253240
self.get_email()
@@ -325,11 +312,6 @@ impl NuveiAuthorizePreprocessingCommon for PaymentsPreProcessingData {
325312
.into(),
326313
)
327314
}
328-
fn get_order_tax_amount(
329-
&self,
330-
) -> Result<Option<MinorUnit>, error_stack::Report<errors::ConnectorError>> {
331-
Ok(None)
332-
}
333315

334316
fn get_is_partial_approval(&self) -> Option<PartialApprovalFlag> {
335317
None
@@ -376,8 +358,62 @@ pub struct NuveiSessionResponse {
376358

377359
#[derive(Debug, Serialize, Default)]
378360
#[serde(rename_all = "camelCase")]
379-
pub struct NuvieAmountDetails {
380-
total_tax: Option<StringMajorUnit>,
361+
pub struct NuveiAmountDetails {
362+
pub total_tax: Option<StringMajorUnit>,
363+
pub total_shipping: Option<StringMajorUnit>,
364+
pub total_handling: Option<StringMajorUnit>,
365+
pub total_discount: Option<StringMajorUnit>,
366+
}
367+
368+
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
369+
#[serde(rename_all = "snake_case")]
370+
pub enum NuveiItemType {
371+
#[default]
372+
Physical,
373+
Discount,
374+
#[serde(rename = "Shipping_fee")]
375+
ShippingFee,
376+
Digital,
377+
#[serde(rename = "Gift_card")]
378+
GiftCard,
379+
#[serde(rename = "Store_credit")]
380+
StoreCredit,
381+
Surcharge,
382+
#[serde(rename = "Sales_tax")]
383+
SalesTax,
384+
}
385+
impl From<Option<enums::ProductType>> for NuveiItemType {
386+
fn from(value: Option<enums::ProductType>) -> Self {
387+
match value {
388+
Some(enums::ProductType::Digital) => Self::Digital,
389+
Some(enums::ProductType::Physical) => Self::Physical,
390+
Some(enums::ProductType::Ride)
391+
| Some(enums::ProductType::Travel)
392+
| Some(enums::ProductType::Accommodation) => Self::ShippingFee,
393+
_ => Self::Physical,
394+
}
395+
}
396+
}
397+
398+
#[serde_with::skip_serializing_none]
399+
#[derive(Debug, Serialize, Default)]
400+
#[serde(rename_all = "camelCase")]
401+
pub struct NuveiItem {
402+
pub name: String,
403+
#[serde(rename = "type")]
404+
pub item_type: NuveiItemType,
405+
pub price: StringMajorUnit,
406+
pub quantity: String,
407+
pub group_id: Option<String>,
408+
pub discount: Option<StringMajorUnit>,
409+
pub discount_rate: Option<String>,
410+
pub shipping: Option<StringMajorUnit>,
411+
pub shipping_tax: Option<StringMajorUnit>,
412+
pub shipping_tax_rate: Option<String>,
413+
pub tax: Option<StringMajorUnit>,
414+
pub tax_rate: Option<String>,
415+
pub image_url: Option<String>,
416+
pub product_url: Option<String>,
381417
}
382418
#[serde_with::skip_serializing_none]
383419
#[derive(Debug, Serialize, Default)]
@@ -404,7 +440,8 @@ pub struct NuveiPaymentsRequest {
404440
pub shipping_address: Option<ShippingAddress>,
405441
pub related_transaction_id: Option<String>,
406442
pub url_details: Option<UrlDetails>,
407-
pub amount_details: Option<NuvieAmountDetails>,
443+
pub amount_details: Option<NuveiAmountDetails>,
444+
pub items: Option<Vec<NuveiItem>>,
408445
pub is_partial_approval: Option<PartialApprovalFlag>,
409446
pub external_scheme_details: Option<ExternalSchemeDetails>,
410447
}
@@ -1424,6 +1461,94 @@ where
14241461
..Default::default()
14251462
})
14261463
}
1464+
fn get_l2_l3_items(
1465+
l2_l3_data: &Option<L2L3Data>,
1466+
currency: enums::Currency,
1467+
) -> Result<Option<Vec<NuveiItem>>, error_stack::Report<errors::ConnectorError>> {
1468+
l2_l3_data.as_ref().map_or(Ok(None), |data| {
1469+
data.order_details
1470+
.as_ref()
1471+
.map_or(Ok(None), |order_details_list| {
1472+
// Map each order to a Result<NuveiItem>
1473+
let results: Vec<Result<NuveiItem, error_stack::Report<errors::ConnectorError>>> =
1474+
order_details_list
1475+
.iter()
1476+
.map(|order| {
1477+
let discount = order
1478+
.unit_discount_amount
1479+
.map(|amount| {
1480+
convert_amount(NUVEI_AMOUNT_CONVERTOR, amount, currency)
1481+
})
1482+
.transpose()?;
1483+
let tax = order
1484+
.total_tax_amount
1485+
.map(|amount| {
1486+
convert_amount(NUVEI_AMOUNT_CONVERTOR, amount, currency)
1487+
})
1488+
.transpose()?;
1489+
Ok(NuveiItem {
1490+
name: order.product_name.clone(),
1491+
item_type: order.product_type.clone().into(),
1492+
price: convert_amount(
1493+
NUVEI_AMOUNT_CONVERTOR,
1494+
order.amount,
1495+
currency,
1496+
)?,
1497+
quantity: order.quantity.to_string(),
1498+
group_id: order.product_id.clone(),
1499+
discount,
1500+
discount_rate: None,
1501+
shipping: None,
1502+
shipping_tax: None,
1503+
shipping_tax_rate: None,
1504+
tax,
1505+
tax_rate: order.tax_rate.map(|rate| rate.to_string()),
1506+
image_url: order.product_img_link.clone(),
1507+
product_url: None,
1508+
})
1509+
})
1510+
.collect();
1511+
let mut items = Vec::with_capacity(results.len());
1512+
for result in results {
1513+
match result {
1514+
Ok(item) => items.push(item),
1515+
Err(err) => return Err(err),
1516+
}
1517+
}
1518+
Ok(Some(items))
1519+
})
1520+
})
1521+
}
1522+
1523+
fn get_amount_details(
1524+
l2_l3_data: &Option<L2L3Data>,
1525+
currency: enums::Currency,
1526+
) -> Result<Option<NuveiAmountDetails>, error_stack::Report<errors::ConnectorError>> {
1527+
l2_l3_data.as_ref().map_or(Ok(None), |data| {
1528+
let total_tax = data
1529+
.order_tax_amount
1530+
.map(|amount| convert_amount(NUVEI_AMOUNT_CONVERTOR, amount, currency))
1531+
.transpose()?;
1532+
let total_shipping = data
1533+
.shipping_cost
1534+
.map(|amount| convert_amount(NUVEI_AMOUNT_CONVERTOR, amount, currency))
1535+
.transpose()?;
1536+
let total_discount = data
1537+
.discount_amount
1538+
.map(|amount| convert_amount(NUVEI_AMOUNT_CONVERTOR, amount, currency))
1539+
.transpose()?;
1540+
let total_handling = data
1541+
.duty_amount
1542+
.map(|amount| convert_amount(NUVEI_AMOUNT_CONVERTOR, amount, currency))
1543+
.transpose()?;
1544+
Ok(Some(NuveiAmountDetails {
1545+
total_tax,
1546+
total_shipping,
1547+
total_handling,
1548+
total_discount,
1549+
}))
1550+
})
1551+
}
14271552

14281553
impl<F, Req> TryFrom<(&RouterData<F, Req, PaymentsResponseData>, String)> for NuveiPaymentsRequest
14291554
where
@@ -1578,12 +1703,8 @@ where
15781703
})?;
15791704
let return_url = item.request.get_return_url_required()?;
15801705

1581-
let amount_details = match item.request.get_order_tax_amount()? {
1582-
Some(tax) => Some(NuvieAmountDetails {
1583-
total_tax: Some(convert_amount(NUVEI_AMOUNT_CONVERTOR, tax, currency)?),
1584-
}),
1585-
None => None,
1586-
};
1706+
let amount_details = get_amount_details(&item.l2_l3_data, currency)?;
1707+
let l2_l3_items: Option<Vec<NuveiItem>> = get_l2_l3_items(&item.l2_l3_data, currency)?;
15871708
let address = {
15881709
if let Some(billing_address) = item.get_optional_billing() {
15891710
let mut billing_address = billing_address.clone();
@@ -1631,6 +1752,7 @@ where
16311752
pending_url: return_url.clone(),
16321753
}),
16331754
amount_details,
1755+
items: l2_l3_items,
16341756
is_partial_approval: item.request.get_is_partial_approval(),
16351757
..request
16361758
})
@@ -3011,9 +3133,9 @@ fn convert_to_additional_payment_method_connector_response(
30113133
merchant_advice_code.and_then(|code| get_merchant_advice_code_description(code));
30123134

30133135
let payment_checks = serde_json::json!({
3014-
"avs_result_code": avs_code,
3136+
"avs_result": avs_code,
30153137
"avs_description": avs_description,
3016-
"cvv_2_reply_code": cvv2_code,
3138+
"cvv_2_reply": cvv2_code,
30173139
"cvv_2_description": cvv_description,
30183140
"merchant_advice_code": merchant_advice_code,
30193141
"merchant_advice_code_description": merchant_advice_description

0 commit comments

Comments
 (0)