diff --git a/crates/api_models/src/disputes.rs b/crates/api_models/src/disputes.rs index a8d10e01f6..f538aa5517 100644 --- a/crates/api_models/src/disputes.rs +++ b/crates/api_models/src/disputes.rs @@ -31,11 +31,14 @@ pub struct DisputeResponse { /// Reason code of dispute sent by connector pub connector_reason_code: Option, /// Evidence deadline of dispute sent by connector - pub challenge_required_by: Option, + #[serde(with = "common_utils::custom_serde::iso8601::option")] + pub challenge_required_by: Option, /// Dispute created time sent by connector - pub created_at: Option, + #[serde(with = "common_utils::custom_serde::iso8601::option")] + pub created_at: Option, /// Dispute updated time sent by connector - pub updated_at: Option, + #[serde(with = "common_utils::custom_serde::iso8601::option")] + pub updated_at: Option, /// Time at which dispute is received pub received_at: String, } diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs index ac615d7a4f..65a2ca1133 100644 --- a/crates/api_models/src/enums.rs +++ b/crates/api_models/src/enums.rs @@ -880,6 +880,7 @@ impl From for IntentStatus { frunk::LabelledGeneric, ToSchema, )] +#[serde(rename_all = "snake_case")] pub enum DisputeStage { PreDispute, #[default] @@ -901,6 +902,7 @@ pub enum DisputeStage { frunk::LabelledGeneric, ToSchema, )] +#[serde(rename_all = "snake_case")] pub enum DisputeStatus { #[default] DisputeOpened, diff --git a/crates/common_utils/src/custom_serde.rs b/crates/common_utils/src/custom_serde.rs index 2d797a5bda..d64abe38e5 100644 --- a/crates/common_utils/src/custom_serde.rs +++ b/crates/common_utils/src/custom_serde.rs @@ -86,6 +86,74 @@ pub mod iso8601 { } } +/// Use the UNIX timestamp when serializing and deserializing an +/// [`PrimitiveDateTime`][PrimitiveDateTime]. +/// +/// [PrimitiveDateTime]: ::time::PrimitiveDateTime +pub mod timestamp { + + use serde::{Deserializer, Serialize, Serializer}; + use time::{serde::timestamp, PrimitiveDateTime, UtcOffset}; + + /// Serialize a [`PrimitiveDateTime`] using UNIX timestamp. + pub fn serialize(date_time: &PrimitiveDateTime, serializer: S) -> Result + where + S: Serializer, + { + date_time + .assume_utc() + .unix_timestamp() + .serialize(serializer) + } + + /// Deserialize an [`PrimitiveDateTime`] from UNIX timestamp. + pub fn deserialize<'a, D>(deserializer: D) -> Result + where + D: Deserializer<'a>, + { + timestamp::deserialize(deserializer).map(|offset_date_time| { + let utc_date_time = offset_date_time.to_offset(UtcOffset::UTC); + PrimitiveDateTime::new(utc_date_time.date(), utc_date_time.time()) + }) + } + + /// Use the UNIX timestamp when serializing and deserializing an + /// [`Option`][PrimitiveDateTime]. + /// + /// [PrimitiveDateTime]: ::time::PrimitiveDateTime + pub mod option { + use serde::Serialize; + + use super::*; + + /// Serialize an [`Option`] from UNIX timestamp. + pub fn serialize( + date_time: &Option, + serializer: S, + ) -> Result + where + S: Serializer, + { + date_time + .map(|date_time| date_time.assume_utc().unix_timestamp()) + .serialize(serializer) + } + + /// Deserialize an [`Option`] from UNIX timestamp. + pub fn deserialize<'a, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'a>, + { + timestamp::option::deserialize(deserializer).map(|option_offset_date_time| { + option_offset_date_time.map(|offset_date_time| { + let utc_date_time = offset_date_time.to_offset(UtcOffset::UTC); + PrimitiveDateTime::new(utc_date_time.date(), utc_date_time.time()) + }) + }) + } + } +} + /// pub mod json_string { diff --git a/crates/router/src/connector/adyen.rs b/crates/router/src/connector/adyen.rs index 70562ba1c4..7f47e19824 100644 --- a/crates/router/src/connector/adyen.rs +++ b/crates/router/src/connector/adyen.rs @@ -792,7 +792,7 @@ impl api::IncomingWebhook for Adyen { connector_reason_code: notif.additional_data.chargeback_reason_code, challenge_required_by: notif.additional_data.defense_period_ends_at, connector_status: notif.event_code.to_string(), - created_at: notif.event_date.clone(), + created_at: notif.event_date, updated_at: notif.event_date, }) } diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index 570ad607f0..d1ed734269 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -2,6 +2,7 @@ use api_models::{enums::DisputeStage, webhooks::IncomingWebhookEvent}; use masking::PeekInterface; use reqwest::Url; use serde::{Deserialize, Serialize}; +use time::PrimitiveDateTime; use crate::{ connector::utils::PaymentsAuthorizeRequestData, @@ -1553,7 +1554,8 @@ pub struct AdyenAdditionalDataWH { pub hmac_signature: String, pub dispute_status: Option, pub chargeback_reason_code: Option, - pub defense_period_ends_at: Option, + #[serde(default, with = "common_utils::custom_serde::iso8601::option")] + pub defense_period_ends_at: Option, } #[derive(Debug, Deserialize)] @@ -1653,7 +1655,8 @@ pub struct AdyenNotificationRequestItemWH { pub merchant_reference: String, pub success: String, pub reason: Option, - pub event_date: Option, + #[serde(default, with = "common_utils::custom_serde::iso8601::option")] + pub event_date: Option, } #[derive(Debug, Deserialize)] diff --git a/crates/router/src/connector/checkout.rs b/crates/router/src/connector/checkout.rs index 9a651594f1..900428e78f 100644 --- a/crates/router/src/connector/checkout.rs +++ b/crates/router/src/connector/checkout.rs @@ -1083,7 +1083,7 @@ impl api::IncomingWebhook for Checkout { .parse_struct("CheckoutWebhookBody") .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?; - if checkout::is_chargeback_event(&details.txn_type) { + if checkout::is_chargeback_event(&details.transaction_type) { return Ok(api_models::webhooks::ObjectReferenceId::PaymentId( api_models::payments::PaymentIdType::ConnectorTransactionId( details @@ -1093,7 +1093,7 @@ impl api::IncomingWebhook for Checkout { ), )); } - if checkout::is_refund_event(&details.txn_type) { + if checkout::is_refund_event(&details.transaction_type) { return Ok(api_models::webhooks::ObjectReferenceId::RefundId( api_models::webhooks::RefundIdType::ConnectorRefundId( details @@ -1117,7 +1117,7 @@ impl api::IncomingWebhook for Checkout { .parse_struct("CheckoutWebhookBody") .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; - Ok(api::IncomingWebhookEvent::from(details.txn_type)) + Ok(api::IncomingWebhookEvent::from(details.transaction_type)) } fn get_webhook_resource_object( @@ -1143,12 +1143,14 @@ impl api::IncomingWebhook for Checkout { Ok(api::disputes::DisputePayload { amount: dispute_details.data.amount.to_string(), currency: dispute_details.data.currency, - dispute_stage: api_models::enums::DisputeStage::from(dispute_details.txn_type.clone()), + dispute_stage: api_models::enums::DisputeStage::from( + dispute_details.transaction_type.clone(), + ), connector_dispute_id: dispute_details.data.id, connector_reason: None, connector_reason_code: dispute_details.data.reason_code, challenge_required_by: dispute_details.data.evidence_required_by, - connector_status: dispute_details.txn_type.to_string(), + connector_status: dispute_details.transaction_type.to_string(), created_at: dispute_details.created_on, updated_at: dispute_details.data.date, }) diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs index fe309f250d..4cad762a3d 100644 --- a/crates/router/src/connector/checkout/transformers.rs +++ b/crates/router/src/connector/checkout/transformers.rs @@ -1,6 +1,7 @@ use common_utils::errors::CustomResult; use error_stack::{IntoReport, ResultExt}; use serde::{Deserialize, Serialize}; +use time::PrimitiveDateTime; use url::Url; use crate::{ @@ -674,27 +675,27 @@ impl From for enums::AttemptStatus { } } -pub fn is_refund_event(event_code: &CheckoutTxnType) -> bool { +pub fn is_refund_event(event_code: &CheckoutTransactionType) -> bool { matches!( event_code, - CheckoutTxnType::PaymentRefunded | CheckoutTxnType::PaymentRefundDeclined + CheckoutTransactionType::PaymentRefunded | CheckoutTransactionType::PaymentRefundDeclined ) } -pub fn is_chargeback_event(event_code: &CheckoutTxnType) -> bool { +pub fn is_chargeback_event(event_code: &CheckoutTransactionType) -> bool { matches!( event_code, - CheckoutTxnType::DisputeReceived - | CheckoutTxnType::DisputeExpired - | CheckoutTxnType::DisputeAccepted - | CheckoutTxnType::DisputeCanceled - | CheckoutTxnType::DisputeEvidenceSubmitted - | CheckoutTxnType::DisputeEvidenceAcknowledgedByScheme - | CheckoutTxnType::DisputeEvidenceRequired - | CheckoutTxnType::DisputeArbitrationLost - | CheckoutTxnType::DisputeArbitrationWon - | CheckoutTxnType::DisputeWon - | CheckoutTxnType::DisputeLost + CheckoutTransactionType::DisputeReceived + | CheckoutTransactionType::DisputeExpired + | CheckoutTransactionType::DisputeAccepted + | CheckoutTransactionType::DisputeCanceled + | CheckoutTransactionType::DisputeEvidenceSubmitted + | CheckoutTransactionType::DisputeEvidenceAcknowledgedByScheme + | CheckoutTransactionType::DisputeEvidenceRequired + | CheckoutTransactionType::DisputeArbitrationLost + | CheckoutTransactionType::DisputeArbitrationWon + | CheckoutTransactionType::DisputeWon + | CheckoutTransactionType::DisputeLost ) } @@ -705,20 +706,20 @@ pub struct CheckoutWebhookData { pub action_id: Option, pub amount: i32, pub currency: String, - pub evidence_required_by: Option, + pub evidence_required_by: Option, pub reason_code: Option, - pub date: Option, + pub date: Option, } #[derive(Debug, Deserialize)] pub struct CheckoutWebhookBody { #[serde(rename = "type")] - pub txn_type: CheckoutTxnType, + pub transaction_type: CheckoutTransactionType, pub data: CheckoutWebhookData, - pub created_on: Option, + pub created_on: Option, } #[derive(Debug, Deserialize, strum::Display, Clone)] #[serde(rename_all = "snake_case")] -pub enum CheckoutTxnType { +pub enum CheckoutTransactionType { PaymentApproved, PaymentDeclined, PaymentRefunded, @@ -736,37 +737,35 @@ pub enum CheckoutTxnType { DisputeLost, } -impl From for api::IncomingWebhookEvent { - fn from(txn_type: CheckoutTxnType) -> Self { - match txn_type { - CheckoutTxnType::PaymentApproved => Self::PaymentIntentSuccess, - CheckoutTxnType::PaymentDeclined => Self::PaymentIntentSuccess, - CheckoutTxnType::PaymentRefunded => Self::RefundSuccess, - CheckoutTxnType::PaymentRefundDeclined => Self::RefundFailure, - CheckoutTxnType::DisputeReceived | CheckoutTxnType::DisputeEvidenceRequired => { - Self::DisputeOpened - } - CheckoutTxnType::DisputeExpired => Self::DisputeExpired, - CheckoutTxnType::DisputeAccepted => Self::DisputeAccepted, - CheckoutTxnType::DisputeCanceled => Self::DisputeCancelled, - CheckoutTxnType::DisputeEvidenceSubmitted - | CheckoutTxnType::DisputeEvidenceAcknowledgedByScheme => Self::DisputeChallenged, - CheckoutTxnType::DisputeWon | CheckoutTxnType::DisputeArbitrationWon => { - Self::DisputeWon - } - CheckoutTxnType::DisputeLost | CheckoutTxnType::DisputeArbitrationLost => { - Self::DisputeLost +impl From for api::IncomingWebhookEvent { + fn from(transaction_type: CheckoutTransactionType) -> Self { + match transaction_type { + CheckoutTransactionType::PaymentApproved => Self::PaymentIntentSuccess, + CheckoutTransactionType::PaymentDeclined => Self::PaymentIntentSuccess, + CheckoutTransactionType::PaymentRefunded => Self::RefundSuccess, + CheckoutTransactionType::PaymentRefundDeclined => Self::RefundFailure, + CheckoutTransactionType::DisputeReceived + | CheckoutTransactionType::DisputeEvidenceRequired => Self::DisputeOpened, + CheckoutTransactionType::DisputeExpired => Self::DisputeExpired, + CheckoutTransactionType::DisputeAccepted => Self::DisputeAccepted, + CheckoutTransactionType::DisputeCanceled => Self::DisputeCancelled, + CheckoutTransactionType::DisputeEvidenceSubmitted + | CheckoutTransactionType::DisputeEvidenceAcknowledgedByScheme => { + Self::DisputeChallenged } + CheckoutTransactionType::DisputeWon + | CheckoutTransactionType::DisputeArbitrationWon => Self::DisputeWon, + CheckoutTransactionType::DisputeLost + | CheckoutTransactionType::DisputeArbitrationLost => Self::DisputeLost, } } } -impl From for api_models::enums::DisputeStage { - fn from(code: CheckoutTxnType) -> Self { +impl From for api_models::enums::DisputeStage { + fn from(code: CheckoutTransactionType) -> Self { match code { - CheckoutTxnType::DisputeArbitrationLost | CheckoutTxnType::DisputeArbitrationWon => { - Self::PreArbitration - } + CheckoutTransactionType::DisputeArbitrationLost + | CheckoutTransactionType::DisputeArbitrationWon => Self::PreArbitration, _ => Self::Dispute, } } diff --git a/crates/router/src/connector/stripe.rs b/crates/router/src/connector/stripe.rs index ec76347ff7..98b5c0560e 100644 --- a/crates/router/src/connector/stripe.rs +++ b/crates/router/src/connector/stripe.rs @@ -1284,28 +1284,58 @@ impl api::IncomingWebhook for Stripe { &self, request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let details: stripe::StripeWebhookObjectId = request + let details: stripe::WebhookEvent = request .body - .parse_struct("StripeWebhookObjectId") + .parse_struct("WebhookEvent") .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?; - Ok(api_models::webhooks::ObjectReferenceId::PaymentId( - api_models::payments::PaymentIdType::ConnectorTransactionId(details.data.object.id), - )) + Ok(match details.event_data.event_object.object { + stripe::WebhookEventObjectType::PaymentIntent => { + api_models::webhooks::ObjectReferenceId::PaymentId( + api_models::payments::PaymentIdType::ConnectorTransactionId( + details.event_data.event_object.id, + ), + ) + } + stripe::WebhookEventObjectType::Dispute => { + api_models::webhooks::ObjectReferenceId::PaymentId( + api_models::payments::PaymentIdType::ConnectorTransactionId( + details + .event_data + .event_object + .payment_intent + .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?, + ), + ) + } + _ => Err(errors::ConnectorError::WebhookReferenceIdNotFound)?, + }) } fn get_webhook_event_type( &self, request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let details: stripe::StripeWebhookObjectEventType = request + let details: stripe::WebhookEvent = request .body - .parse_struct("StripeWebhookObjectEventType") - .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?; - - Ok(match details.event_type.as_str() { - "payment_intent.payment_failed" => api::IncomingWebhookEvent::PaymentIntentFailure, - "payment_intent.succeeded" => api::IncomingWebhookEvent::PaymentIntentSuccess, + .parse_struct("WebhookEvent") + .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?; + Ok(match details.event_type { + stripe::WebhookEventType::PaymentIntentFailed => { + api::IncomingWebhookEvent::PaymentIntentFailure + } + stripe::WebhookEventType::PaymentIntentSucceed => { + api::IncomingWebhookEvent::PaymentIntentSuccess + } + stripe::WebhookEventType::DisputeCreated => api::IncomingWebhookEvent::DisputeOpened, + stripe::WebhookEventType::DisputeClosed => api::IncomingWebhookEvent::DisputeCancelled, + stripe::WebhookEventType::DisputeUpdated => api::IncomingWebhookEvent::try_from( + details + .event_data + .event_object + .status + .ok_or(errors::ConnectorError::WebhookEventTypeNotFound)?, + )?, _ => Err(errors::ConnectorError::WebhookEventTypeNotFound).into_report()?, }) } @@ -1314,13 +1344,43 @@ impl api::IncomingWebhook for Stripe { &self, request: &api::IncomingWebhookRequestDetails<'_>, ) -> CustomResult { - let details: stripe::StripeWebhookObjectResource = request + let details: stripe::WebhookEventObjectResource = request .body - .parse_struct("StripeWebhookObjectResource") + .parse_struct("WebhookEventObjectResource") .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?; Ok(details.data.object) } + fn get_dispute_details( + &self, + request: &api::IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + let details: stripe::WebhookEvent = request + .body + .parse_struct("WebhookEvent") + .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?; + Ok(api::disputes::DisputePayload { + amount: details.event_data.event_object.amount.to_string(), + currency: details.event_data.event_object.currency, + dispute_stage: api_models::enums::DisputeStage::Dispute, + connector_dispute_id: details.event_data.event_object.id, + connector_reason: details.event_data.event_object.reason, + connector_reason_code: None, + challenge_required_by: details + .event_data + .event_object + .evidence_details + .map(|payload| payload.due_by), + connector_status: details + .event_data + .event_object + .status + .ok_or(errors::ConnectorError::WebhookResourceObjectNotFound)? + .to_string(), + created_at: Some(details.event_data.event_object.created), + updated_at: None, + }) + } } impl services::ConnectorRedirectResponse for Stripe { diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index a75c64b36a..50594412c1 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -4,6 +4,7 @@ use common_utils::{errors::CustomResult, pii}; use error_stack::{IntoReport, ResultExt}; use masking::{ExposeInterface, ExposeOptionInterface, Secret}; use serde::{Deserialize, Serialize}; +use time::PrimitiveDateTime; use url::Url; use uuid::Uuid; @@ -357,6 +358,20 @@ pub enum StripeBankNames { VanLanschot, } +impl TryFrom for api_models::webhooks::IncomingWebhookEvent { + type Error = errors::ConnectorError; + fn try_from(value: WebhookEventStatus) -> Result { + Ok(match value { + WebhookEventStatus::WarningNeedsResponse => Self::DisputeOpened, + WebhookEventStatus::WarningClosed => Self::DisputeCancelled, + WebhookEventStatus::WarningUnderReview => Self::DisputeChallenged, + WebhookEventStatus::Won => Self::DisputeWon, + WebhookEventStatus::Lost => Self::DisputeLost, + _ => Err(errors::ConnectorError::WebhookEventTypeNotFound)?, + }) + } +} + impl TryFrom<&api_models::enums::BankNames> for StripeBankNames { type Error = errors::ConnectorError; fn try_from(bank: &api_models::enums::BankNames) -> Result { @@ -1566,34 +1581,119 @@ impl // } #[derive(Debug, Deserialize)] -pub struct StripeWebhookDataObjectId { - pub id: String, -} - -#[derive(Debug, Deserialize)] -pub struct StripeWebhookDataId { - pub object: StripeWebhookDataObjectId, -} - -#[derive(Debug, Deserialize)] -pub struct StripeWebhookDataResource { +pub struct WebhookEventDataResource { pub object: serde_json::Value, } #[derive(Debug, Deserialize)] -pub struct StripeWebhookObjectResource { - pub data: StripeWebhookDataResource, +pub struct WebhookEventObjectResource { + pub data: WebhookEventDataResource, } #[derive(Debug, Deserialize)] -pub struct StripeWebhookObjectEventType { +pub struct WebhookEvent { #[serde(rename = "type")] - pub event_type: String, + pub event_type: WebhookEventType, + #[serde(rename = "data")] + pub event_data: WebhookEventData, } #[derive(Debug, Deserialize)] -pub struct StripeWebhookObjectId { - pub data: StripeWebhookDataId, +pub struct WebhookEventData { + #[serde(rename = "object")] + pub event_object: WebhookEventObjectData, +} + +#[derive(Debug, Deserialize)] +pub struct WebhookEventObjectData { + pub id: String, + pub object: WebhookEventObjectType, + pub amount: i32, + pub currency: String, + pub payment_intent: Option, + pub reason: Option, + #[serde(with = "common_utils::custom_serde::timestamp")] + pub created: PrimitiveDateTime, + pub evidence_details: Option, + pub status: Option, +} + +#[derive(Debug, Deserialize, strum::Display)] +#[serde(rename_all = "snake_case")] +pub enum WebhookEventObjectType { + PaymentIntent, + Dispute, + Charge, +} + +#[derive(Debug, Deserialize)] +pub enum WebhookEventType { + #[serde(rename = "payment_intent.payment_failed")] + PaymentIntentFailed, + #[serde(rename = "payment_intent.succeeded")] + PaymentIntentSucceed, + #[serde(rename = "charge.dispute.captured")] + ChargeDisputeCaptured, + #[serde(rename = "charge.dispute.created")] + DisputeCreated, + #[serde(rename = "charge.dispute.closed")] + DisputeClosed, + #[serde(rename = "charge.dispute.updated")] + DisputeUpdated, + #[serde(rename = "charge.dispute.funds_reinstated")] + ChargeDisputeFundsReinstated, + #[serde(rename = "charge.dispute.funds_withdrawn")] + ChargeDisputeFundsWithdrawn, + #[serde(rename = "charge.expired")] + ChargeExpired, + #[serde(rename = "charge.failed")] + ChargeFailed, + #[serde(rename = "charge.pending")] + ChargePending, + #[serde(rename = "charge.captured")] + ChargeCaptured, + #[serde(rename = "charge.succeeded")] + ChargeSucceeded, + #[serde(rename = "charge.updated")] + ChargeUpdated, + #[serde(rename = "charge.refunded")] + ChanrgeRefunded, + #[serde(rename = "payment_intent.canceled")] + PaymentIntentCanceled, + #[serde(rename = "payment_intent.created")] + PaymentIntentCreated, + #[serde(rename = "payment_intent.processing")] + PaymentIntentProcessing, + #[serde(rename = "payment_intent.requires_action")] + PaymentIntentRequiresAction, + #[serde(rename = "amount_capturable_updated")] + PaymentIntentAmountCapturableUpdated, +} + +#[derive(Debug, Serialize, strum::Display, Deserialize, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum WebhookEventStatus { + WarningNeedsResponse, + WarningClosed, + WarningUnderReview, + Won, + Lost, + NeedsResponse, + UnderReview, + ChargeRefunded, + Succeeded, + RequiresPaymentMethod, + RequiresConfirmation, + RequiresAction, + Processing, + RequiresCapture, + Canceled, +} + +#[derive(Debug, Deserialize, PartialEq)] +pub struct EvidenceDetails { + #[serde(with = "common_utils::custom_serde::timestamp")] + pub due_by: PrimitiveDateTime, } impl diff --git a/crates/router/src/types/api/disputes.rs b/crates/router/src/types/api/disputes.rs index 9763fad8f3..cf23df1c9e 100644 --- a/crates/router/src/types/api/disputes.rs +++ b/crates/router/src/types/api/disputes.rs @@ -1,4 +1,5 @@ use masking::{Deserialize, Serialize}; +use time::PrimitiveDateTime; use crate::{services, types}; @@ -7,7 +8,7 @@ pub struct DisputeId { pub dispute_id: String, } -#[derive(Default, Debug, Deserialize)] +#[derive(Default, Debug)] pub struct DisputePayload { pub amount: String, pub currency: String, @@ -16,9 +17,9 @@ pub struct DisputePayload { pub connector_dispute_id: String, pub connector_reason: Option, pub connector_reason_code: Option, - pub challenge_required_by: Option, - pub created_at: Option, - pub updated_at: Option, + pub challenge_required_by: Option, + pub created_at: Option, + pub updated_at: Option, } #[derive(Debug, Clone)] diff --git a/crates/storage_models/src/dispute.rs b/crates/storage_models/src/dispute.rs index 7022f399ac..bf9c514650 100644 --- a/crates/storage_models/src/dispute.rs +++ b/crates/storage_models/src/dispute.rs @@ -1,11 +1,11 @@ use common_utils::custom_serde; use diesel::{AsChangeset, Identifiable, Insertable, Queryable}; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use time::PrimitiveDateTime; use crate::{enums as storage_enums, schema::dispute}; -#[derive(Clone, Debug, Deserialize, Insertable, Serialize, router_derive::DebugAsDisplay)] +#[derive(Clone, Debug, Insertable, Serialize, router_derive::DebugAsDisplay)] #[diesel(table_name = dispute)] #[serde(deny_unknown_fields)] pub struct DisputeNew { @@ -21,13 +21,13 @@ pub struct DisputeNew { pub connector_dispute_id: String, pub connector_reason: Option, pub connector_reason_code: Option, - pub challenge_required_by: Option, - pub dispute_created_at: Option, - pub updated_at: Option, + pub challenge_required_by: Option, + pub dispute_created_at: Option, + pub updated_at: Option, pub connector: String, } -#[derive(Clone, Debug, Deserialize, Serialize, Identifiable, Queryable)] +#[derive(Clone, Debug, Serialize, Identifiable, Queryable)] #[diesel(table_name = dispute)] pub struct Dispute { #[serde(skip_serializing)] @@ -44,9 +44,9 @@ pub struct Dispute { pub connector_dispute_id: String, pub connector_reason: Option, pub connector_reason_code: Option, - pub challenge_required_by: Option, - pub dispute_created_at: Option, - pub updated_at: Option, + pub challenge_required_by: Option, + pub dispute_created_at: Option, + pub updated_at: Option, #[serde(with = "custom_serde::iso8601")] pub created_at: PrimitiveDateTime, #[serde(with = "custom_serde::iso8601")] @@ -62,8 +62,8 @@ pub enum DisputeUpdate { connector_status: String, connector_reason: Option, connector_reason_code: Option, - challenge_required_by: Option, - updated_at: Option, + challenge_required_by: Option, + updated_at: Option, }, StatusUpdate { dispute_status: storage_enums::DisputeStatus, @@ -79,8 +79,8 @@ pub struct DisputeUpdateInternal { connector_status: Option, connector_reason: Option, connector_reason_code: Option, - challenge_required_by: Option, - updated_at: Option, + challenge_required_by: Option, + updated_at: Option, modified_at: Option, } diff --git a/crates/storage_models/src/schema.rs b/crates/storage_models/src/schema.rs index 2a642a42ee..f381044d49 100644 --- a/crates/storage_models/src/schema.rs +++ b/crates/storage_models/src/schema.rs @@ -128,9 +128,9 @@ diesel::table! { connector_dispute_id -> Varchar, connector_reason -> Nullable, connector_reason_code -> Nullable, - challenge_required_by -> Nullable, - dispute_created_at -> Nullable, - updated_at -> Nullable, + challenge_required_by -> Nullable, + dispute_created_at -> Nullable, + updated_at -> Nullable, created_at -> Timestamp, modified_at -> Timestamp, connector -> Varchar, diff --git a/migrations/2023-04-26-062424_alter_dispute_table/down.sql b/migrations/2023-04-26-062424_alter_dispute_table/down.sql new file mode 100644 index 0000000000..9cc7d7c77c --- /dev/null +++ b/migrations/2023-04-26-062424_alter_dispute_table/down.sql @@ -0,0 +1,4 @@ +ALTER TABLE dispute +ALTER COLUMN challenge_required_by TYPE VARCHAR(255), +ALTER COLUMN dispute_created_at TYPE VARCHAR(255), +ALTER COLUMN updated_at TYPE VARCHAR(255) \ No newline at end of file diff --git a/migrations/2023-04-26-062424_alter_dispute_table/up.sql b/migrations/2023-04-26-062424_alter_dispute_table/up.sql new file mode 100644 index 0000000000..201e67a40f --- /dev/null +++ b/migrations/2023-04-26-062424_alter_dispute_table/up.sql @@ -0,0 +1,4 @@ +ALTER TABLE dispute +ALTER COLUMN challenge_required_by TYPE TIMESTAMP USING dispute_created_at::TIMESTAMP, +ALTER COLUMN dispute_created_at TYPE TIMESTAMP USING dispute_created_at::TIMESTAMP, +ALTER COLUMN updated_at TYPE TIMESTAMP USING dispute_created_at::TIMESTAMP \ No newline at end of file