diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 53b8c636dab7..c6a1fad0d352 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -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" diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 1ba6ac636b84..353e9d5d49b3 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -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" diff --git a/crates/api_models/src/disputes.rs b/crates/api_models/src/disputes.rs index 4ddb50af0f2a..5b0de11f2d05 100644 --- a/crates/api_models/src/disputes.rs +++ b/crates/api_models/src/disputes.rs @@ -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 { @@ -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 @@ -137,7 +138,7 @@ pub struct DisputeListGetConstraints { pub connector: Option>, /// The comma separated list of currencies of the disputes #[serde(default, deserialize_with = "parse_comma_separated")] - pub currency: Option>, + pub currency: Option>, /// The merchant connector id to filter the disputes list pub merchant_connector_id: Option, /// 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). @@ -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>, /// The list of available currency filters - pub currency: Vec, + pub currency: Vec, /// The list of available dispute status filters pub dispute_status: Vec, /// The list of available dispute stage filters diff --git a/crates/diesel_models/src/dispute.rs b/crates/diesel_models/src/dispute.rs index 130e46aa9cc1..8e3bab20d89c 100644 --- a/crates/diesel_models/src/dispute.rs +++ b/crates/diesel_models/src/dispute.rs @@ -31,6 +31,7 @@ pub struct DisputeNew { pub merchant_connector_id: Option, pub dispute_amount: i64, pub organization_id: common_utils::id_type::OrganizationId, + pub dispute_currency: Option, } #[derive(Clone, Debug, PartialEq, Serialize, Identifiable, Queryable, Selectable)] @@ -61,6 +62,7 @@ pub struct Dispute { pub merchant_connector_id: Option, pub dispute_amount: i64, pub organization_id: common_utils::id_type::OrganizationId, + pub dispute_currency: Option, } #[derive(Debug)] diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs index 19a0763d770c..2b815db390c0 100644 --- a/crates/diesel_models/src/schema.rs +++ b/crates/diesel_models/src/schema.rs @@ -384,6 +384,7 @@ diesel::table! { dispute_amount -> Int8, #[max_length = 32] organization_id -> Varchar, + dispute_currency -> Nullable, } } diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index aa7f3f7232c6..aea22e3d7c68 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -396,6 +396,7 @@ diesel::table! { dispute_amount -> Int8, #[max_length = 32] organization_id -> Varchar, + dispute_currency -> Nullable, } } diff --git a/crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs b/crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs index bb3bc3990772..040a1422e0e0 100644 --- a/crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs @@ -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, diff --git a/crates/hyperswitch_connectors/src/connectors/novalnet.rs b/crates/hyperswitch_connectors/src/connectors/novalnet.rs index 8331e229acb9..fd7ff906d08a 100644 --- a/crates/hyperswitch_connectors/src/connectors/novalnet.rs +++ b/crates/hyperswitch_connectors/src/connectors/novalnet.rs @@ -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, diff --git a/crates/hyperswitch_interfaces/src/disputes.rs b/crates/hyperswitch_interfaces/src/disputes.rs index acc7b56e906e..55a6d13c91d1 100644 --- a/crates/hyperswitch_interfaces/src/disputes.rs +++ b/crates/hyperswitch_interfaces/src/disputes.rs @@ -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 diff --git a/crates/router/src/compatibility/stripe/webhooks.rs b/crates/router/src/compatibility/stripe/webhooks.rs index ddc291e6b139..2212a8953fc7 100644 --- a/crates/router/src/compatibility/stripe/webhooks.rs +++ b/crates/router/src/compatibility/stripe/webhooks.rs @@ -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")] @@ -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, pub status: StripeDisputeStatus, diff --git a/crates/router/src/connector/adyen.rs b/crates/router/src/connector/adyen.rs index 7b491674e92a..c9ccd8a9c629 100644 --- a/crates/router/src/connector/adyen.rs +++ b/crates/router/src/connector/adyen.rs @@ -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, diff --git a/crates/router/src/connector/bluesnap.rs b/crates/router/src/connector/bluesnap.rs index 468f68dc340c..181f1dbf3d7e 100644 --- a/crates/router/src/connector/bluesnap.rs +++ b/crates/router/src/connector/bluesnap.rs @@ -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, diff --git a/crates/router/src/connector/braintree.rs b/crates/router/src/connector/braintree.rs index 85b310397b26..dba261218801 100644 --- a/crates/router/src/connector/braintree.rs +++ b/crates/router/src/connector/braintree.rs @@ -1,5 +1,4 @@ pub mod transformers; -use std::str::FromStr; use api_models::webhooks::IncomingWebhookEvent; use base64::Engine; @@ -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)?, } } diff --git a/crates/router/src/connector/braintree/transformers.rs b/crates/router/src/connector/braintree/transformers.rs index bcef8124c65c..24c6118e44a8 100644 --- a/crates/router/src/connector/braintree/transformers.rs +++ b/crates/router/src/connector/braintree/transformers.rs @@ -1766,7 +1766,7 @@ pub struct BraintreeDisputeData { pub amount_won: Option, pub case_number: Option, pub chargeback_protection_level: Option, - pub currency_iso_code: String, + pub currency_iso_code: enums::Currency, #[serde(default, with = "common_utils::custom_serde::iso8601::option")] pub created_at: Option, pub evidence: Option, diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index 1f6b737367d0..0d4d82010034 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -1252,7 +1252,7 @@ pub struct CheckoutDisputeWebhookData { pub payment_id: Option, pub action_id: Option, pub amount: i32, - pub currency: String, + pub currency: enums::Currency, #[serde(default, with = "common_utils::custom_serde::iso8601::option")] pub evidence_required_by: Option, pub reason_code: Option, diff --git a/crates/router/src/connector/payme.rs b/crates/router/src/connector/payme.rs index 6bf26b4f60bd..bc5524e5c8fc 100644 --- a/crates/router/src/connector/payme.rs +++ b/crates/router/src/connector/payme.rs @@ -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, diff --git a/crates/router/src/connector/paypal.rs b/crates/router/src/connector/paypal.rs index 48a35c78cc25..e79912f61ff2 100644 --- a/crates/router/src/connector/paypal.rs +++ b/crates/router/src/connector/paypal.rs @@ -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(), ), diff --git a/crates/router/src/connector/rapyd.rs b/crates/router/src/connector/rapyd.rs index 196eb4ce73dd..64c3fcdf5a1b 100644 --- a/crates/router/src/connector/rapyd.rs +++ b/crates/router/src/connector/rapyd.rs @@ -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), diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 32fa8da0320e..6d9a4f1c459d 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -3640,7 +3640,8 @@ pub struct WebhookEventObjectData { pub id: String, pub object: WebhookEventObjectType, pub amount: Option, - pub currency: String, + #[serde(default, deserialize_with = "connector_util::convert_uppercase")] + pub currency: enums::Currency, pub payment_intent: Option, pub client_secret: Option>, pub reason: Option, diff --git a/crates/router/src/connector/trustpay/transformers.rs b/crates/router/src/connector/trustpay/transformers.rs index 8312b3e26593..dafca256529e 100644 --- a/crates/router/src/connector/trustpay/transformers.rs +++ b/crates/router/src/connector/trustpay/transformers.rs @@ -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)] diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index 687edd5aa238..ed4b97e2a996 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -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; @@ -3143,3 +3143,14 @@ impl NetworkTokenData for domain::NetworkTokenData { Secret::new(year) } } + +pub fn convert_uppercase<'de, D, T>(v: D) -> Result +where + D: serde::Deserializer<'de>, + T: FromStr, + ::Err: std::fmt::Debug + std::fmt::Display + std::error::Error, +{ + use serde::de::Error; + let output = <&str>::deserialize(v)?; + output.to_uppercase().parse::().map_err(D::Error::custom) +} diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index b049ffdb1298..3532f1e3fd72 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -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) @@ -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::().unwrap_or(0), organization_id: organization_id.clone(), + dispute_currency: Some(dispute_details.currency), }; state .store diff --git a/crates/router/src/db/dispute.rs b/crates/router/src/db/dispute.rs index d7f4af63015e..054f949059d9 100644 --- a/crates/router/src/db/dispute.rs +++ b/crates/router/src/db/dispute.rs @@ -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()); @@ -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 @@ -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()), } } diff --git a/crates/router/src/services/kafka/dispute.rs b/crates/router/src/services/kafka/dispute.rs index 2afb41cc8673..cc3a538851ef 100644 --- a/crates/router/src/services/kafka/dispute.rs +++ b/crates/router/src/services/kafka/dispute.rs @@ -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; @@ -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, @@ -41,7 +41,13 @@ impl<'a> KafkaDispute<'a> { Self { dispute_id: &dispute.dispute_id, dispute_amount: dispute.amount.parse::().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, diff --git a/crates/router/src/services/kafka/dispute_event.rs b/crates/router/src/services/kafka/dispute_event.rs index 057a060decda..64d91e8acaa6 100644 --- a/crates/router/src/services/kafka/dispute_event.rs +++ b/crates/router/src/services/kafka/dispute_event.rs @@ -1,3 +1,4 @@ +use common_utils::ext_traits::StringExt; use diesel_models::enums as storage_enums; use masking::Secret; use time::OffsetDateTime; @@ -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, @@ -41,7 +42,13 @@ impl<'a> KafkaDisputeEvent<'a> { Self { dispute_id: &dispute.dispute_id, dispute_amount: dispute.amount.parse::().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, diff --git a/crates/router/src/types/storage/dispute.rs b/crates/router/src/types/storage/dispute.rs index 28a9573b3330..2d42aaa0a8a9 100644 --- a/crates/router/src/types/storage/dispute.rs +++ b/crates/router/src/types/storage/dispute.rs @@ -83,14 +83,8 @@ impl DisputeDbExt for Dispute { if let Some(dispute_status) = &dispute_list_constraints.dispute_status { filter = filter.filter(dsl::dispute_status.eq_any(dispute_status.clone())); } - if let Some(currency_list) = &dispute_list_constraints.currency { - let currency: Vec = currency_list - .iter() - .map(|currency| currency.to_string()) - .collect(); - - filter = filter.filter(dsl::currency.eq_any(currency)); + filter = filter.filter(dsl::dispute_currency.eq_any(currency_list.clone())); } if let Some(merchant_connector_id) = &dispute_list_constraints.merchant_connector_id { filter = filter.filter(dsl::merchant_connector_id.eq(merchant_connector_id.clone())) diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs index 8ba6783372b6..8fe910cd7b46 100644 --- a/crates/router/src/types/transformers.rs +++ b/crates/router/src/types/transformers.rs @@ -886,7 +886,13 @@ impl ForeignFrom for api_models::disputes::DisputeResponse { payment_id: dispute.payment_id, attempt_id: dispute.attempt_id, amount: dispute.amount, - 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, connector: dispute.connector, diff --git a/crates/router/src/utils/user/sample_data.rs b/crates/router/src/utils/user/sample_data.rs index 4f859d8e56a9..8ffb0f2001fb 100644 --- a/crates/router/src/utils/user/sample_data.rs +++ b/crates/router/src/utils/user/sample_data.rs @@ -435,6 +435,7 @@ pub async fn generate_sample_data( merchant_connector_id: payment_attempt.merchant_connector_id.clone(), dispute_amount: amount * 100, organization_id: org_id.clone(), + dispute_currency: Some(payment_intent.currency.unwrap_or_default()), }) } else { None diff --git a/migrations/2024-10-28-125949_add_dispute_currency_column_in_dispute_table/down.sql b/migrations/2024-10-28-125949_add_dispute_currency_column_in_dispute_table/down.sql new file mode 100644 index 000000000000..052223ca0ae8 --- /dev/null +++ b/migrations/2024-10-28-125949_add_dispute_currency_column_in_dispute_table/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +ALTER TABLE dispute DROP COLUMN IF EXISTS dispute_currency; \ No newline at end of file diff --git a/migrations/2024-10-28-125949_add_dispute_currency_column_in_dispute_table/up.sql b/migrations/2024-10-28-125949_add_dispute_currency_column_in_dispute_table/up.sql new file mode 100644 index 000000000000..732909adfea2 --- /dev/null +++ b/migrations/2024-10-28-125949_add_dispute_currency_column_in_dispute_table/up.sql @@ -0,0 +1,2 @@ +-- Your SQL goes here +ALTER TABLE dispute ADD COLUMN IF NOT EXISTS dispute_currency "Currency"; \ No newline at end of file