"""Tests for backdated reported-date support (Wahab demo). Anchors: * A ticket created with a past ``reported_at`` persists that date and it is exposed on list + detail responses — this is how Wahab enters old tickets that stay active in the normal workflow. * A ticket created without ``reported_at`` defaults to "now", so existing create behavior is unchanged. * The reported date is metadata only: SLA deadlines still run from creation time and no age/backdate restriction kicks in. """ from __future__ import annotations from datetime import datetime import pytest pytestmark = pytest.mark.asyncio def _naive(iso: str) -> datetime: """Parse an ISO datetime and strip any tz offset for safe comparison.""" dt = datetime.fromisoformat(iso) return dt.replace(tzinfo=None) if dt.tzinfo is not None else dt async def _login(client, email="wahab@denya.com", password="denya123") -> str: resp = await client.post( "/api/auth/login", json={"email": email, "password": password}, ) assert resp.status_code == 200, resp.text return resp.json()["access_token"] async def _create_ticket(client, token: str, **overrides) -> dict: payload = { "unit_id": 2, "category_id": 3, "priority": "medium", "reporter": "Backdate Test", "reported_via": "walk-in", "description": "backdate test ticket", **overrides, } resp = await client.post( "/api/tickets", json=payload, headers={"Authorization": f"Bearer {token}"}, ) assert resp.status_code == 201, resp.text return resp.json() async def test_create_with_backdated_reported_at_persists(client): """Wahab (Admin/Wahab) can enter an old ticket and its date sticks.""" token = await _login(client) ticket = await _create_ticket( client, token, reported_at="2026-07-20", description="Old plumbing issue reported weeks ago", ) assert ticket["reported_at"] is not None assert ticket["reported_at"].startswith("2026-07-20") # Still an active ticket in the normal workflow — no age restriction. assert ticket["status"] in {"New", "Logged"} # Detail endpoint exposes the reported date. detail = await client.get(f"/api/tickets/{ticket['id']}") assert detail.status_code == 200 assert detail.json()["reported_at"].startswith("2026-07-20") # List endpoint exposes it too. listing = await client.get("/api/tickets") assert listing.status_code == 200 listed = next(t for t in listing.json()["items"] if t["id"] == ticket["id"]) assert listed["reported_at"].startswith("2026-07-20") async def test_create_without_reported_at_defaults_to_now(client): """Omitting reported_at behaves exactly as before: reported == created.""" token = await _login(client) ticket = await _create_ticket(client, token, description="normal today ticket") assert ticket["reported_at"] is not None reported = _naive(ticket["reported_at"]) created = _naive(ticket["created_at"]) assert abs((reported - created).total_seconds()) < 60 async def test_reported_at_does_not_shift_sla_deadline(client): """SLA computation is unchanged: deadlines run from creation time.""" token = await _login(client) ticket = await _create_ticket( client, token, priority="urgent", reported_at="2026-01-01", description="old urgent ticket", ) assert ticket["sla_deadline"] is not None created = _naive(ticket["created_at"]) deadline = _naive(ticket["sla_deadline"]) hours = (deadline - created).total_seconds() / 3600 assert 3.5 <= hours <= 4.5 # urgent → 4 h resolution window from creation async def test_reported_at_round_trips_full_datetime(client): """A precise datetime (not just a date) survives the round trip.""" token = await _login(client) reported = "2026-07-20T14:30:00" ticket = await _create_ticket(client, token, reported_at=reported, description="datetime round trip") assert ticket["reported_at"] is not None parsed = _naive(ticket["reported_at"]) assert parsed.date().isoformat() == "2026-07-20" assert parsed.hour == 14 and parsed.minute == 30