feat: Sprint A Wahab review batch — categories, property hierarchy, priority grouping
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).
This commit is contained in:
+25
-3
@@ -135,23 +135,39 @@ SEED_CATEGORIES_DATA: list[dict] = [
|
||||
{"type": "maintenance", "name": "Security", "subs": ["Lock broken", "Door not closing", "Window latch", "CCTV issue"]},
|
||||
{"type": "maintenance", "name": "Internet", "subs": ["WiFi down", "Slow speed", "Router reset"]},
|
||||
{"type": "maintenance", "name": "Structural", "subs": ["Wall crack", "Ceiling leak", "Floor tile", "Paint touch-up"]},
|
||||
{"type": "maintenance", "name": "Aluminum/Glass",
|
||||
"subs": ["Window repair", "Window replacement", "Door repair (sliding)", "Door repair (fixed)",
|
||||
"Glass replacement", "Aluminum frame repair", "Shower screen", "Mirror replacement"]},
|
||||
{"type": "maintenance", "name": "Carpentry",
|
||||
"subs": ["Door repair", "Door replacement", "Door frame", "Cabinet repair", "Wardrobe repair",
|
||||
"Shelving", "Timber repair", "Loose hinge/lock plate"]},
|
||||
{"type": "maintenance", "name": "Mould & Damp",
|
||||
"subs": ["Wall mould", "Ceiling damp patch", "Bathroom mould", "Mould after leak",
|
||||
"Damp proofing / remediation"],
|
||||
"sla_urgency": "medium"},
|
||||
# ── Customer Service ─────────────────────────────────────────
|
||||
{"type": "cs", "name": "Check-in", "subs": ["Early check-in", "Key handover", "Welcome instructions"]},
|
||||
{"type": "cs", "name": "Check-out", "subs": ["Late checkout", "Key return", "Inspection"]},
|
||||
{"type": "cs", "name": "Housekeeping", "subs": ["Mid-stay cleaning", "Linen change", "Restocking"]},
|
||||
{"type": "cs", "name": "Lost Property", "subs": ["Guest left items behind"]},
|
||||
{"type": "cs", "name": "Missing Item", "subs": ["Guest left items behind", "Item search request"]},
|
||||
{"type": "cs", "name": "Billing", "subs": ["Invoice question", "Payment issue", "Deposit query"]},
|
||||
{"type": "cs", "name": "Staff Behaviour", "subs": ["Staff conduct feedback"]},
|
||||
# ── Emergency ────────────────────────────────────────────────
|
||||
{"type": "emergency", "name": "Fire", "subs": ["Smoke detected", "Fire alarm", "Sprinkler issue"], "sla_urgency": "urgent"},
|
||||
{"type": "emergency", "name": "Flood", "subs": ["Major water leak", "Burst pipe", "Overflowing"], "sla_urgency": "urgent"},
|
||||
{"type": "emergency", "name": "Gas Leak", "subs": ["Gas smell", "Suspected leak"], "sla_urgency": "urgent"},
|
||||
{"type": "emergency", "name": "Gas Leak", "subs": ["Gas smell", "Suspected leak"], "sla_urgency": "urgent", "show_in_form": False},
|
||||
{"type": "emergency", "name": "Electrical Hazard", "subs": ["Sparking", "Exposed wires", "Power outage multiple units"], "sla_urgency": "urgent"},
|
||||
]
|
||||
|
||||
|
||||
async def seed_categories(db: AsyncSession) -> list[Category]:
|
||||
"""Seed the categories table with the full PRD §7 taxonomy."""
|
||||
"""Seed the categories table with the full PRD §7 taxonomy.
|
||||
|
||||
Idempotent: only inserts missing rows. ``show_in_form`` on existing
|
||||
parents is synced when the seed data explicitly sets it (e.g. Gas Leak
|
||||
is alert-only, so already-seeded databases get flipped to False on the
|
||||
next startup).
|
||||
"""
|
||||
created: list[Category] = []
|
||||
|
||||
for group in SEED_CATEGORIES_DATA:
|
||||
@@ -170,10 +186,16 @@ async def seed_categories(db: AsyncSession) -> list[Category]:
|
||||
name=group["name"],
|
||||
parent_id=None,
|
||||
sla_urgency=group.get("sla_urgency"),
|
||||
show_in_form=group.get("show_in_form", True),
|
||||
)
|
||||
db.add(parent)
|
||||
await db.flush()
|
||||
created.append(parent)
|
||||
elif "show_in_form" in group and parent.show_in_form != group["show_in_form"]:
|
||||
# Sync visibility for existing rows (e.g. Gas Leak → alert-only)
|
||||
parent.show_in_form = group["show_in_form"]
|
||||
await db.flush()
|
||||
created.append(parent)
|
||||
|
||||
# Seed sub-categories
|
||||
for sub_name in group["subs"]:
|
||||
|
||||
Reference in New Issue
Block a user