Items 1-5, 9, 11 from denya-wahab-feedback-s2: - Category.show_in_form (alert-only flag): Gas Leak hidden from issue picker but kept urgent for SLA/alert and reporting; emergency quick path on the new-issue form creates urgent tickets via include_hidden categories. - Seed: Aluminum/Glass, Carpentry, Mould & Damp (Medium default) maintenance categories; Lost Property renamed Missing Item (+ sub). - One alembic migration: add show_in_form (backfill True, Gas Leak False) + data rename Lost Property -> Missing Item. - Property -> Building -> Apartment cascade with searchable apartment combobox on the new-issue form and ticket list filters; /api/tickets/units gains building filter + /units/grouped variant; /api/tickets gains additive building/unit_id filters. apartment_mapping.json committed (deterministic). - Group-by-priority toggle on /tickets (four sections + unknown bucket, age-sortable, composes with filters, URL deep links), FM dashboard active tickets, and CS dashboard priority card click-through. - Tests: 13 new (category visibility, seed idempotency/sync, unit grouping, ticket building/unit filters).
45 lines
1.5 KiB
Python
45 lines
1.5 KiB
Python
"""Ticket category model with self-referencing parent for sub-categories."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from sqlalchemy import Boolean, ForeignKey, Integer, String, true
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.core.database import Base
|
|
|
|
|
|
class Category(Base):
|
|
__tablename__ = "categories"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
|
type: Mapped[str] = mapped_column(
|
|
String(20),
|
|
nullable=False,
|
|
comment="maintenance, cs, emergency",
|
|
)
|
|
name: Mapped[str] = mapped_column(String(100), nullable=False)
|
|
parent_id: Mapped[int | None] = mapped_column(
|
|
Integer,
|
|
ForeignKey("categories.id"),
|
|
nullable=True,
|
|
)
|
|
sla_urgency: Mapped[str | None] = mapped_column(
|
|
String(10),
|
|
nullable=True,
|
|
comment="urgent, high, medium, low",
|
|
)
|
|
show_in_form: Mapped[bool] = mapped_column(
|
|
Boolean,
|
|
nullable=False,
|
|
default=True,
|
|
server_default=true(),
|
|
comment="Visible in the new-issue category picker (False = alert-only, e.g. Gas Leak)",
|
|
)
|
|
|
|
# self-referencing relationship
|
|
children: Mapped[list[Category]] = relationship("Category", back_populates="parent", cascade="all, delete-orphan")
|
|
parent: Mapped[Category | None] = relationship("Category", back_populates="children", remote_side="Category.id")
|
|
|
|
def __repr__(self) -> str:
|
|
return f"<Category {self.type}:{self.name}>"
|