diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 0cad88bfd4f..88d7dd4b4a7 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -553,7 +553,7 @@ pub struct StringMajorUnit(String); impl StringMajorUnit { /// forms a new major unit from amount - fn new(value: String) -> Self { + pub fn new(value: String) -> Self { Self(value) } diff --git a/crates/router/src/connector/riskified.rs b/crates/router/src/connector/riskified.rs index 0f8ebb46134..7d9feec717a 100644 --- a/crates/router/src/connector/riskified.rs +++ b/crates/router/src/connector/riskified.rs @@ -1,8 +1,10 @@ pub mod transformers; -use std::fmt::Debug; #[cfg(feature = "frm")] use base64::Engine; +use common_utils::types::{ + AmountConvertor, MinorUnit, StringMajorUnit, StringMajorUnitForConnector, +}; #[cfg(feature = "frm")] use common_utils::{crypto, ext_traits::ByteSliceExt, request::RequestContent}; #[cfg(feature = "frm")] @@ -14,6 +16,7 @@ use ring::hmac; #[cfg(feature = "frm")] use transformers as riskified; +use super::utils::convert_amount; #[cfg(feature = "frm")] use super::utils::{self as connector_utils, FrmTransactionRouterDataRequest}; use crate::{ @@ -35,10 +38,18 @@ use crate::{ utils::BytesExt, }; -#[derive(Debug, Clone)] -pub struct Riskified; +#[derive(Clone)] +pub struct Riskified { + amount_converter: &'static (dyn AmountConvertor + Sync), +} impl Riskified { + pub fn new() -> &'static Self { + &Self { + amount_converter: &StringMajorUnitForConnector, + } + } + #[cfg(feature = "frm")] pub fn generate_authorization_signature( &self, @@ -173,7 +184,17 @@ impl req: &frm_types::FrmCheckoutRouterData, _connectors: &settings::Connectors, ) -> CustomResult { - let req_obj = riskified::RiskifiedPaymentsCheckoutRequest::try_from(req)?; + let amount = convert_amount( + self.amount_converter, + MinorUnit::new(req.request.amount), + req.request + .currency + .ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "currency", + })?, + )?; + let req_data = riskified::RiskifiedRouterData::from((amount, req)); + let req_obj = riskified::RiskifiedPaymentsCheckoutRequest::try_from(&req_data)?; Ok(RequestContent::Json(Box::new(req_obj))) } @@ -293,7 +314,17 @@ impl Ok(RequestContent::Json(Box::new(req_obj))) } _ => { - let req_obj = riskified::TransactionSuccessRequest::try_from(req)?; + let amount = convert_amount( + self.amount_converter, + MinorUnit::new(req.request.amount), + req.request + .currency + .ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "currency", + })?, + )?; + let req_data = riskified::RiskifiedRouterData::from((amount, req)); + let req_obj = riskified::TransactionSuccessRequest::try_from(&req_data)?; Ok(RequestContent::Json(Box::new(req_obj))) } } diff --git a/crates/router/src/connector/riskified/transformers/api.rs b/crates/router/src/connector/riskified/transformers/api.rs index 2e0ac3b0047..b3aed4e18d6 100644 --- a/crates/router/src/connector/riskified/transformers/api.rs +++ b/crates/router/src/connector/riskified/transformers/api.rs @@ -1,5 +1,5 @@ use api_models::payments::AdditionalPaymentData; -use common_utils::{ext_traits::ValueExt, id_type, pii::Email}; +use common_utils::{ext_traits::ValueExt, id_type, pii::Email, types::StringMajorUnit}; use error_stack::{self, ResultExt}; use masking::Secret; use serde::{Deserialize, Serialize}; @@ -18,6 +18,21 @@ use crate::{ type Error = error_stack::Report; +#[derive(Debug, Serialize)] +pub struct RiskifiedRouterData { + pub amount: StringMajorUnit, + pub router_data: T, +} + +impl From<(StringMajorUnit, T)> for RiskifiedRouterData { + fn from((amount, router_data): (StringMajorUnit, T)) -> Self { + Self { + amount, + router_data, + } + } +} + #[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Clone)] pub struct RiskifiedPaymentsCheckoutRequest { order: CheckoutRequest, @@ -35,8 +50,8 @@ pub struct CheckoutRequest { updated_at: PrimitiveDateTime, gateway: Option, browser_ip: Option, - total_price: i64, - total_discounts: i64, + total_price: StringMajorUnit, + total_discounts: StringMajorUnit, cart_token: String, referring_site: String, line_items: Vec, @@ -60,13 +75,13 @@ pub struct PaymentDetails { #[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Clone)] pub struct ShippingLines { - price: i64, + price: StringMajorUnit, title: Option, } #[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Clone)] pub struct DiscountCodes { - amount: i64, + amount: StringMajorUnit, code: Option, } @@ -110,7 +125,7 @@ pub struct OrderAddress { #[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Clone)] pub struct LineItem { - price: i64, + price: StringMajorUnit, quantity: i32, title: String, product_type: Option, @@ -132,9 +147,14 @@ pub struct RiskifiedMetadata { shipping_lines: Vec, } -impl TryFrom<&frm_types::FrmCheckoutRouterData> for RiskifiedPaymentsCheckoutRequest { +impl TryFrom<&RiskifiedRouterData<&frm_types::FrmCheckoutRouterData>> + for RiskifiedPaymentsCheckoutRequest +{ type Error = Error; - fn try_from(payment_data: &frm_types::FrmCheckoutRouterData) -> Result { + fn try_from( + payment: &RiskifiedRouterData<&frm_types::FrmCheckoutRouterData>, + ) -> Result { + let payment_data = payment.router_data.clone(); let metadata: RiskifiedMetadata = payment_data .frm_metadata .clone() @@ -156,14 +176,14 @@ impl TryFrom<&frm_types::FrmCheckoutRouterData> for RiskifiedPaymentsCheckoutReq created_at: common_utils::date_time::now(), updated_at: common_utils::date_time::now(), gateway: payment_data.request.gateway.clone(), - total_price: payment_data.request.amount, + total_price: payment.amount.clone(), cart_token: payment_data.attempt_id.clone(), line_items: payment_data .request .get_order_details()? .iter() .map(|order_detail| LineItem { - price: order_detail.amount, + price: StringMajorUnit::new(order_detail.amount.to_string()), quantity: i32::from(order_detail.quantity), title: order_detail.product_name.clone(), product_type: order_detail.product_type.clone(), @@ -176,7 +196,7 @@ impl TryFrom<&frm_types::FrmCheckoutRouterData> for RiskifiedPaymentsCheckoutReq source: Source::DesktopWeb, billing_address: OrderAddress::try_from(billing_address).ok(), shipping_address: OrderAddress::try_from(shipping_address).ok(), - total_discounts: 0, + total_discounts: StringMajorUnit::new("0".to_string()), currency: payment_data.request.currency, referring_site: "hyperswitch.io".to_owned(), discount_codes: Vec::new(), @@ -411,7 +431,7 @@ pub struct SuccessfulTransactionData { pub struct TransactionDecisionData { external_status: TransactionStatus, reason: Option, - amount: i64, + amount: StringMajorUnit, currency: storage_enums::Currency, #[serde(with = "common_utils::custom_serde::iso8601")] decided_at: PrimitiveDateTime, @@ -429,16 +449,21 @@ pub enum TransactionStatus { Approved, } -impl TryFrom<&frm_types::FrmTransactionRouterData> for TransactionSuccessRequest { +impl TryFrom<&RiskifiedRouterData<&frm_types::FrmTransactionRouterData>> + for TransactionSuccessRequest +{ type Error = Error; - fn try_from(item: &frm_types::FrmTransactionRouterData) -> Result { + fn try_from( + item_data: &RiskifiedRouterData<&frm_types::FrmTransactionRouterData>, + ) -> Result { + let item = item_data.router_data.clone(); Ok(Self { order: SuccessfulTransactionData { id: item.attempt_id.clone(), decision: TransactionDecisionData { external_status: TransactionStatus::Approved, reason: None, - amount: item.request.amount, + amount: item_data.amount.clone(), currency: item.request.get_currency()?, decided_at: common_utils::date_time::now(), payment_details: [TransactionPaymentDetails { diff --git a/crates/router/src/types/api/fraud_check.rs b/crates/router/src/types/api/fraud_check.rs index 2d1a42092f4..213aef9cf03 100644 --- a/crates/router/src/types/api/fraud_check.rs +++ b/crates/router/src/types/api/fraud_check.rs @@ -51,7 +51,7 @@ impl FraudCheckConnectorData { Ok(ConnectorEnum::Old(Box::new(&connector::Signifyd))) } enums::FrmConnectors::Riskified => { - Ok(ConnectorEnum::Old(Box::new(&connector::Riskified))) + Ok(ConnectorEnum::Old(Box::new(connector::Riskified::new()))) } } }