diff --git a/DEVLOG.md b/DEVLOG.md index 42531e4..b91a598 100644 --- a/DEVLOG.md +++ b/DEVLOG.md @@ -15722,3 +15722,69 @@ Keine Commits in dieser Session. - frontend/src/styles/global/responsive.css | 12 ++++++++++++ --- +## 2026-09-13 23:14 – 23:20 (6m) +**Beschreibung:** Claude Code Session +**Projekt:** asb-material + +### Commits +- 29b3345 fix(assets): ASSET-009 Zählerstand-Panel als Opt-in je Objekttyp + +### Geänderte Dateien +- DEVLOG.md | 45 ++++++++++++++++++++++++++++++++ +- arbeitskacheln/04_assets.md | 20 +++++++++++--- +- backend/alembic/versions/0058_objekttyp_zaehler_typ.py | 34 ++++++++++++++++++++++++ +- backend/app/models/stammdaten.py | 16 ++++++++++++ +- backend/app/schemas/akte.py | 1 + +- backend/app/schemas/stammdaten.py | 4 ++- +- backend/app/services/akte.py | 1 + +- backend/tests/test_akte.py | 24 +++++++++++++++++ +- frontend/src/api/types.ts | 4 +++ +- frontend/src/components/ZaehlerstandPanel.tsx | 91 ++++++++++++++++++++++++++++++++++++---------------------------- +- frontend/src/pages/AktePage.tsx | 17 +++++++----- +- frontend/src/pages/admin/ObjekttypSection.tsx | 45 +++++++++++++++++++++++++++++++- + +--- +## 2026-09-13 23:23 – 23:23 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** asb-material + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- DEVLOG.md | 45 ++++++++++++++++++++++++++++++++ +- arbeitskacheln/04_assets.md | 20 +++++++++++--- +- backend/alembic/versions/0058_objekttyp_zaehler_typ.py | 34 ++++++++++++++++++++++++ +- backend/app/models/stammdaten.py | 16 ++++++++++++ +- backend/app/schemas/akte.py | 1 + +- backend/app/schemas/stammdaten.py | 4 ++- +- backend/app/services/akte.py | 1 + +- backend/tests/test_akte.py | 24 +++++++++++++++++ +- frontend/src/api/types.ts | 4 +++ +- frontend/src/components/ZaehlerstandPanel.tsx | 91 ++++++++++++++++++++++++++++++++++++---------------------------- +- frontend/src/pages/AktePage.tsx | 17 +++++++----- +- frontend/src/pages/admin/ObjekttypSection.tsx | 45 +++++++++++++++++++++++++++++++- + +--- +## 2026-09-13 23:26 – 23:26 (0m) +**Beschreibung:** Claude Code Session +**Projekt:** asb-material + +### Commits +Keine Commits in dieser Session. + +### Geänderte Dateien +- DEVLOG.md | 45 ++++++++++++++++++++++++++++++++ +- arbeitskacheln/04_assets.md | 20 +++++++++++--- +- backend/alembic/versions/0058_objekttyp_zaehler_typ.py | 34 ++++++++++++++++++++++++ +- backend/app/models/stammdaten.py | 16 ++++++++++++ +- backend/app/schemas/akte.py | 1 + +- backend/app/schemas/stammdaten.py | 4 ++- +- backend/app/services/akte.py | 1 + +- backend/tests/test_akte.py | 24 +++++++++++++++++ +- frontend/src/api/types.ts | 4 +++ +- frontend/src/components/ZaehlerstandPanel.tsx | 91 ++++++++++++++++++++++++++++++++++++---------------------------- +- frontend/src/pages/AktePage.tsx | 17 +++++++----- +- frontend/src/pages/admin/ObjekttypSection.tsx | 45 +++++++++++++++++++++++++++++++- + +--- diff --git a/arbeitskacheln/10_maintenance.md b/arbeitskacheln/10_maintenance.md index 73b2553..1fa2ba0 100644 --- a/arbeitskacheln/10_maintenance.md +++ b/arbeitskacheln/10_maintenance.md @@ -85,6 +85,20 @@ ebenfalls P3/offen. + werkstatt_name** (beantwortet die Nutzerfrage nach externer Werkstatt), Kosten optional. Zyklus offen→in_arbeit→erledigt getestet, inkl. ad-hoc- Auftrag ohne Plan. + **Korrektur 2026-09-13 (Nutzer-Fund):** "jedes Objekt kann einen Wartungs- + auftrag bekommen" war in der Praxis unerwünscht — ein reines + Bestandsobjekt (Rettungsrucksack) braucht nur Inventur/Kontrolle, keine + Wartung. Auf Opt-in je Objekttyp umgestellt (`Objekttyp.wartung_aktiv`, + Migration `0059_objekttyp_wartung_aktiv.py`, gleiches Muster wie + `ressourcenbuchung_aktiv`/`zaehler_typ`) — bestehende Objekttypen mit + Wartungsplan ODER `ist_zugfahrzeug=true` automatisch aktiviert, damit sich + für produktiv genutzte Fälle nichts ändert. `AktePage.tsx` zeigt + `WartungSection` nur noch bei `akte.wartung_aktiv`. Backend-Endpunkte + selbst bleiben ungegatet (reine Anzeige-Einschränkung, wie bei den anderen + Opt-in-Flags). Admin-UI: Checkbox „Wartung in der Akte anzeigen" in + `ObjekttypSection.tsx`. Test: + `test_akte_wartung_aktiv_folgt_objekttyp_und_ist_default_false` + (`backend/tests/test_akte.py`). ## MAINT-004 — Wartungshistorie diff --git a/backend/alembic/versions/0059_objekttyp_wartung_aktiv.py b/backend/alembic/versions/0059_objekttyp_wartung_aktiv.py new file mode 100644 index 0000000..b65010d --- /dev/null +++ b/backend/alembic/versions/0059_objekttyp_wartung_aktiv.py @@ -0,0 +1,36 @@ +"""Nutzer-Korrektur zu MAINT-003: Wartung war als universelles Ad-hoc- +Reparatur-Ticket für JEDES Objekt gedacht - in der Praxis unerwünscht für +reine Bestandsobjekte (Rucksäcke etc.), die nur Inventur/Kontrolle +brauchen. Opt-in je Objekttyp, gleiches Muster wie ressourcenbuchung_aktiv. + +Revision ID: 0059_objekttyp_wartung_aktiv +Revises: 0058_objekttyp_zaehler_typ +Create Date: 2026-09-13 +""" + +from typing import Sequence, Union + +from alembic import op + +revision: str = "0059_objekttyp_wartung_aktiv" +down_revision: Union[str, None] = "0058_objekttyp_zaehler_typ" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.execute("ALTER TABLE objekttyp ADD COLUMN wartung_aktiv BOOLEAN NOT NULL DEFAULT false") + # Objekttypen mit bereits bestehendem Wartungsplan ODER Fahrzeuge nutzen + # Wartung nachweislich produktiv - automatisch aktiviert, damit sich für + # diese Fälle nichts sichtbar ändert. + op.execute( + """ + UPDATE objekttyp SET wartung_aktiv = true + WHERE ist_zugfahrzeug = true + OR id IN (SELECT DISTINCT objekttyp_id FROM wartungsplan) + """ + ) + + +def downgrade() -> None: + op.execute("ALTER TABLE objekttyp DROP COLUMN wartung_aktiv") diff --git a/backend/app/models/stammdaten.py b/backend/app/models/stammdaten.py index 8392b4b..a3e2be7 100644 --- a/backend/app/models/stammdaten.py +++ b/backend/app/models/stammdaten.py @@ -73,6 +73,12 @@ class Objekttyp(Base): # wie ressourcenbuchung_aktiv, hier als Enum statt bool, da die Kachel # selbst zwischen km/Betriebsstunden/beidem/keinem unterscheidet. zaehler_typ: Mapped[ZaehlerTyp] = mapped_column(zaehler_typ_pg, nullable=False, default=ZaehlerTyp.keiner) + # Nutzer-Entscheidung 2026-09-13 (Korrektur zu MAINT-003): Wartung war + # bewusst als universelles Ad-hoc-Reparatur-Ticket für JEDES Objekt + # gedacht - in der Praxis aber unerwünscht für reine Bestandsobjekte + # (Rucksäcke etc.), die nur Inventur/Kontrolle brauchen, keine Wartung. + # Gleiches Opt-in-Muster wie ressourcenbuchung_aktiv/zaehler_typ. + wartung_aktiv: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) class Nummernschema(Base): diff --git a/backend/app/schemas/akte.py b/backend/app/schemas/akte.py index ecd893b..1c04220 100644 --- a/backend/app/schemas/akte.py +++ b/backend/app/schemas/akte.py @@ -42,6 +42,7 @@ class AkteRead(BaseModel): objekttyp_name: str ressourcenbuchung_aktiv: bool zaehler_typ: str + wartung_aktiv: bool standort_name: str fahrzeugdetails: FahrzeugdetailsRead | None zustaendige_benutzer: list[ZustaendigerBenutzer] diff --git a/backend/app/schemas/stammdaten.py b/backend/app/schemas/stammdaten.py index f9e5e20..8b3d560 100644 --- a/backend/app/schemas/stammdaten.py +++ b/backend/app/schemas/stammdaten.py @@ -92,6 +92,7 @@ class ObjekttypCreate(BaseModel): ist_zugfahrzeug: bool = False ressourcenbuchung_aktiv: bool = False zaehler_typ: ZaehlerTyp = ZaehlerTyp.keiner + wartung_aktiv: bool = False class ObjekttypRead(ObjekttypCreate): @@ -106,6 +107,7 @@ class ObjekttypUpdate(BaseModel): ist_zugfahrzeug: bool | None = None ressourcenbuchung_aktiv: bool | None = None zaehler_typ: ZaehlerTyp | None = None + wartung_aktiv: bool | None = None class FachCreate(BaseModel): diff --git a/backend/app/services/akte.py b/backend/app/services/akte.py index 440d495..06943da 100644 --- a/backend/app/services/akte.py +++ b/backend/app/services/akte.py @@ -141,6 +141,7 @@ async def akte_fuer_objekt(db: AsyncSession, objekt_id: int) -> AkteRead | None: objekttyp_name=objekttyp.name if objekttyp else "", ressourcenbuchung_aktiv=objekttyp.ressourcenbuchung_aktiv if objekttyp else False, zaehler_typ=objekttyp.zaehler_typ.value if objekttyp else "keiner", + wartung_aktiv=objekttyp.wartung_aktiv if objekttyp else False, standort_name=standort.name if standort else "", fahrzeugdetails=FahrzeugdetailsRead.model_validate(fahrzeugdetails) if fahrzeugdetails else None, zustaendige_benutzer=zustaendige, diff --git a/backend/tests/test_akte.py b/backend/tests/test_akte.py index 6b0be1c..53120d1 100644 --- a/backend/tests/test_akte.py +++ b/backend/tests/test_akte.py @@ -103,6 +103,30 @@ async def test_akte_zaehler_typ_folgt_objekttyp_und_ist_default_keiner(client, o assert antwort.json()["zaehler_typ"] == "betriebsstunden" +@pytest.mark.asyncio +async def test_akte_wartung_aktiv_folgt_objekttyp_und_ist_default_false(client, objekt_mit_position, admin_user): + """Nutzer-Korrektur zu MAINT-003 (2026-09-13): Wartung war universell für + jedes Objekt sichtbar - jetzt Opt-in je Objekttyp, ein reines + Bestandsobjekt (Rucksack) braucht nur Inventur/Kontrolle, keine Wartung.""" + objekt, _material = objekt_mit_position + token = await login(client, "admin1") + + ohne_aenderung = await client.get(f"/api/v1/akte/objekt/{objekt.id}", headers=auth_header(token)) + assert ohne_aenderung.json()["wartung_aktiv"] is False + + objekttyp_id = objekt.objekttyp_id + aendern = await client.patch( + f"/api/v1/objekttypen/{objekttyp_id}", + json={"wartung_aktiv": True}, + headers=auth_header(token), + ) + assert aendern.status_code == 200 + assert aendern.json()["wartung_aktiv"] is True + + antwort = await client.get(f"/api/v1/akte/objekt/{objekt.id}", headers=auth_header(token)) + assert antwort.json()["wartung_aktiv"] is True + + @pytest.mark.asyncio async def test_akte_readiness_unbekannt_bei_nie_kontrolliert(client, objekt_mit_position, admin_user): """UI-005: ein Objekt ohne jede Auffälligkeit, aber noch nie kontrolliert, diff --git a/frontend/src/api/types.ts b/frontend/src/api/types.ts index 0ff37b8..e54614e 100644 --- a/frontend/src/api/types.ts +++ b/frontend/src/api/types.ts @@ -423,6 +423,7 @@ export interface Objekttyp { ist_zugfahrzeug: boolean; ressourcenbuchung_aktiv: boolean; zaehler_typ: ZaehlerTyp; + wartung_aktiv: boolean; } export interface Nummernschema { @@ -482,6 +483,7 @@ export interface Akte { objekttyp_name: string; ressourcenbuchung_aktiv: boolean; zaehler_typ: ZaehlerTyp; + wartung_aktiv: boolean; standort_name: string; fahrzeugdetails: Fahrzeugdetails | null; zustaendige_benutzer: ZustaendigerBenutzer[]; diff --git a/frontend/src/pages/AktePage.tsx b/frontend/src/pages/AktePage.tsx index 95eb1f6..d97cf7e 100644 --- a/frontend/src/pages/AktePage.tsx +++ b/frontend/src/pages/AktePage.tsx @@ -279,9 +279,11 @@ export function AktePage() { )} -