Skip to content

Commit

Permalink
fix(dispute): change dispute currency type to currency enum (#6454)
Browse files Browse the repository at this point in the history
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
  • Loading branch information
ImSagnik007 and hyperswitch-bot[bot] authored Nov 20, 2024
1 parent 012e352 commit 98aa84b
Show file tree
Hide file tree
Showing 30 changed files with 95 additions and 61 deletions.
3 changes: 1 addition & 2 deletions api-reference-v2/openapi_spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -7192,8 +7192,7 @@
"description": "The dispute amount"
},
"currency": {
"type": "string",
"description": "The three-letter ISO currency code"
"$ref": "#/components/schemas/Currency"
},
"dispute_stage": {
"$ref": "#/components/schemas/DisputeStage"
Expand Down
3 changes: 1 addition & 2 deletions api-reference/openapi_spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -10040,8 +10040,7 @@
"description": "The dispute amount"
},
"currency": {
"type": "string",
"description": "The three-letter ISO currency code"
"$ref": "#/components/schemas/Currency"
},
"dispute_stage": {
"$ref": "#/components/schemas/DisputeStage"
Expand Down
11 changes: 6 additions & 5 deletions crates/api_models/src/disputes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use serde::de::Error;
use time::PrimitiveDateTime;
use utoipa::ToSchema;

use super::enums::{DisputeStage, DisputeStatus};
use crate::{admin::MerchantConnectorInfo, enums, files};
use super::enums::{Currency, DisputeStage, DisputeStatus};
use crate::{admin::MerchantConnectorInfo, files};

#[derive(Clone, Debug, Serialize, ToSchema, Eq, PartialEq)]
pub struct DisputeResponse {
Expand All @@ -21,7 +21,8 @@ pub struct DisputeResponse {
/// The dispute amount
pub amount: String,
/// The three-letter ISO currency code
pub currency: String,
#[schema(value_type = Currency)]
pub currency: Currency,
/// Stage of the dispute
pub dispute_stage: DisputeStage,
/// Status of the dispute
Expand Down Expand Up @@ -137,7 +138,7 @@ pub struct DisputeListGetConstraints {
pub connector: Option<Vec<String>>,
/// The comma separated list of currencies of the disputes
#[serde(default, deserialize_with = "parse_comma_separated")]
pub currency: Option<Vec<common_enums::Currency>>,
pub currency: Option<Vec<Currency>>,
/// The merchant connector id to filter the disputes list
pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
/// The time range for which objects are needed. TimeRange has two fields start_time and end_time from which objects can be filtered as per required scenarios (created_at, time less than, greater than etc).
Expand All @@ -150,7 +151,7 @@ pub struct DisputeListFilters {
/// The map of available connector filters, where the key is the connector name and the value is a list of MerchantConnectorInfo instances
pub connector: HashMap<String, Vec<MerchantConnectorInfo>>,
/// The list of available currency filters
pub currency: Vec<enums::Currency>,
pub currency: Vec<Currency>,
/// The list of available dispute status filters
pub dispute_status: Vec<DisputeStatus>,
/// The list of available dispute stage filters
Expand Down
2 changes: 2 additions & 0 deletions crates/diesel_models/src/dispute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub struct DisputeNew {
pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
pub dispute_amount: i64,
pub organization_id: common_utils::id_type::OrganizationId,
pub dispute_currency: Option<storage_enums::Currency>,
}

#[derive(Clone, Debug, PartialEq, Serialize, Identifiable, Queryable, Selectable)]
Expand Down Expand Up @@ -61,6 +62,7 @@ pub struct Dispute {
pub merchant_connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
pub dispute_amount: i64,
pub organization_id: common_utils::id_type::OrganizationId,
pub dispute_currency: Option<storage_enums::Currency>,
}

#[derive(Debug)]
Expand Down
1 change: 1 addition & 0 deletions crates/diesel_models/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ diesel::table! {
dispute_amount -> Int8,
#[max_length = 32]
organization_id -> Varchar,
dispute_currency -> Nullable<Currency>,
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/diesel_models/src/schema_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ diesel::table! {
dispute_amount -> Int8,
#[max_length = 32]
organization_id -> Varchar,
dispute_currency -> Nullable<Currency>,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,7 @@ pub struct AirwallexObjectData {
pub struct AirwallexDisputeObject {
pub payment_intent_id: String,
pub dispute_amount: i64,
pub dispute_currency: String,
pub dispute_currency: enums::Currency,
pub stage: AirwallexDisputeStage,
pub dispute_id: String,
pub dispute_reason_type: Option<String>,
Expand Down
2 changes: 1 addition & 1 deletion crates/hyperswitch_connectors/src/connectors/novalnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@ impl webhooks::IncomingWebhook for Novalnet {
novalnet::get_novalnet_dispute_status(notif.event.event_type).to_string();
Ok(disputes::DisputePayload {
amount: novalnet::option_to_result(amount)?.to_string(),
currency: novalnet::option_to_result(currency)?.to_string(),
currency: novalnet::option_to_result(currency)?,
dispute_stage: api_models::enums::DisputeStage::Dispute,
connector_dispute_id: notif.event.tid.to_string(),
connector_reason: reason,
Expand Down
2 changes: 1 addition & 1 deletion crates/hyperswitch_interfaces/src/disputes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub struct DisputePayload {
/// amount
pub amount: String,
/// currency
pub currency: String,
pub currency: common_enums::enums::Currency,
/// dispute_stage
pub dispute_stage: common_enums::enums::DisputeStage,
/// connector_status
Expand Down
4 changes: 2 additions & 2 deletions crates/router/src/compatibility/stripe/webhooks.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(feature = "payouts")]
use api_models::payouts as payout_models;
use api_models::{
enums::{DisputeStatus, MandateStatus},
enums::{Currency, DisputeStatus, MandateStatus},
webhooks::{self as api},
};
#[cfg(feature = "payouts")]
Expand Down Expand Up @@ -93,7 +93,7 @@ pub enum StripeWebhookObject {
pub struct StripeDisputeResponse {
pub id: String,
pub amount: String,
pub currency: String,
pub currency: Currency,
pub payment_intent: common_utils::id_type::PaymentId,
pub reason: Option<String>,
pub status: StripeDisputeStatus,
Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/connector/adyen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1895,7 +1895,7 @@ impl api::IncomingWebhook for Adyen {
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
Ok(api::disputes::DisputePayload {
amount: notif.amount.value.to_string(),
currency: notif.amount.currency.to_string(),
currency: notif.amount.currency,
dispute_stage: api_models::enums::DisputeStage::from(notif.event_code.clone()),
connector_dispute_id: notif.psp_reference,
connector_reason: notif.reason,
Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/connector/bluesnap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,7 @@ impl api::IncomingWebhook for Bluesnap {
dispute_details.invoice_charge_amount.abs().to_string(),
dispute_details.currency,
)?,
currency: dispute_details.currency.to_string(),
currency: dispute_details.currency,
dispute_stage: api_models::enums::DisputeStage::Dispute,
connector_dispute_id: dispute_details.reversal_ref_num,
connector_reason: dispute_details.reversal_reason,
Expand Down
35 changes: 15 additions & 20 deletions crates/router/src/connector/braintree.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
pub mod transformers;
use std::str::FromStr;

use api_models::webhooks::IncomingWebhookEvent;
use base64::Engine;
Expand Down Expand Up @@ -998,25 +997,21 @@ impl api::IncomingWebhook for Braintree {
let response = decode_webhook_payload(notif.bt_payload.replace('\n', "").as_bytes())?;

match response.dispute {
Some(dispute_data) => {
let currency = enums::Currency::from_str(dispute_data.currency_iso_code.as_str())
.change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
Ok(api::disputes::DisputePayload {
amount: connector_utils::to_currency_lower_unit(
dispute_data.amount_disputed.to_string(),
currency,
)?,
currency: dispute_data.currency_iso_code,
dispute_stage: transformers::get_dispute_stage(dispute_data.kind.as_str())?,
connector_dispute_id: dispute_data.id,
connector_reason: dispute_data.reason,
connector_reason_code: dispute_data.reason_code,
challenge_required_by: dispute_data.reply_by_date,
connector_status: dispute_data.status,
created_at: dispute_data.created_at,
updated_at: dispute_data.updated_at,
})
}
Some(dispute_data) => Ok(api::disputes::DisputePayload {
amount: connector_utils::to_currency_lower_unit(
dispute_data.amount_disputed.to_string(),
dispute_data.currency_iso_code,
)?,
currency: dispute_data.currency_iso_code,
dispute_stage: transformers::get_dispute_stage(dispute_data.kind.as_str())?,
connector_dispute_id: dispute_data.id,
connector_reason: dispute_data.reason,
connector_reason_code: dispute_data.reason_code,
challenge_required_by: dispute_data.reply_by_date,
connector_status: dispute_data.status,
created_at: dispute_data.created_at,
updated_at: dispute_data.updated_at,
}),
None => Err(errors::ConnectorError::WebhookResourceObjectNotFound)?,
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/connector/braintree/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1766,7 +1766,7 @@ pub struct BraintreeDisputeData {
pub amount_won: Option<String>,
pub case_number: Option<String>,
pub chargeback_protection_level: Option<String>,
pub currency_iso_code: String,
pub currency_iso_code: enums::Currency,
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub created_at: Option<PrimitiveDateTime>,
pub evidence: Option<DisputeEvidence>,
Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/connector/checkout/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1252,7 +1252,7 @@ pub struct CheckoutDisputeWebhookData {
pub payment_id: Option<String>,
pub action_id: Option<String>,
pub amount: i32,
pub currency: String,
pub currency: enums::Currency,
#[serde(default, with = "common_utils::custom_serde::iso8601::option")]
pub evidence_required_by: Option<PrimitiveDateTime>,
pub reason_code: Option<String>,
Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/connector/payme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1280,7 +1280,7 @@ impl api::IncomingWebhook for Payme {

Ok(api::disputes::DisputePayload {
amount: webhook_object.price.to_string(),
currency: webhook_object.currency.to_string(),
currency: webhook_object.currency,
dispute_stage: api_models::enums::DisputeStage::Dispute,
connector_dispute_id: webhook_object.payme_transaction_id,
connector_reason: None,
Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/connector/paypal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2001,7 +2001,7 @@ impl api::IncomingWebhook for Paypal {
payload.dispute_amount.value.get_amount_as_string(),
payload.dispute_amount.currency_code,
)?,
currency: payload.dispute_amount.currency_code.to_string(),
currency: payload.dispute_amount.currency_code,
dispute_stage: api_models::enums::DisputeStage::from(
payload.dispute_life_cycle_stage.clone(),
),
Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/connector/rapyd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,7 @@ impl api::IncomingWebhook for Rapyd {
}?;
Ok(api::disputes::DisputePayload {
amount: webhook_dispute_data.amount.to_string(),
currency: webhook_dispute_data.currency.to_string(),
currency: webhook_dispute_data.currency,
dispute_stage: api_models::enums::DisputeStage::Dispute,
connector_dispute_id: webhook_dispute_data.token,
connector_reason: Some(webhook_dispute_data.dispute_reason_description),
Expand Down
3 changes: 2 additions & 1 deletion crates/router/src/connector/stripe/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3640,7 +3640,8 @@ pub struct WebhookEventObjectData {
pub id: String,
pub object: WebhookEventObjectType,
pub amount: Option<i32>,
pub currency: String,
#[serde(default, deserialize_with = "connector_util::convert_uppercase")]
pub currency: enums::Currency,
pub payment_intent: Option<String>,
pub client_secret: Option<Secret<String>>,
pub reason: Option<String>,
Expand Down
2 changes: 1 addition & 1 deletion crates/router/src/connector/trustpay/transformers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1790,7 +1790,7 @@ pub struct WebhookReferences {
#[serde(rename_all = "PascalCase")]
pub struct WebhookAmount {
pub amount: f64,
pub currency: String,
pub currency: enums::Currency,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
Expand Down
13 changes: 12 additions & 1 deletion crates/router/src/connector/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use hyperswitch_domain_models::{
SyncIntegrityObject,
},
};
use masking::{ExposeInterface, Secret};
use masking::{Deserialize, ExposeInterface, Secret};
use once_cell::sync::Lazy;
use regex::Regex;
use serde::Serializer;
Expand Down Expand Up @@ -3143,3 +3143,14 @@ impl NetworkTokenData for domain::NetworkTokenData {
Secret::new(year)
}
}

pub fn convert_uppercase<'de, D, T>(v: D) -> Result<T, D::Error>
where
D: serde::Deserializer<'de>,
T: FromStr,
<T as FromStr>::Err: std::fmt::Debug + std::fmt::Display + std::error::Error,
{
use serde::de::Error;
let output = <&str>::deserialize(v)?;
output.to_uppercase().parse::<T>().map_err(D::Error::custom)
}
3 changes: 2 additions & 1 deletion crates/router/src/core/webhooks/incoming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,7 @@ async fn get_or_update_dispute_object(
let new_dispute = diesel_models::dispute::DisputeNew {
dispute_id,
amount: dispute_details.amount.clone(),
currency: dispute_details.currency,
currency: dispute_details.currency.to_string(),
dispute_stage: dispute_details.dispute_stage,
dispute_status: common_enums::DisputeStatus::foreign_try_from(event_type)
.change_context(errors::ApiErrorResponse::WebhookProcessingFailure)
Expand All @@ -963,6 +963,7 @@ async fn get_or_update_dispute_object(
merchant_connector_id: payment_attempt.merchant_connector_id.clone(),
dispute_amount: dispute_details.amount.parse::<i64>().unwrap_or(0),
organization_id: organization_id.clone(),
dispute_currency: Some(dispute_details.currency),
};
state
.store
Expand Down
11 changes: 8 additions & 3 deletions crates/router/src/db/dispute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ impl DisputeInterface for MockDb {
merchant_connector_id: dispute.merchant_connector_id,
dispute_amount: dispute.dispute_amount,
organization_id: dispute.organization_id,
dispute_currency: dispute.dispute_currency,
};

locked_disputes.push(new_dispute.clone());
Expand Down Expand Up @@ -308,9 +309,12 @@ impl DisputeInterface for MockDb {
.currency
.as_ref()
.map_or(true, |currencies| {
currencies
.iter()
.any(|currency| dispute.currency.as_str() == currency.to_string())
currencies.iter().any(|currency| {
dispute
.dispute_currency
.map(|dispute_currency| &dispute_currency == currency)
.unwrap_or(dispute.currency.as_str() == currency.to_string())
})
})
&& dispute_constraints
.time_range
Expand Down Expand Up @@ -502,6 +506,7 @@ mod tests {
merchant_connector_id: None,
dispute_amount: 1040,
organization_id: common_utils::id_type::OrganizationId::default(),
dispute_currency: Some(common_enums::Currency::default()),
}
}

Expand Down
12 changes: 9 additions & 3 deletions crates/router/src/services/kafka/dispute.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use common_utils::id_type;
use common_utils::{ext_traits::StringExt, id_type};
use diesel_models::enums as storage_enums;
use masking::Secret;
use time::OffsetDateTime;
Expand All @@ -9,7 +9,7 @@ use crate::types::storage::dispute::Dispute;
pub struct KafkaDispute<'a> {
pub dispute_id: &'a String,
pub dispute_amount: i64,
pub currency: &'a String,
pub currency: storage_enums::Currency,
pub dispute_stage: &'a storage_enums::DisputeStage,
pub dispute_status: &'a storage_enums::DisputeStatus,
pub payment_id: &'a id_type::PaymentId,
Expand Down Expand Up @@ -41,7 +41,13 @@ impl<'a> KafkaDispute<'a> {
Self {
dispute_id: &dispute.dispute_id,
dispute_amount: dispute.amount.parse::<i64>().unwrap_or_default(),
currency: &dispute.currency,
currency: dispute.dispute_currency.unwrap_or(
dispute
.currency
.to_uppercase()
.parse_enum("Currency")
.unwrap_or_default(),
),
dispute_stage: &dispute.dispute_stage,
dispute_status: &dispute.dispute_status,
payment_id: &dispute.payment_id,
Expand Down
11 changes: 9 additions & 2 deletions crates/router/src/services/kafka/dispute_event.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use common_utils::ext_traits::StringExt;
use diesel_models::enums as storage_enums;
use masking::Secret;
use time::OffsetDateTime;
Expand All @@ -9,7 +10,7 @@ use crate::types::storage::dispute::Dispute;
pub struct KafkaDisputeEvent<'a> {
pub dispute_id: &'a String,
pub dispute_amount: i64,
pub currency: &'a String,
pub currency: storage_enums::Currency,
pub dispute_stage: &'a storage_enums::DisputeStage,
pub dispute_status: &'a storage_enums::DisputeStatus,
pub payment_id: &'a common_utils::id_type::PaymentId,
Expand Down Expand Up @@ -41,7 +42,13 @@ impl<'a> KafkaDisputeEvent<'a> {
Self {
dispute_id: &dispute.dispute_id,
dispute_amount: dispute.amount.parse::<i64>().unwrap_or_default(),
currency: &dispute.currency,
currency: dispute.dispute_currency.unwrap_or(
dispute
.currency
.to_uppercase()
.parse_enum("Currency")
.unwrap_or_default(),
),
dispute_stage: &dispute.dispute_stage,
dispute_status: &dispute.dispute_status,
payment_id: &dispute.payment_id,
Expand Down
Loading

0 comments on commit 98aa84b

Please sign in to comment.