pub struct Ticket {Show 24 fields
pub id: Uuid,
pub organization_id: Uuid,
pub building_id: Uuid,
pub unit_id: Option<Uuid>,
pub created_by: Uuid,
pub assigned_to: Option<Uuid>,
pub title: String,
pub description: String,
pub category: TicketCategory,
pub priority: TicketPriority,
pub status: TicketStatus,
pub resolution_notes: Option<String>,
pub work_order_sent_at: Option<DateTime<Utc>>,
pub kind: TicketKind,
pub severity: Option<TicketSeverity>,
pub incident_date: Option<DateTime<Utc>>,
pub evidence_attachments: Vec<String>,
pub witnesses: Vec<Uuid>,
pub sla_due_at: Option<DateTime<Utc>>,
pub sla_escalated_at: Option<DateTime<Utc>>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub resolved_at: Option<DateTime<Utc>>,
pub closed_at: Option<DateTime<Utc>>,
}Expand description
Ticket Entity - Maintenance request from owners
Represents a maintenance request (ticket) submitted by a co-owner for issues in the building (plumbing, electrical, etc.).
Fields§
§id: Uuid§organization_id: Uuid§building_id: Uuid§unit_id: Option<Uuid>§created_by: Uuid§assigned_to: Option<Uuid>§title: String§description: String§category: TicketCategory§priority: TicketPriority§status: TicketStatus§resolution_notes: Option<String>§work_order_sent_at: Option<DateTime<Utc>>§kind: TicketKindStory 3.6 (FR31) — Request (default) vs Complaint. Drives triage UI and (for Complaint) the severity invariant.
severity: Option<TicketSeverity>Story 3.6 (FR31) — Triage tier. MUST be Some when kind == Complaint
(enforced by validate_invariants).
incident_date: Option<DateTime<Utc>>Story 3.6 (FR31) — Optional incident timestamp (legal evidence). Free
of an upper bound here; the use-case layer may compare against
created_at if needed.
evidence_attachments: Vec<String>Story 3.6 (FR31) — Up to MAX_EVIDENCE_ATTACHMENTS URLs / object-
store references attached as proof.
witnesses: Vec<Uuid>Story 3.6 (FR31) — Up to MAX_WITNESSES user_ids witnesses. No
duplicates (enforced by validate_invariants).
sla_due_at: Option<DateTime<Utc>>Story 3.7 (FR32) — Deadline before which the syndic must respond to
the ticket. Computed by Ticket::new_with_kind from severity via
crate::domain::entities::sla_window_for_severity. None for
pre-3.7 tickets and for tickets without a severity tier.
sla_escalated_at: Option<DateTime<Utc>>Story 3.7 (FR32) — Timestamp at which the SLA was “consumed”: either
because a syndic responded in time (pre-empts escalation) or because
the cron job marked the ticket as overdue. None while the SLA is
still open.
created_at: DateTime<Utc>§updated_at: DateTime<Utc>§resolved_at: Option<DateTime<Utc>>§closed_at: Option<DateTime<Utc>>Implementations§
Source§impl Ticket
impl Ticket
Sourcepub fn new(
organization_id: Uuid,
building_id: Uuid,
unit_id: Option<Uuid>,
created_by: Uuid,
title: String,
description: String,
category: TicketCategory,
priority: TicketPriority,
) -> Result<Self, String>
pub fn new( organization_id: Uuid, building_id: Uuid, unit_id: Option<Uuid>, created_by: Uuid, title: String, description: String, category: TicketCategory, priority: TicketPriority, ) -> Result<Self, String>
Create a new ticket
Sourcepub fn new_with_kind(
organization_id: Uuid,
building_id: Uuid,
unit_id: Option<Uuid>,
created_by: Uuid,
title: String,
description: String,
category: TicketCategory,
priority: TicketPriority,
kind: TicketKind,
severity: Option<TicketSeverity>,
incident_date: Option<DateTime<Utc>>,
evidence_attachments: Vec<String>,
witnesses: Vec<Uuid>,
) -> Result<Self, AppError>
pub fn new_with_kind( organization_id: Uuid, building_id: Uuid, unit_id: Option<Uuid>, created_by: Uuid, title: String, description: String, category: TicketCategory, priority: TicketPriority, kind: TicketKind, severity: Option<TicketSeverity>, incident_date: Option<DateTime<Utc>>, evidence_attachments: Vec<String>, witnesses: Vec<Uuid>, ) -> Result<Self, AppError>
Story 3.6 (FR31) — Constructor supporting the full Story 3.6 surface
(kind / severity / incident_date / evidence / witnesses). Returns
AppError natively so the use-case layer doesn’t have to bridge a
legacy String error.
Invariants enforced here in addition to the legacy new() checks:
kind == Complaint→severity.is_some()evidence_attachments.len() <= MAX_EVIDENCE_ATTACHMENTSwitnesses.len() <= MAX_WITNESSES- no duplicate witnesses
created_bynot inwitnesses(self-witnessing is incoherent)
Sourcepub fn is_editable_at(&self, t: DateTime<Utc>) -> bool
pub fn is_editable_at(&self, t: DateTime<Utc>) -> bool
Returns true when t falls strictly within the
TICKET_EDIT_WINDOW_MINUTES window after created_at.
Sourcepub fn is_currently_editable(&self) -> bool
pub fn is_currently_editable(&self) -> bool
Convenience wrapper using Utc::now() — see Self::is_editable_at.
Sourcepub fn validate_invariants(&self) -> Result<(), AppError>
pub fn validate_invariants(&self) -> Result<(), AppError>
Story 3.6 (FR31) — Validate every Complaint/evidence/witness invariant at once. Used by both constructors and the PATCH use-case (after the caller mutates fields) so the entity never escapes in an inconsistent state.
Returns AppError::Validation with a self-describing message on the
first violation found.
Sourcepub fn assign(&mut self, user_id: Uuid) -> Result<(), String>
pub fn assign(&mut self, user_id: Uuid) -> Result<(), String>
Assign ticket to a user (syndic or contractor)
Sourcepub fn start_work(&mut self) -> Result<(), String>
pub fn start_work(&mut self) -> Result<(), String>
Mark ticket as in progress
Sourcepub fn resolve(&mut self, resolution_notes: String) -> Result<(), String>
pub fn resolve(&mut self, resolution_notes: String) -> Result<(), String>
Resolve ticket (work completed)
Sourcepub fn reopen(&mut self, reason: String) -> Result<(), String>
pub fn reopen(&mut self, reason: String) -> Result<(), String>
Reopen ticket (if incorrectly resolved)
Sourcepub fn send_work_order_to_contractor(&mut self) -> Result<(), String>
pub fn send_work_order_to_contractor(&mut self) -> Result<(), String>
Send work order to contractor (magic link PWA) - Issue #309 Validates ticket is in InProgress status (must be assigned)
Sourcepub fn is_overdue(&self, max_days: i64) -> bool
pub fn is_overdue(&self, max_days: i64) -> bool
Check if ticket is overdue (open for more than X days)
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Ticket
impl<'de> Deserialize<'de> for Ticket
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl From<Ticket> for TicketResponse
impl From<Ticket> for TicketResponse
Auto Trait Implementations§
impl Freeze for Ticket
impl RefUnwindSafe for Ticket
impl Send for Ticket
impl Sync for Ticket
impl Unpin for Ticket
impl UnsafeUnpin for Ticket
impl UnwindSafe for Ticket
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
§impl<T> Fake for T
impl<T> Fake for T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more