diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 956d6d6697c..e04fb0d70da 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -9770,8 +9770,7 @@ "description": "The identifier for payment_attempt" }, "amount": { - "type": "string", - "description": "The dispute amount" + "$ref": "#/components/schemas/StringMinorUnit" }, "currency": { "$ref": "#/components/schemas/Currency" @@ -22819,6 +22818,10 @@ "propertyName": "type" } }, + "StringMinorUnit": { + "type": "string", + "description": "Connector specific types to send" + }, "StripeChargeResponseData": { "type": "object", "description": "Fee information to be charged on the payment being collected via Stripe", diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index ed5757c1875..b9b60103243 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -11907,8 +11907,7 @@ "description": "The identifier for payment_attempt" }, "amount": { - "type": "string", - "description": "The dispute amount" + "$ref": "#/components/schemas/StringMinorUnit" }, "currency": { "$ref": "#/components/schemas/Currency" @@ -27172,6 +27171,10 @@ "propertyName": "type" } }, + "StringMinorUnit": { + "type": "string", + "description": "Connector specific types to send" + }, "StripeChargeResponseData": { "type": "object", "description": "Fee information to be charged on the payment being collected via Stripe", diff --git a/crates/api_models/src/disputes.rs b/crates/api_models/src/disputes.rs index 5b0de11f2d0..55d02c872c9 100644 --- a/crates/api_models/src/disputes.rs +++ b/crates/api_models/src/disputes.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use common_utils::types::TimeRange; +use common_utils::types::{StringMinorUnit, TimeRange}; use masking::{Deserialize, Serialize}; use serde::de::Error; use time::PrimitiveDateTime; @@ -19,7 +19,7 @@ pub struct DisputeResponse { /// The identifier for payment_attempt pub attempt_id: String, /// The dispute amount - pub amount: String, + pub amount: StringMinorUnit, /// The three-letter ISO currency code #[schema(value_type = Currency)] pub currency: Currency, diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index 1ff0dcb20ba..62c6e9cf75f 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -520,7 +520,20 @@ impl Sum for MinorUnit { } /// Connector specific types to send -#[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq)] +#[derive( + Default, + Debug, + serde::Deserialize, + AsExpression, + serde::Serialize, + Clone, + PartialEq, + Eq, + Hash, + ToSchema, + PartialOrd, +)] +#[diesel(sql_type = sql_types::Text)] pub struct StringMinorUnit(String); impl StringMinorUnit { @@ -544,6 +557,45 @@ impl StringMinorUnit { } } +impl Display for StringMinorUnit { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl FromSql for StringMinorUnit +where + DB: Backend, + String: FromSql, +{ + fn from_sql(value: DB::RawValue<'_>) -> deserialize::Result { + let val = String::from_sql(value)?; + Ok(Self(val)) + } +} + +impl ToSql for StringMinorUnit +where + DB: Backend, + String: ToSql, +{ + fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> diesel::serialize::Result { + self.0.to_sql(out) + } +} + +impl Queryable for StringMinorUnit +where + DB: Backend, + Self: FromSql, +{ + type Row = Self; + + fn build(row: Self::Row) -> deserialize::Result { + Ok(row) + } +} + /// Connector specific types to send #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq)] pub struct FloatMajorUnit(f64); diff --git a/crates/diesel_models/src/dispute.rs b/crates/diesel_models/src/dispute.rs index 8e3bab20d89..70ae34ad1dc 100644 --- a/crates/diesel_models/src/dispute.rs +++ b/crates/diesel_models/src/dispute.rs @@ -1,4 +1,7 @@ -use common_utils::custom_serde; +use common_utils::{ + custom_serde, + types::{MinorUnit, StringMinorUnit}, +}; use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable}; use masking::Secret; use serde::Serialize; @@ -11,7 +14,7 @@ use crate::{enums as storage_enums, schema::dispute}; #[serde(deny_unknown_fields)] pub struct DisputeNew { pub dispute_id: String, - pub amount: String, + pub amount: StringMinorUnit, pub currency: String, pub dispute_stage: storage_enums::DisputeStage, pub dispute_status: storage_enums::DisputeStatus, @@ -29,7 +32,7 @@ pub struct DisputeNew { pub evidence: Option>, pub profile_id: Option, pub merchant_connector_id: Option, - pub dispute_amount: i64, + pub dispute_amount: MinorUnit, pub organization_id: common_utils::id_type::OrganizationId, pub dispute_currency: Option, } @@ -38,7 +41,7 @@ pub struct DisputeNew { #[diesel(table_name = dispute, primary_key(dispute_id), check_for_backend(diesel::pg::Pg))] pub struct Dispute { pub dispute_id: String, - pub amount: String, + pub amount: StringMinorUnit, pub currency: String, pub dispute_stage: storage_enums::DisputeStage, pub dispute_status: storage_enums::DisputeStatus, @@ -60,7 +63,7 @@ pub struct Dispute { pub evidence: Secret, pub profile_id: Option, pub merchant_connector_id: Option, - pub dispute_amount: i64, + pub dispute_amount: MinorUnit, pub organization_id: common_utils::id_type::OrganizationId, pub dispute_currency: Option, } diff --git a/crates/hyperswitch_connectors/src/connectors/adyen.rs b/crates/hyperswitch_connectors/src/connectors/adyen.rs index a2a8b3dabdb..5feeb0a3e74 100644 --- a/crates/hyperswitch_connectors/src/connectors/adyen.rs +++ b/crates/hyperswitch_connectors/src/connectors/adyen.rs @@ -8,7 +8,10 @@ use common_utils::{ errors::CustomResult, ext_traits::{ByteSliceExt, OptionExt}, request::{Method, Request, RequestBuilder, RequestContent}, - types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, + types::{ + AmountConvertor, MinorUnit, MinorUnitForConnector, StringMinorUnit, + StringMinorUnitForConnector, + }, }; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{ @@ -86,7 +89,7 @@ use crate::{ SubmitEvidenceRouterData, }, utils::{ - self as connector_utils, convert_payment_authorize_router_response, + convert_amount, convert_payment_authorize_router_response, convert_setup_mandate_router_data_to_authorize_router_data, is_mandate_supported, ForeignTryFrom, PaymentMethodDataType, }, @@ -96,12 +99,14 @@ const ADYEN_API_VERSION: &str = "v68"; #[derive(Clone)] pub struct Adyen { amount_converter: &'static (dyn AmountConvertor + Sync), + amount_converter_webhooks: &'static (dyn AmountConvertor + Sync), } impl Adyen { pub const fn new() -> &'static Self { &Self { amount_converter: &MinorUnitForConnector, + amount_converter_webhooks: &StringMinorUnitForConnector, } } } @@ -466,7 +471,7 @@ impl ConnectorIntegration fo req: &PaymentsCaptureRouterData, _connectors: &Connectors, ) -> CustomResult { - let amount_to_capture = connector_utils::convert_amount( + let amount_to_capture = convert_amount( self.amount_converter, req.request.minor_amount_to_capture, req.request.currency, @@ -849,7 +854,7 @@ impl ConnectorIntegration CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount, req.request.currency, @@ -1012,7 +1017,7 @@ impl ConnectorIntegration for Adyen req: &PayoutsRouterData, _connectors: &Connectors, ) -> CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount, req.request.destination_currency, @@ -1395,7 +1400,7 @@ impl ConnectorIntegration for A req: &PayoutsRouterData, _connectors: &Connectors, ) -> CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount, req.request.destination_currency, @@ -1522,7 +1527,7 @@ impl ConnectorIntegration for Adyen req: &PayoutsRouterData, _connectors: &Connectors, ) -> CustomResult { - let amount = connector_utils::convert_amount( + let amount = convert_amount( self.amount_converter, req.request.minor_amount, req.request.destination_currency, @@ -1627,7 +1632,7 @@ impl ConnectorIntegration for Adyen { req: &RefundsRouterData, _connectors: &Connectors, ) -> CustomResult { - let refund_amount = connector_utils::convert_amount( + let refund_amount = convert_amount( self.amount_converter, req.request.minor_refund_amount, req.request.currency, @@ -1875,8 +1880,14 @@ impl IncomingWebhook for Adyen { ) -> CustomResult { let notif = get_webhook_object_from_body(request.body) .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?; + + let amount = convert_amount( + self.amount_converter_webhooks, + notif.amount.value, + notif.amount.currency, + )?; Ok(disputes::DisputePayload { - amount: notif.amount.value.to_string(), + amount, currency: notif.amount.currency, dispute_stage: api_models::enums::DisputeStage::from(notif.event_code.clone()), connector_dispute_id: notif.psp_reference, diff --git a/crates/hyperswitch_connectors/src/connectors/airwallex.rs b/crates/hyperswitch_connectors/src/connectors/airwallex.rs index 52485ac470f..900e8ef0d53 100644 --- a/crates/hyperswitch_connectors/src/connectors/airwallex.rs +++ b/crates/hyperswitch_connectors/src/connectors/airwallex.rs @@ -1,6 +1,6 @@ pub mod transformers; -use std::{fmt::Debug, sync::LazyLock}; +use std::sync::LazyLock; use api_models::webhooks::IncomingWebhookEvent; use common_enums::{enums, CallConnectorAction, PaymentAction}; @@ -9,6 +9,7 @@ use common_utils::{ errors::CustomResult, ext_traits::{ByteSliceExt, BytesExt, ValueExt}, request::{Method, Request, RequestBuilder, RequestContent}, + types::{AmountConvertor, StringMinorUnit, StringMinorUnitForConnector}, }; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{ @@ -53,11 +54,21 @@ use transformers as airwallex; use crate::{ constants::headers, types::{RefreshTokenRouterData, ResponseRouterData}, - utils::{AccessTokenRequestInfo, RefundsRequestData}, + utils::{convert_amount, AccessTokenRequestInfo, RefundsRequestData}, }; -#[derive(Debug, Clone)] -pub struct Airwallex; +#[derive(Clone)] +pub struct Airwallex { + amount_converter: &'static (dyn AmountConvertor + Sync), +} + +impl Airwallex { + pub const fn new() -> &'static Self { + &Self { + amount_converter: &StringMinorUnitForConnector, + } + } +} impl ConnectorCommonExt for Airwallex where @@ -1064,8 +1075,13 @@ impl IncomingWebhook for Airwallex { .object .parse_value("AirwallexDisputeObject") .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?; + let amount = convert_amount( + self.amount_converter, + dispute_details.dispute_amount, + dispute_details.dispute_currency, + )?; Ok(DisputePayload { - amount: dispute_details.dispute_amount.to_string(), + amount, currency: dispute_details.dispute_currency, dispute_stage: api_models::enums::DisputeStage::from(dispute_details.stage.clone()), connector_dispute_id: dispute_details.dispute_id, diff --git a/crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs b/crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs index 9f154103c69..b141c00e948 100644 --- a/crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs @@ -1,5 +1,5 @@ use common_enums::enums; -use common_utils::{errors::ParsingError, pii::IpAddress, request::Method}; +use common_utils::{errors::ParsingError, pii::IpAddress, request::Method, types::MinorUnit}; use error_stack::ResultExt; use hyperswitch_domain_models::{ payment_method_data::{PaymentMethodData, WalletData}, @@ -913,7 +913,7 @@ pub struct AirwallexObjectData { #[derive(Debug, Deserialize)] pub struct AirwallexDisputeObject { pub payment_intent_id: String, - pub dispute_amount: i64, + pub dispute_amount: MinorUnit, pub dispute_currency: enums::Currency, pub stage: AirwallexDisputeStage, pub dispute_id: String, diff --git a/crates/hyperswitch_connectors/src/connectors/bluesnap.rs b/crates/hyperswitch_connectors/src/connectors/bluesnap.rs index 1a902650d70..93c087e370d 100644 --- a/crates/hyperswitch_connectors/src/connectors/bluesnap.rs +++ b/crates/hyperswitch_connectors/src/connectors/bluesnap.rs @@ -11,7 +11,10 @@ use common_utils::{ errors::CustomResult, ext_traits::{BytesExt, StringExt, ValueExt}, request::{Method, Request, RequestBuilder, RequestContent}, - types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector}, + types::{ + AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector, StringMajorUnit, + StringMajorUnitForConnector, StringMinorUnit, StringMinorUnitForConnector, + }, }; use error_stack::{report, Report, ResultExt}; use hyperswitch_domain_models::{ @@ -58,10 +61,10 @@ use crate::{ constants::headers, types::ResponseRouterData, utils::{ - construct_not_supported_error_report, convert_amount, + construct_not_supported_error_report, convert_amount, convert_back_amount_to_minor_units, get_error_code_error_message_based_on_priority, get_header_key_value, get_http_header, handle_json_response_deserialization_failure, to_connector_meta_from_secret, - to_currency_lower_unit, ConnectorErrorType, ConnectorErrorTypeMapping, ForeignTryFrom, + ConnectorErrorType, ConnectorErrorTypeMapping, ForeignTryFrom, PaymentsAuthorizeRequestData, RefundsRequestData, RouterData as _, }, }; @@ -73,12 +76,18 @@ pub const REQUEST_TIMEOUT_PAYMENT_NOT_FOUND: &str = "Timed out ,payment not foun #[derive(Clone)] pub struct Bluesnap { amount_converter: &'static (dyn AmountConvertor + Sync), + amount_converter_to_string_minor_unit: + &'static (dyn AmountConvertor + Sync), + amount_converter_float_major_unit: + &'static (dyn AmountConvertor + Sync), } impl Bluesnap { pub fn new() -> &'static Self { &Self { amount_converter: &StringMajorUnitForConnector, + amount_converter_to_string_minor_unit: &StringMinorUnitForConnector, + amount_converter_float_major_unit: &FloatMajorUnitForConnector, } } } @@ -1161,9 +1170,15 @@ impl IncomingWebhook for Bluesnap { let dispute_details: bluesnap::BluesnapDisputeWebhookBody = serde_urlencoded::from_bytes(request.body) .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?; + let amount = convert_back_amount_to_minor_units( + self.amount_converter_float_major_unit, + dispute_details.invoice_charge_amount, + dispute_details.currency, + )?; Ok(DisputePayload { - amount: to_currency_lower_unit( - dispute_details.invoice_charge_amount.abs().to_string(), + amount: convert_amount( + self.amount_converter_to_string_minor_unit, + amount, dispute_details.currency, )?, currency: dispute_details.currency, diff --git a/crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs b/crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs index b8ebe76e5d1..20a6773eb99 100644 --- a/crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs @@ -16,7 +16,7 @@ use common_utils::{ errors::CustomResult, ext_traits::{ByteSliceExt, Encode, OptionExt, StringExt, ValueExt}, pii::Email, - types::StringMajorUnit, + types::{FloatMajorUnit, StringMajorUnit}, }; use error_stack::ResultExt; use hyperswitch_domain_models::{ @@ -1030,7 +1030,7 @@ impl TryFrom for IncomingWebhookEvent { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct BluesnapDisputeWebhookBody { - pub invoice_charge_amount: f64, + pub invoice_charge_amount: FloatMajorUnit, pub currency: enums::Currency, pub reversal_reason: Option, pub reversal_ref_num: String, diff --git a/crates/hyperswitch_connectors/src/connectors/braintree.rs b/crates/hyperswitch_connectors/src/connectors/braintree.rs index b0f83088be1..7891ffc18ee 100644 --- a/crates/hyperswitch_connectors/src/connectors/braintree.rs +++ b/crates/hyperswitch_connectors/src/connectors/braintree.rs @@ -11,7 +11,10 @@ use common_utils::{ errors::{CustomResult, ParsingError}, ext_traits::{BytesExt, XmlExt}, request::{Method, Request, RequestBuilder, RequestContent}, - types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector}, + types::{ + AmountConvertor, StringMajorUnit, StringMajorUnitForConnector, StringMinorUnit, + StringMinorUnitForConnector, + }, }; use error_stack::{report, Report, ResultExt}; use hyperswitch_domain_models::{ @@ -67,7 +70,7 @@ use crate::{ constants::headers, types::ResponseRouterData, utils::{ - self, convert_amount, is_mandate_supported, to_currency_lower_unit, PaymentMethodDataType, + self, convert_amount, is_mandate_supported, PaymentMethodDataType, PaymentsAuthorizeRequestData, PaymentsCompleteAuthorizeRequestData, }, }; @@ -75,12 +78,14 @@ use crate::{ #[derive(Clone)] pub struct Braintree { amount_converter: &'static (dyn AmountConvertor + Sync), + amount_converter_webhooks: &'static (dyn AmountConvertor + Sync), } impl Braintree { pub const fn new() -> &'static Self { &Self { amount_converter: &StringMajorUnitForConnector, + amount_converter_webhooks: &StringMinorUnitForConnector, } } } @@ -1034,11 +1039,11 @@ impl IncomingWebhook for Braintree { .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?; let response = decode_webhook_payload(notif.bt_payload.replace('\n', "").as_bytes())?; - match response.dispute { Some(dispute_data) => Ok(DisputePayload { - amount: to_currency_lower_unit( - dispute_data.amount_disputed.to_string(), + amount: convert_amount( + self.amount_converter_webhooks, + dispute_data.amount_disputed, dispute_data.currency_iso_code, )?, currency: dispute_data.currency_iso_code, diff --git a/crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs b/crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs index 4c4e766f450..9d6a36117eb 100644 --- a/crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs @@ -1,6 +1,9 @@ use api_models::webhooks::IncomingWebhookEvent; use common_enums::enums; -use common_utils::{pii, types::StringMajorUnit}; +use common_utils::{ + pii, + types::{MinorUnit, StringMajorUnit}, +}; use error_stack::ResultExt; use hyperswitch_domain_models::{ payment_method_data::PaymentMethodData, @@ -2002,7 +2005,7 @@ pub(crate) fn get_status(status: &str) -> IncomingWebhookEvent { #[derive(Debug, Deserialize, Serialize)] pub struct BraintreeDisputeData { - pub amount_disputed: i64, + pub amount_disputed: MinorUnit, pub amount_won: Option, pub case_number: Option, pub chargeback_protection_level: Option, diff --git a/crates/hyperswitch_connectors/src/connectors/checkout.rs b/crates/hyperswitch_connectors/src/connectors/checkout.rs index 91df23088c8..e8d48ae92cf 100644 --- a/crates/hyperswitch_connectors/src/connectors/checkout.rs +++ b/crates/hyperswitch_connectors/src/connectors/checkout.rs @@ -1,5 +1,5 @@ pub mod transformers; -use std::sync::LazyLock; +use std::{convert::TryFrom, sync::LazyLock}; use common_enums::{enums, CallConnectorAction, PaymentAction}; use common_utils::{ @@ -7,7 +7,10 @@ use common_utils::{ errors::CustomResult, ext_traits::ByteSliceExt, request::{Method, Request, RequestBuilder, RequestContent}, - types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, + types::{ + AmountConvertor, MinorUnit, MinorUnitForConnector, StringMinorUnit, + StringMinorUnitForConnector, + }, }; use error_stack::ResultExt; use hyperswitch_domain_models::{ @@ -71,12 +74,14 @@ use crate::{ #[derive(Clone)] pub struct Checkout { amount_converter: &'static (dyn AmountConvertor + Sync), + amount_converter_webhooks: &'static (dyn AmountConvertor + Sync), } impl Checkout { pub fn new() -> &'static Self { &Self { amount_converter: &MinorUnitForConnector, + amount_converter_webhooks: &StringMinorUnitForConnector, } } } @@ -1292,8 +1297,15 @@ impl webhooks::IncomingWebhook for Checkout { .body .parse_struct("CheckoutWebhookBody") .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?; + + let amount = utils::convert_amount( + self.amount_converter_webhooks, + dispute_details.data.amount, + dispute_details.data.currency, + )?; + Ok(DisputePayload { - amount: dispute_details.data.amount.to_string(), + amount, currency: dispute_details.data.currency, dispute_stage: api_models::enums::DisputeStage::from( dispute_details.transaction_type.clone(), diff --git a/crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs b/crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs index d3150a3b049..9d765c2c2e6 100644 --- a/crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs @@ -1267,7 +1267,7 @@ pub struct CheckoutDisputeWebhookData { pub id: String, pub payment_id: Option, pub action_id: Option, - pub amount: i32, + pub amount: MinorUnit, pub currency: enums::Currency, #[serde(default, with = "common_utils::custom_serde::iso8601::option")] pub evidence_required_by: Option, diff --git a/crates/hyperswitch_connectors/src/connectors/novalnet.rs b/crates/hyperswitch_connectors/src/connectors/novalnet.rs index 4c431048e5a..0a6201c9592 100644 --- a/crates/hyperswitch_connectors/src/connectors/novalnet.rs +++ b/crates/hyperswitch_connectors/src/connectors/novalnet.rs @@ -970,7 +970,11 @@ impl webhooks::IncomingWebhook for Novalnet { let dispute_status = novalnet::get_novalnet_dispute_status(notif.event.event_type).to_string(); Ok(disputes::DisputePayload { - amount: novalnet::option_to_result(amount)?.to_string(), + amount: utils::convert_amount( + self.amount_converter, + amount.ok_or(errors::ConnectorError::AmountConversionFailed)?, + novalnet::option_to_result(currency)?, + )?, currency: novalnet::option_to_result(currency)?, dispute_stage: api_models::enums::DisputeStage::Dispute, connector_dispute_id: notif.event.tid.to_string(), diff --git a/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs b/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs index 7eb6398f1b3..de25d080376 100644 --- a/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs @@ -4,7 +4,11 @@ use api_models::webhooks::IncomingWebhookEvent; use cards::CardNumber; use common_enums::{enums, enums as api_enums}; use common_utils::{ - consts, ext_traits::OptionExt, pii::Email, request::Method, types::StringMinorUnit, + consts, + ext_traits::OptionExt, + pii::Email, + request::Method, + types::{MinorUnit, StringMinorUnit}, }; use error_stack::ResultExt; use hyperswitch_domain_models::{ @@ -560,7 +564,7 @@ pub struct ResultData { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct NovalnetPaymentsResponseTransactionData { - pub amount: Option, + pub amount: Option, pub currency: Option, pub date: Option, pub order_no: Option, @@ -732,7 +736,7 @@ pub struct NovalnetAuthorizationResponse { #[derive(Serialize, Deserialize, Clone, Debug)] pub struct NovalnetSyncResponseTransactionData { - pub amount: Option, + pub amount: Option, pub currency: Option, pub date: Option, pub order_no: Option, @@ -898,7 +902,7 @@ pub struct NovalnetRefundSyncResponse { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct NovalnetRefundsTransactionData { - pub amount: Option, + pub amount: Option, pub date: Option, pub currency: Option, pub order_no: Option, @@ -1097,7 +1101,7 @@ impl #[derive(Debug, Clone, Serialize, Deserialize)] pub struct NovalnetCaptureTransactionData { - pub amount: Option, + pub amount: Option, pub capture: CaptureData, pub currency: Option, pub order_no: Option, diff --git a/crates/hyperswitch_connectors/src/connectors/payme.rs b/crates/hyperswitch_connectors/src/connectors/payme.rs index a5b51c8a807..a55d747452b 100644 --- a/crates/hyperswitch_connectors/src/connectors/payme.rs +++ b/crates/hyperswitch_connectors/src/connectors/payme.rs @@ -9,7 +9,7 @@ use common_utils::{ request::{Method, Request, RequestBuilder, RequestContent}, types::{ AmountConvertor, MinorUnit, MinorUnitForConnector, StringMajorUnit, - StringMajorUnitForConnector, + StringMajorUnitForConnector, StringMinorUnit, StringMinorUnitForConnector, }, }; use error_stack::{Report, ResultExt}; @@ -63,6 +63,7 @@ pub struct Payme { amount_converter: &'static (dyn AmountConvertor + Sync), apple_pay_google_pay_amount_converter: &'static (dyn AmountConvertor + Sync), + amount_converter_webhooks: &'static (dyn AmountConvertor + Sync), } impl Payme { @@ -70,6 +71,7 @@ impl Payme { &Self { amount_converter: &MinorUnitForConnector, apple_pay_google_pay_amount_converter: &StringMajorUnitForConnector, + amount_converter_webhooks: &StringMinorUnitForConnector, } } } @@ -1242,7 +1244,11 @@ impl webhooks::IncomingWebhook for Payme { .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?; Ok(DisputePayload { - amount: webhook_object.price.to_string(), + amount: utils::convert_amount( + self.amount_converter_webhooks, + webhook_object.price, + webhook_object.currency, + )?, currency: webhook_object.currency, dispute_stage: api_models::enums::DisputeStage::Dispute, connector_dispute_id: webhook_object.payme_transaction_id, diff --git a/crates/hyperswitch_connectors/src/connectors/payme/transformers.rs b/crates/hyperswitch_connectors/src/connectors/payme/transformers.rs index 06be676ab6b..bf549a49a64 100644 --- a/crates/hyperswitch_connectors/src/connectors/payme/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/payme/transformers.rs @@ -1229,7 +1229,7 @@ pub struct WebhookEventDataResource { pub payme_transaction_id: String, pub status_error_details: Option, pub status_error_code: Option, - pub price: i64, + pub price: MinorUnit, pub currency: enums::Currency, } diff --git a/crates/hyperswitch_connectors/src/connectors/paypal.rs b/crates/hyperswitch_connectors/src/connectors/paypal.rs index 189c012839f..e33c2e0d3a2 100644 --- a/crates/hyperswitch_connectors/src/connectors/paypal.rs +++ b/crates/hyperswitch_connectors/src/connectors/paypal.rs @@ -8,7 +8,10 @@ use common_utils::{ errors::CustomResult, ext_traits::ByteSliceExt, request::{Method, Request, RequestBuilder, RequestContent}, - types::{AmountConvertor, MinorUnit, StringMajorUnit, StringMajorUnitForConnector}, + types::{ + AmountConvertor, MinorUnit, StringMajorUnit, StringMajorUnitForConnector, StringMinorUnit, + StringMinorUnitForConnector, + }, }; use error_stack::ResultExt; use hyperswitch_domain_models::{ @@ -86,12 +89,14 @@ use crate::{ #[derive(Clone)] pub struct Paypal { amount_converter: &'static (dyn AmountConvertor + Sync), + amount_converter_webhooks: &'static (dyn AmountConvertor + Sync), } impl Paypal { pub fn new() -> &'static Self { &Self { amount_converter: &StringMajorUnitForConnector, + amount_converter_webhooks: &StringMinorUnitForConnector, } } } @@ -2024,9 +2029,15 @@ impl IncomingWebhook for Paypal { .attach_printable("Expected Dispute webhooks,but found other webhooks")? } transformers::PaypalResource::PaypalDisputeWebhooks(payload) => { + let amt = connector_utils::convert_back_amount_to_minor_units( + self.amount_converter, + payload.dispute_amount.value, + payload.dispute_amount.currency_code, + )?; Ok(disputes::DisputePayload { - amount: connector_utils::to_currency_lower_unit( - payload.dispute_amount.value.get_amount_as_string(), + amount: connector_utils::convert_amount( + self.amount_converter_webhooks, + amt, payload.dispute_amount.currency_code, )?, currency: payload.dispute_amount.currency_code, diff --git a/crates/hyperswitch_connectors/src/connectors/rapyd.rs b/crates/hyperswitch_connectors/src/connectors/rapyd.rs index 5ec039b30ae..d65d9af8a65 100644 --- a/crates/hyperswitch_connectors/src/connectors/rapyd.rs +++ b/crates/hyperswitch_connectors/src/connectors/rapyd.rs @@ -9,7 +9,10 @@ use common_utils::{ errors::CustomResult, ext_traits::{ByteSliceExt, BytesExt, Encode, StringExt}, request::{Method, Request, RequestBuilder, RequestContent}, - types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector}, + types::{ + AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector, StringMinorUnit, + StringMinorUnitForConnector, + }, }; use error_stack::{Report, ResultExt}; use hyperswitch_domain_models::{ @@ -60,11 +63,13 @@ use crate::{ #[derive(Clone)] pub struct Rapyd { amount_converter: &'static (dyn AmountConvertor + Sync), + amount_converter_webhooks: &'static (dyn AmountConvertor + Sync), } impl Rapyd { pub fn new() -> &'static Self { &Self { amount_converter: &FloatMajorUnitForConnector, + amount_converter_webhooks: &StringMinorUnitForConnector, } } } @@ -926,7 +931,11 @@ impl IncomingWebhook for Rapyd { _ => Err(errors::ConnectorError::WebhookBodyDecodingFailed), }?; Ok(DisputePayload { - amount: webhook_dispute_data.amount.to_string(), + amount: convert_amount( + self.amount_converter_webhooks, + webhook_dispute_data.amount, + webhook_dispute_data.currency, + )?, currency: webhook_dispute_data.currency, dispute_stage: api_models::enums::DisputeStage::Dispute, connector_dispute_id: webhook_dispute_data.token, diff --git a/crates/hyperswitch_connectors/src/connectors/rapyd/transformers.rs b/crates/hyperswitch_connectors/src/connectors/rapyd/transformers.rs index b3e3d880c54..fb77ffe541c 100644 --- a/crates/hyperswitch_connectors/src/connectors/rapyd/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/rapyd/transformers.rs @@ -1,5 +1,9 @@ use common_enums::enums; -use common_utils::{ext_traits::OptionExt, request::Method, types::FloatMajorUnit}; +use common_utils::{ + ext_traits::OptionExt, + request::Method, + types::{FloatMajorUnit, MinorUnit}, +}; use error_stack::ResultExt; use hyperswitch_domain_models::{ payment_method_data::{PaymentMethodData, WalletData}, @@ -287,7 +291,7 @@ pub struct ResponseData { #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct DisputeResponseData { pub id: String, - pub amount: i64, + pub amount: MinorUnit, pub currency: api_models::enums::Currency, pub token: String, pub dispute_reason_description: String, diff --git a/crates/hyperswitch_connectors/src/connectors/stripe.rs b/crates/hyperswitch_connectors/src/connectors/stripe.rs index be1777bac42..e50207c9879 100644 --- a/crates/hyperswitch_connectors/src/connectors/stripe.rs +++ b/crates/hyperswitch_connectors/src/connectors/stripe.rs @@ -10,9 +10,12 @@ use common_enums::{ use common_utils::{ crypto, errors::CustomResult, - ext_traits::{ByteSliceExt as _, BytesExt, OptionExt as _}, + ext_traits::{ByteSliceExt as _, BytesExt}, request::{Method, Request, RequestBuilder, RequestContent}, - types::{AmountConvertor, MinorUnit, MinorUnitForConnector}, + types::{ + AmountConvertor, MinorUnit, MinorUnitForConnector, StringMinorUnit, + StringMinorUnitForConnector, + }, }; use error_stack::ResultExt; use hyperswitch_domain_models::{ @@ -90,12 +93,14 @@ use crate::{ #[derive(Clone)] pub struct Stripe { amount_converter: &'static (dyn AmountConvertor + Sync), + amount_converter_webhooks: &'static (dyn AmountConvertor + Sync), } impl Stripe { pub const fn new() -> &'static Self { &Self { amount_converter: &MinorUnitForConnector, + amount_converter_webhooks: &StringMinorUnitForConnector, } } } @@ -2248,16 +2253,18 @@ impl IncomingWebhook for Stripe { .body .parse_struct("WebhookEvent") .change_context(ConnectorError::WebhookBodyDecodingFailed)?; + let amt = details.event_data.event_object.amount.ok_or_else(|| { + ConnectorError::MissingRequiredField { + field_name: "amount", + } + })?; + Ok(DisputePayload { - amount: details - .event_data - .event_object - .amount - .get_required_value("amount") - .change_context(ConnectorError::MissingRequiredField { - field_name: "amount", - })? - .to_string(), + amount: utils::convert_amount( + self.amount_converter_webhooks, + amt, + details.event_data.event_object.currency, + )?, currency: details.event_data.event_object.currency, dispute_stage: api_models::enums::DisputeStage::Dispute, connector_dispute_id: details.event_data.event_object.id, diff --git a/crates/hyperswitch_connectors/src/connectors/stripe/transformers.rs b/crates/hyperswitch_connectors/src/connectors/stripe/transformers.rs index 73d9007706c..47c0f94aa12 100644 --- a/crates/hyperswitch_connectors/src/connectors/stripe/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/stripe/transformers.rs @@ -3701,7 +3701,7 @@ pub struct WebhookPaymentMethodDetails { pub struct WebhookEventObjectData { pub id: String, pub object: WebhookEventObjectType, - pub amount: Option, + pub amount: Option, #[serde(default, deserialize_with = "convert_uppercase")] pub currency: enums::Currency, pub payment_intent: Option, diff --git a/crates/hyperswitch_connectors/src/connectors/trustpay.rs b/crates/hyperswitch_connectors/src/connectors/trustpay.rs index 6ae7ee104e1..4c7d774a38f 100644 --- a/crates/hyperswitch_connectors/src/connectors/trustpay.rs +++ b/crates/hyperswitch_connectors/src/connectors/trustpay.rs @@ -7,7 +7,10 @@ use common_utils::{ errors::{CustomResult, ReportSwitchExt}, ext_traits::ByteSliceExt, request::{Method, Request, RequestBuilder, RequestContent}, - types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector}, + types::{ + AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector, StringMajorUnit, + StringMajorUnitForConnector, StringMinorUnit, StringMinorUnitForConnector, + }, }; use error_stack::{Report, ResultExt}; use hyperswitch_domain_models::{ @@ -57,12 +60,18 @@ use crate::{ #[derive(Clone)] pub struct Trustpay { amount_converter: &'static (dyn AmountConvertor + Sync), + amount_converter_to_float_major_unit: + &'static (dyn AmountConvertor + Sync), + amount_converter_to_string_minor_unit: + &'static (dyn AmountConvertor + Sync), } impl Trustpay { pub fn new() -> &'static Self { &Self { amount_converter: &StringMajorUnitForConnector, + amount_converter_to_float_major_unit: &FloatMajorUnitForConnector, + amount_converter_to_string_minor_unit: &StringMinorUnitForConnector, } } } @@ -965,8 +974,17 @@ impl webhooks::IncomingWebhook for Trustpay { .references .payment_id .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?; + let amount = utils::convert_back_amount_to_minor_units( + self.amount_converter_to_float_major_unit, + payment_info.amount.amount, + payment_info.amount.currency, + )?; Ok(DisputePayload { - amount: payment_info.amount.amount.to_string(), + amount: utils::convert_amount( + self.amount_converter_to_string_minor_unit, + amount, + payment_info.amount.currency, + )?, currency: payment_info.amount.currency, dispute_stage: api_models::enums::DisputeStage::Dispute, connector_dispute_id, diff --git a/crates/hyperswitch_connectors/src/connectors/trustpay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/trustpay/transformers.rs index e0114269612..d3cfe77c4b1 100644 --- a/crates/hyperswitch_connectors/src/connectors/trustpay/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/trustpay/transformers.rs @@ -6,7 +6,7 @@ use common_utils::{ errors::CustomResult, pii::{self, Email}, request::Method, - types::StringMajorUnit, + types::{FloatMajorUnit, StringMajorUnit}, }; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{ @@ -1904,7 +1904,7 @@ pub struct WebhookReferences { #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "PascalCase")] pub struct WebhookAmount { - pub amount: f64, + pub amount: FloatMajorUnit, pub currency: enums::Currency, } diff --git a/crates/hyperswitch_connectors/src/utils.rs b/crates/hyperswitch_connectors/src/utils.rs index 80c9f63ca49..468a98ae31c 100644 --- a/crates/hyperswitch_connectors/src/utils.rs +++ b/crates/hyperswitch_connectors/src/utils.rs @@ -133,15 +133,6 @@ pub(crate) fn to_currency_base_unit( .change_context(errors::ConnectorError::ParsingFailed) } -pub(crate) fn to_currency_lower_unit( - amount: String, - currency: enums::Currency, -) -> Result> { - currency - .to_currency_lower_unit(amount) - .change_context(errors::ConnectorError::ResponseHandlingFailed) -} - pub trait ConnectorErrorTypeMapping { fn get_connector_error_type( &self, diff --git a/crates/hyperswitch_interfaces/src/disputes.rs b/crates/hyperswitch_interfaces/src/disputes.rs index 55a6d13c91d..55965fb2c6d 100644 --- a/crates/hyperswitch_interfaces/src/disputes.rs +++ b/crates/hyperswitch_interfaces/src/disputes.rs @@ -1,12 +1,12 @@ //! Disputes interface - +use common_utils::types::StringMinorUnit; use time::PrimitiveDateTime; /// struct DisputePayload #[derive(Default, Debug)] pub struct DisputePayload { /// amount - pub amount: String, + pub amount: StringMinorUnit, /// currency pub currency: common_enums::enums::Currency, /// dispute_stage diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index b042d2bdbd6..ecc047d21ff 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -205,6 +205,7 @@ Never share your secret api keys. Keep them guarded and secure. ), components(schemas( common_utils::types::MinorUnit, + common_utils::types::StringMinorUnit, common_utils::types::TimeRange, common_utils::link_utils::GenericLinkUiConfig, common_utils::link_utils::EnabledPaymentMethod, diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index 9b8387389fe..1fa023b1b1f 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -160,6 +160,7 @@ Never share your secret api keys. Keep them guarded and secure. ), components(schemas( common_utils::types::MinorUnit, + common_utils::types::StringMinorUnit, common_utils::types::TimeRange, common_utils::types::BrowserInformation, common_utils::link_utils::GenericLinkUiConfig, diff --git a/crates/router/src/compatibility/stripe/webhooks.rs b/crates/router/src/compatibility/stripe/webhooks.rs index 2212a8953fc..f5dde401b35 100644 --- a/crates/router/src/compatibility/stripe/webhooks.rs +++ b/crates/router/src/compatibility/stripe/webhooks.rs @@ -218,7 +218,7 @@ impl From for StripeDisputeResponse { fn from(res: api_models::disputes::DisputeResponse) -> Self { Self { id: res.dispute_id, - amount: res.amount, + amount: res.amount.to_string(), currency: res.currency, payment_intent: res.payment_id, reason: res.connector_reason, diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index f50308d932c..2152c56341d 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -4,7 +4,12 @@ use actix_web::FromRequest; #[cfg(feature = "payouts")] use api_models::payouts as payout_models; use api_models::webhooks::{self, WebhookResponseTracker}; -use common_utils::{errors::ReportSwitchExt, events::ApiEventsType, ext_traits::AsyncExt}; +use common_utils::{ + errors::ReportSwitchExt, + events::ApiEventsType, + ext_traits::AsyncExt, + types::{AmountConvertor, StringMinorUnitForConnector}, +}; use diesel_models::ConnectorMandateReferenceId; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{ @@ -1187,7 +1192,16 @@ async fn get_or_update_dispute_object( profile_id: Some(business_profile.get_id().to_owned()), evidence: None, merchant_connector_id: payment_attempt.merchant_connector_id.clone(), - dispute_amount: dispute_details.amount.parse::().unwrap_or(0), + dispute_amount: StringMinorUnitForConnector::convert_back( + &StringMinorUnitForConnector, + dispute_details.amount, + dispute_details.currency, + ) + .change_context( + errors::ApiErrorResponse::AmountConversionFailed { + amount_type: "MinorUnit", + }, + )?, organization_id: organization_id.clone(), dispute_currency: Some(dispute_details.currency), }; diff --git a/crates/router/src/db/dispute.rs b/crates/router/src/db/dispute.rs index 054f949059d..6ba8a72f5c6 100644 --- a/crates/router/src/db/dispute.rs +++ b/crates/router/src/db/dispute.rs @@ -463,6 +463,8 @@ mod tests { mod mockdb_dispute_interface { use std::borrow::Cow; + use common_enums::enums::Currency; + use common_utils::types::{AmountConvertor, MinorUnit, StringMinorUnitForConnector}; use diesel_models::{ dispute::DisputeNew, enums::{DisputeStage, DisputeStatus}, @@ -486,7 +488,12 @@ mod tests { fn create_dispute_new(dispute_ids: DisputeNewIds) -> DisputeNew { DisputeNew { dispute_id: dispute_ids.dispute_id, - amount: "amount".into(), + amount: StringMinorUnitForConnector::convert( + &StringMinorUnitForConnector, + MinorUnit::new(0), + Currency::USD, + ) + .expect("Amount Conversion Error"), currency: "currency".into(), dispute_stage: DisputeStage::Dispute, dispute_status: DisputeStatus::DisputeOpened, @@ -504,9 +511,9 @@ mod tests { evidence: Some(Secret::from(Value::String("evidence".into()))), profile_id: Some(common_utils::generate_profile_id_of_default_length()), merchant_connector_id: None, - dispute_amount: 1040, + dispute_amount: MinorUnit::new(1040), organization_id: common_utils::id_type::OrganizationId::default(), - dispute_currency: Some(common_enums::Currency::default()), + dispute_currency: Some(Currency::default()), } } diff --git a/crates/router/src/services/kafka/dispute.rs b/crates/router/src/services/kafka/dispute.rs index 4414af494f2..b0478b6a57f 100644 --- a/crates/router/src/services/kafka/dispute.rs +++ b/crates/router/src/services/kafka/dispute.rs @@ -1,4 +1,8 @@ -use common_utils::{ext_traits::StringExt, id_type}; +use common_utils::{ + ext_traits::StringExt, + id_type, + types::{AmountConvertor, MinorUnit, StringMinorUnitForConnector}, +}; use diesel_models::enums as storage_enums; use masking::Secret; use time::OffsetDateTime; @@ -8,7 +12,7 @@ use crate::types::storage::dispute::Dispute; #[derive(serde::Serialize, Debug)] pub struct KafkaDispute<'a> { pub dispute_id: &'a String, - pub dispute_amount: i64, + pub dispute_amount: MinorUnit, pub currency: storage_enums::Currency, pub dispute_stage: &'a storage_enums::DisputeStage, pub dispute_status: &'a storage_enums::DisputeStatus, @@ -38,16 +42,25 @@ pub struct KafkaDispute<'a> { impl<'a> KafkaDispute<'a> { pub fn from_storage(dispute: &'a Dispute) -> Self { + let currency = dispute.dispute_currency.unwrap_or( + dispute + .currency + .to_uppercase() + .parse_enum("Currency") + .unwrap_or_default(), + ); Self { dispute_id: &dispute.dispute_id, - dispute_amount: dispute.amount.parse::().unwrap_or_default(), - currency: dispute.dispute_currency.unwrap_or( - dispute - .currency - .to_uppercase() - .parse_enum("Currency") - .unwrap_or_default(), - ), + dispute_amount: StringMinorUnitForConnector::convert_back( + &StringMinorUnitForConnector, + dispute.amount.clone(), + currency, + ) + .unwrap_or_else(|e| { + router_env::logger::error!("Failed to convert dispute amount: {e:?}"); + MinorUnit::new(0) + }), + currency, dispute_stage: &dispute.dispute_stage, dispute_status: &dispute.dispute_status, payment_id: &dispute.payment_id, diff --git a/crates/router/src/services/kafka/dispute_event.rs b/crates/router/src/services/kafka/dispute_event.rs index 45e7ff2c798..13301c30288 100644 --- a/crates/router/src/services/kafka/dispute_event.rs +++ b/crates/router/src/services/kafka/dispute_event.rs @@ -1,4 +1,7 @@ -use common_utils::ext_traits::StringExt; +use common_utils::{ + ext_traits::StringExt, + types::{AmountConvertor, MinorUnit, StringMinorUnitForConnector}, +}; use diesel_models::enums as storage_enums; use masking::Secret; use time::OffsetDateTime; @@ -9,7 +12,7 @@ use crate::types::storage::dispute::Dispute; #[derive(serde::Serialize, Debug)] pub struct KafkaDisputeEvent<'a> { pub dispute_id: &'a String, - pub dispute_amount: i64, + pub dispute_amount: MinorUnit, pub currency: storage_enums::Currency, pub dispute_stage: &'a storage_enums::DisputeStage, pub dispute_status: &'a storage_enums::DisputeStatus, @@ -39,16 +42,25 @@ pub struct KafkaDisputeEvent<'a> { impl<'a> KafkaDisputeEvent<'a> { pub fn from_storage(dispute: &'a Dispute) -> Self { + let currency = dispute.dispute_currency.unwrap_or( + dispute + .currency + .to_uppercase() + .parse_enum("Currency") + .unwrap_or_default(), + ); Self { dispute_id: &dispute.dispute_id, - dispute_amount: dispute.amount.parse::().unwrap_or_default(), - currency: dispute.dispute_currency.unwrap_or( - dispute - .currency - .to_uppercase() - .parse_enum("Currency") - .unwrap_or_default(), - ), + dispute_amount: StringMinorUnitForConnector::convert_back( + &StringMinorUnitForConnector, + dispute.amount.clone(), + currency, + ) + .unwrap_or_else(|e| { + router_env::logger::error!("Failed to convert dispute amount: {e:?}"); + MinorUnit::new(0) + }), + currency, dispute_stage: &dispute.dispute_stage, dispute_status: &dispute.dispute_status, payment_id: &dispute.payment_id, diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs index 7f501d3a9e5..e98cc78a41e 100644 --- a/crates/router/src/types/api.rs +++ b/crates/router/src/types/api.rs @@ -334,7 +334,7 @@ impl ConnectorData { connector::Adyenplatform::new(), ))), enums::Connector::Airwallex => { - Ok(ConnectorEnum::Old(Box::new(&connector::Airwallex))) + Ok(ConnectorEnum::Old(Box::new(connector::Airwallex::new()))) } // enums::Connector::Amazonpay => { // Ok(ConnectorEnum::Old(Box::new(connector::Amazonpay))) diff --git a/crates/router/src/utils/user/sample_data.rs b/crates/router/src/utils/user/sample_data.rs index dddded4c3d5..989e7db3c0c 100644 --- a/crates/router/src/utils/user/sample_data.rs +++ b/crates/router/src/utils/user/sample_data.rs @@ -4,7 +4,7 @@ use api_models::{ }; use common_utils::{ id_type, - types::{ConnectorTransactionId, MinorUnit}, + types::{AmountConvertor, ConnectorTransactionId, MinorUnit, StringMinorUnitForConnector}, }; #[cfg(feature = "v1")] use diesel_models::user::sample_data::PaymentAttemptBatchNew; @@ -430,13 +430,18 @@ pub async fn generate_sample_data( let dispute = if disputes_count < number_of_disputes && !is_failed_payment && refund.is_none() { disputes_count += 1; + let currency = payment_intent + .currency + .unwrap_or(common_enums::Currency::USD); Some(DisputeNew { dispute_id: common_utils::generate_id_with_default_len("test"), - amount: (amount * 100).to_string(), - currency: payment_intent - .currency - .unwrap_or(common_enums::Currency::USD) - .to_string(), + amount: StringMinorUnitForConnector::convert( + &StringMinorUnitForConnector, + MinorUnit::new(amount * 100), + currency, + ) + .change_context(SampleDataError::InternalServerError)?, + currency: currency.to_string(), dispute_stage: storage_enums::DisputeStage::Dispute, dispute_status: storage_enums::DisputeStatus::DisputeOpened, payment_id: payment_id.clone(), @@ -456,7 +461,7 @@ pub async fn generate_sample_data( evidence: None, profile_id: payment_intent.profile_id.clone(), merchant_connector_id: payment_attempt.merchant_connector_id.clone(), - dispute_amount: amount * 100, + dispute_amount: MinorUnit::new(amount * 100), organization_id: org_id.clone(), dispute_currency: Some(payment_intent.currency.unwrap_or_default()), }) diff --git a/crates/router/tests/connectors/airwallex.rs b/crates/router/tests/connectors/airwallex.rs index bf5a06f157a..a399d648da9 100644 --- a/crates/router/tests/connectors/airwallex.rs +++ b/crates/router/tests/connectors/airwallex.rs @@ -19,7 +19,7 @@ impl Connector for AirwallexTest { fn get_data(&self) -> types::api::ConnectorData { use router::connector::Airwallex; utils::construct_connector_data_old( - Box::new(&Airwallex), + Box::new(Airwallex::new()), types::Connector::Airwallex, types::api::GetToken::Connector, None,