From 97218730882035367507cefe6a55d483a49be565 Mon Sep 17 00:00:00 2001 From: patrick Date: Sun, 6 Sep 2026 22:26:57 +0200 Subject: [PATCH] fix(kontrolle): doppelten Fehlbestand bei Folge-Kontrolle vermieden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _synchronisiere_fehlbestand suchte nur nach Fehlbeständen der eigenen Kontroll-Sitzung. Ein bereits offener Fehlbestand aus einer früheren Kontrolle für dasselbe Objekt+Material wurde nicht wiedergefunden - es entstand ein zweiter, paralleler Fehlbestand mit eigener (neuerer) Sollmenge, der alte blieb mit veralteter Sollmenge offen liegen. Lookup jetzt über objekt_id+material_id+status=offen statt kontrolle_id; kontrolle_id am gefundenen Datensatz bleibt unverändert, damit ein Abbruch der aktuellen Kontrolle ihn nicht fälschlich mitlöscht. Löst sich die Abweichung über eine andere Kontrolle als die erzeugende auf, wird der Fehlbestand jetzt sauber als erledigt markiert (inkl. Mindermenge-Abschluss) statt stillschweigend gelöscht. Nebenbei: Kommentare mit Kachel-/Datums-Referenzen ("Bug-Fund 2026-09-06", "UI-00X (Epic 20)") aus dem Code dieser Session entfernt. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV --- backend/app/services/dashboard.py | 17 ++--- backend/app/services/kontrolle/erfassung.py | 50 +++++++++++--- backend/tests/test_dashboard.py | 3 - backend/tests/test_kontrolle.py | 67 +++++++++++++++++++ frontend/src/api/client.ts | 2 +- frontend/src/components/CommandPalette.tsx | 2 +- frontend/src/components/ThemeToggle.tsx | 2 +- frontend/src/components/status/FristBadge.tsx | 2 +- .../components/status/InspectionStatus.tsx | 2 +- .../src/components/status/InventoryStatus.tsx | 2 +- .../src/components/status/ReadinessBadge.tsx | 2 +- frontend/src/components/status/SyncStatus.tsx | 2 +- frontend/src/pages/AdminPage.tsx | 2 +- frontend/src/pages/AktePage.tsx | 2 +- frontend/src/pages/DashboardPage.tsx | 4 -- frontend/src/pages/FehlbestandListePage.tsx | 2 +- frontend/src/pages/MangelListePage.tsx | 4 +- frontend/src/pages/ObjektListPage.tsx | 8 +-- .../src/pages/admin/GeraeteInstanzenListe.tsx | 2 +- frontend/src/pages/kontrolle/PositionCard.tsx | 2 +- 20 files changed, 133 insertions(+), 46 deletions(-) diff --git a/backend/app/services/dashboard.py b/backend/app/services/dashboard.py index 3e0472a..77489e7 100644 --- a/backend/app/services/dashboard.py +++ b/backend/app/services/dashboard.py @@ -228,9 +228,8 @@ async def einsatzbereitschaft(db: AsyncSession) -> dict: "unbekannt": unbekannt, "nicht_einsatzbereit": len(objekte) - bereit - eingeschraenkt - unbekannt, "gesamt": len(objekte), - # Bug-Fund 2026-09-06: "unbekannt" zählt nur Objekte OHNE jeden anderen - # Grund - diese Zahl zählt "nie kontrolliert" unabhängig von sonstigen - # Problemen mit, damit sie beim manuellen Nachzählen stimmt. + # "unbekannt" zählt nur Objekte ohne jeden anderen Grund - diese Zahl + # zählt "nie kontrolliert" unabhängig von sonstigen Problemen mit. "nie_kontrolliert_gesamt": nie_kontrolliert_gesamt, "details": details, } @@ -247,7 +246,7 @@ def _kategorie_und_gruende( objekt_ids_kritischer_mangel: set, objekt_ids_hu_uvv_ueberfaellig: set, ) -> tuple[str, list[str]]: - """UI-005 (Epic 20): aus der `einsatzbereitschaft()`-Schleife extrahiert, damit + """aus der `einsatzbereitschaft()`-Schleife extrahiert, damit `objekt_readiness()` (Begründung auf der Objektakte) dieselbe Logik nutzt statt sie zu duplizieren.""" gruende: list[str] = [] @@ -267,12 +266,8 @@ def _kategorie_und_gruende( if objekt.id in objekt_ids_hu_uvv_ueberfaellig: gruende.append("hu_uvv_ueberfaellig") - # Bug-Fund 2026-09-06 (Nutzer: "beim genauen Schauen sind es mehr"): - # "noch nie kontrolliert" wurde bisher nur gezählt, wenn es der EINZIGE - # Grund war - ein Objekt mit z.B. offenem Fehlbestand UND nie kontrolliert - # verlor den Hinweis komplett (fiel unter "nicht einsatzbereit" ohne - # diesen Grund zu nennen). Jetzt immer als Zusatzgrund angehängt, wenn - # zutreffend, unabhängig von anderen Gründen. + # "noch nie kontrolliert" gilt zusätzlich zu jedem anderen Grund, nicht nur + # wenn es der einzige ist. nie_kontrolliert = letzte_kontrolle is None if not gruende and fehlbestand_ids and fehlbestand_ids <= fehlbestand_ids_genehmigt: @@ -288,7 +283,7 @@ def _kategorie_und_gruende( async def objekt_readiness(db: AsyncSession, objekt_id: int) -> dict: - """UI-005 (Epic 20): begründete Einsatzbereitschaft für EIN Objekt (Objektakte), + """begründete Einsatzbereitschaft für EIN Objekt (Objektakte), dieselbe Fachlogik wie `einsatzbereitschaft()` (Dashboard-Aggregat), nur für einen einzelnen Datensatz statt aller Objekte. `ausser_dienst` zählt hier bewusst nicht als eigener Fall - Objektakte zeigt das Objekt so oder so an, diff --git a/backend/app/services/kontrolle/erfassung.py b/backend/app/services/kontrolle/erfassung.py index f0082e4..3233598 100644 --- a/backend/app/services/kontrolle/erfassung.py +++ b/backend/app/services/kontrolle/erfassung.py @@ -7,6 +7,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from app.models.fehlbestand import Fehlbestand, FehlbestandStatus from app.models.kontrolle import Kontrolle, Kontrollposition +from app.models.mindermenge import MindermengeStatus, MindermengenGenehmigung from app.models.objekt import Objekt from app.models.objektposition import Objektposition from app.services import benachrichtigung as benachrichtigung_service @@ -109,12 +110,13 @@ async def _synchronisiere_fehlbestand( ) -> uuid.UUID | None: result = await db.execute( select(Fehlbestand).where( - Fehlbestand.kontrolle_id == kontrolle.id, + Fehlbestand.objekt_id == objekt.id, Fehlbestand.material_id == material_id, Fehlbestand.status == FehlbestandStatus.offen, ) ) bestehender = result.scalar_one_or_none() + von_dieser_kontrolle = bestehender is not None and bestehender.kontrolle_id == kontrolle.id unterdeckung = sollmenge - istmenge if unterdeckung > 0: @@ -153,16 +155,48 @@ async def _synchronisiere_fehlbestand( ) await benachrichtigung_service.benachrichtige_neuer_fehlbestand(db, fehlbestand=bestehender) else: - # Korrektur vor Abschluss (z. B. Tippfehler nochmal erfasst) - solange die - # Kontrolle noch läuft, ist der von IHR erzeugte Fehlbestand noch nicht - # final und darf berichtigt werden. + # kontrolle_id bleibt unangetastet, sonst würde ein Abbruch dieser + # Kontrolle einen fremden Fehlbestand mitlöschen (_verwirf_kontrolldaten). bestehender.sollmenge = sollmenge bestehender.istmenge = istmenge bestehender.fehlmenge = unterdeckung elif bestehender is not None: - # Abweichung wurde vor Abschluss korrigiert - der von dieser Kontrolle - # erzeugte Fehlbestand hat sich erledigt, bevor er je "real" wurde. - await db.delete(bestehender) - bestehender = None + if von_dieser_kontrolle: + await db.delete(bestehender) + bestehender = None + else: + bestehender.istmenge = istmenge + bestehender.fehlmenge = Decimal(0) + bestehender.status = FehlbestandStatus.erledigt + bestehender.erledigt_am = datetime.now(timezone.utc) + await historie_service.log( + db, + zustaendiger_server_id=zustaendiger_server_id, + benutzer_id=kontrolle.benutzer_id, + ereignistyp="fehlbestand_erledigt", + entitaet_typ="fehlbestand", + entitaet_id=bestehender.id, + neuer_wert={"status": "erledigt"}, + ) + genehmigung_result = await db.execute( + select(MindermengenGenehmigung).where( + MindermengenGenehmigung.fehlbestand_id == bestehender.id, + MindermengenGenehmigung.status == MindermengeStatus.aktiv, + ) + ) + genehmigung = genehmigung_result.scalar_one_or_none() + if genehmigung is not None: + genehmigung.status = MindermengeStatus.beendet_durch_erledigung + genehmigung.beendet_am = datetime.now(timezone.utc) + await historie_service.log( + db, + zustaendiger_server_id=zustaendiger_server_id, + benutzer_id=kontrolle.benutzer_id, + ereignistyp="mindermenge_beendet_durch_erledigung", + entitaet_typ="mindermengen_genehmigung", + entitaet_id=genehmigung.id, + neuer_wert={"status": "beendet_durch_erledigung"}, + ) + bestehender = None await db.flush() return bestehender.id if bestehender is not None else None diff --git a/backend/tests/test_dashboard.py b/backend/tests/test_dashboard.py index b76eee8..8e93ac1 100644 --- a/backend/tests/test_dashboard.py +++ b/backend/tests/test_dashboard.py @@ -204,9 +204,6 @@ async def test_offener_fehlbestand_macht_objekt_nicht_einsatzbereit( body = response.json() assert body["einsatzbereit"] == 0 assert body["nicht_einsatzbereit"] == 1 - # Bug-Fund 2026-09-06: "nie kontrolliert" darf nicht verloren gehen, nur - # weil das Objekt zusätzlich einen anderen Grund hat (objekt_mit_position - # hat nie eine abgeschlossene Kontrolle). assert body["details"][0]["gruende"] == ["fehlbestand_offen", "noch_nie_kontrolliert"] assert body["nie_kontrolliert_gesamt"] == 1 diff --git a/backend/tests/test_kontrolle.py b/backend/tests/test_kontrolle.py index 476c1e9..9ad2cae 100644 --- a/backend/tests/test_kontrolle.py +++ b/backend/tests/test_kontrolle.py @@ -306,3 +306,70 @@ async def test_verschiedene_objekte_parallel_kontrollierbar( zweiter = await _starte(client, token2, objekt_b.id) assert zweiter.status_code == 201 + + +@pytest.mark.asyncio +async def test_zweite_kontrolle_aktualisiert_offenen_fehlbestand_statt_duplikat( + client, db_session, objekt_mit_position, mitarbeiter_user +): + """Ein offener Fehlbestand aus einer früheren Kontrolle wird aktualisiert + statt einen zweiten parallelen zu erzeugen.""" + objekt, material = objekt_mit_position + token = await login(client, "mitarbeiter1") + + erste_kontrolle = (await _starte(client, token, objekt.id)).json()["id"] + await client.put( + f"/api/v1/kontrollen/{erste_kontrolle}/positionen/{material.id}", + json={"istmenge": "8"}, + headers=auth_header(token), + ) + await client.post(f"/api/v1/kontrollen/{erste_kontrolle}/abschliessen", headers=auth_header(token)) + + zweite_kontrolle = (await _starte(client, token, objekt.id)).json()["id"] + await client.put( + f"/api/v1/kontrollen/{zweite_kontrolle}/positionen/{material.id}", + json={"istmenge": "7"}, + headers=auth_header(token), + ) + + result = await db_session.execute( + select(Fehlbestand).where(Fehlbestand.objekt_id == objekt.id, Fehlbestand.material_id == material.id) + ) + fehlbestaende = result.scalars().all() + assert len(fehlbestaende) == 1 + assert float(fehlbestaende[0].istmenge) == 7 + assert float(fehlbestaende[0].fehlmenge) == 3 + assert fehlbestaende[0].kontrolle_id == erste_kontrolle + + +@pytest.mark.asyncio +async def test_zweite_kontrolle_erledigt_offenen_fehlbestand_bei_korrektur( + client, db_session, objekt_mit_position, mitarbeiter_user +): + """Ergänzend: löst die Folge-Kontrolle die Abweichung auf, wird der + Fehlbestand aus der früheren Kontrolle als erledigt markiert (nicht + gelöscht - er war bereits real, anders als der Same-Session-Fall).""" + objekt, material = objekt_mit_position + token = await login(client, "mitarbeiter1") + + erste_kontrolle = (await _starte(client, token, objekt.id)).json()["id"] + await client.put( + f"/api/v1/kontrollen/{erste_kontrolle}/positionen/{material.id}", + json={"istmenge": "8"}, + headers=auth_header(token), + ) + await client.post(f"/api/v1/kontrollen/{erste_kontrolle}/abschliessen", headers=auth_header(token)) + + zweite_kontrolle = (await _starte(client, token, objekt.id)).json()["id"] + await client.put( + f"/api/v1/kontrollen/{zweite_kontrolle}/positionen/{material.id}", + json={"istmenge": "10"}, + headers=auth_header(token), + ) + + result = await db_session.execute( + select(Fehlbestand).where(Fehlbestand.objekt_id == objekt.id, Fehlbestand.material_id == material.id) + ) + fehlbestand = result.scalar_one() + assert fehlbestand.status.value == "erledigt" + assert fehlbestand.fehlmenge == 0 diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index f80b175..d8e51d7 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -106,7 +106,7 @@ export async function ladeDokumentHerunter(dokumentId: string, dateiname: string URL.revokeObjectURL(url); } -// UI-005 (Epic 20): Dokumente waren bisher nur per Zwangs-Download einsehbar, +// Dokumente waren bisher nur per Zwangs-Download einsehbar, // nicht direkt im Browser anschaubar (PDF/Bild in neuem Tab statt Datei // speichern). Auch hier: Auth-Header nötig, daher Blob statt einfachem // auf den Download-Endpunkt. Object-URL wird bewusst NICHT sofort diff --git a/frontend/src/components/CommandPalette.tsx b/frontend/src/components/CommandPalette.tsx index a29fbd3..158d24c 100644 --- a/frontend/src/components/CommandPalette.tsx +++ b/frontend/src/components/CommandPalette.tsx @@ -13,7 +13,7 @@ interface Eintrag { } /** - * UI-002 (Epic 20): globale Suche/Quick Actions per Ctrl+K bzw. ⌘+K. + * globale Suche/Quick Actions per Ctrl+K bzw. ⌘+K. * Öffnet sich über der ganzen App (AppShell), navigiert nur - keine eigene * Fachlogik, nur Zusammenfassung bereits vorhandener Routen/Aktionen. */ diff --git a/frontend/src/components/ThemeToggle.tsx b/frontend/src/components/ThemeToggle.tsx index 6073feb..9510ffa 100644 --- a/frontend/src/components/ThemeToggle.tsx +++ b/frontend/src/components/ThemeToggle.tsx @@ -25,7 +25,7 @@ function gespeichertesTheme(): Theme { const REIHENFOLGE: Theme[] = ["system", "light", "dark"]; const LABEL: Record = { system: "System", light: "Hell", dark: "Dunkel" }; -/** UI-001 (Epic 20): manueller Dark-Mode-Schalter, Präferenz überlebt Reload. */ +/** manueller Dark-Mode-Schalter, Präferenz überlebt Reload. */ export function ThemeToggle() { const [theme, setTheme] = useState(() => gespeichertesTheme()); diff --git a/frontend/src/components/status/FristBadge.tsx b/frontend/src/components/status/FristBadge.tsx index 2080742..c0d7548 100644 --- a/frontend/src/components/status/FristBadge.tsx +++ b/frontend/src/components/status/FristBadge.tsx @@ -17,7 +17,7 @@ interface Props { tage?: number; } -/** UI-003 (Epic 20): gemeinsame Basis für InspectionStatus/InventoryStatus - +/** gemeinsame Basis für InspectionStatus/InventoryStatus - * beide Backend-Endpunkte (Prüftermine/Ablaufdaten) liefern dieselben zwei * Fristzustände (siehe app/services/dashboard.py `_ablauf_status`). */ export function FristBadge({ status, tage }: Props) { diff --git a/frontend/src/components/status/InspectionStatus.tsx b/frontend/src/components/status/InspectionStatus.tsx index ead2bbd..f29b21f 100644 --- a/frontend/src/components/status/InspectionStatus.tsx +++ b/frontend/src/components/status/InspectionStatus.tsx @@ -1,6 +1,6 @@ import { FristBadge } from "./FristBadge"; -/** UI-003 (Epic 20): Geräteprüfung-Fristanzeige (Dashboard "Nächste Prüftermine"). */ +/** Geräteprüfung-Fristanzeige (Dashboard "Nächste Prüftermine"). */ export function InspectionStatus({ status, tage }: { status: string; tage?: number }) { return ; } diff --git a/frontend/src/components/status/InventoryStatus.tsx b/frontend/src/components/status/InventoryStatus.tsx index 365c64f..d948a00 100644 --- a/frontend/src/components/status/InventoryStatus.tsx +++ b/frontend/src/components/status/InventoryStatus.tsx @@ -1,6 +1,6 @@ import { FristBadge } from "./FristBadge"; -/** UI-003 (Epic 20): Chargen-/Ablaufdatum-Fristanzeige (Dashboard "Bevorstehende Ablaufdaten"). */ +/** Chargen-/Ablaufdatum-Fristanzeige (Dashboard "Bevorstehende Ablaufdaten"). */ export function InventoryStatus({ status, tage }: { status: string; tage?: number }) { return ; } diff --git a/frontend/src/components/status/ReadinessBadge.tsx b/frontend/src/components/status/ReadinessBadge.tsx index 309e7cb..491cd04 100644 --- a/frontend/src/components/status/ReadinessBadge.tsx +++ b/frontend/src/components/status/ReadinessBadge.tsx @@ -27,7 +27,7 @@ interface Props { } /** - * UI-003 (Epic 20): einzige Stelle, die Einsatzbereitschaft farblich/textlich + * einzige Stelle, die Einsatzbereitschaft farblich/textlich * darstellt - "unbekannt" (noch nie kontrolliert) sieht bewusst NIE wie * "einsatzbereit" aus (eigene Farbe/Icon, siehe global.css badge-unknown). */ diff --git a/frontend/src/components/status/SyncStatus.tsx b/frontend/src/components/status/SyncStatus.tsx index d015555..81a150d 100644 --- a/frontend/src/components/status/SyncStatus.tsx +++ b/frontend/src/components/status/SyncStatus.tsx @@ -4,7 +4,7 @@ import { alleEintraege } from "../../offline/queue"; import { useOnlineStatus } from "../../offline/useOnlineStatus"; /** - * UI-003 (Epic 20): Online-/Offline-/Sync-Status war bisher nirgends sichtbar + * Online-/Offline-/Sync-Status war bisher nirgends sichtbar * (useOnlineStatus/Queue existierten nur intern für den Kontroll-Workflow) - * echte Lücke laut Redesign-Vorgabe, kein reiner Umbau. */ diff --git a/frontend/src/pages/AdminPage.tsx b/frontend/src/pages/AdminPage.tsx index bbe5173..5361ed1 100644 --- a/frontend/src/pages/AdminPage.tsx +++ b/frontend/src/pages/AdminPage.tsx @@ -104,7 +104,7 @@ export function AdminPage() { const [qualifikationstypen, setQualifikationstypen] = useState([]); const [fehler, setFehler] = useState(null); const [laedt, setLaedt] = useState(true); - // UI-002 (Epic 20): Tab im URL-Query statt nur lokalem State - erlaubt + // Tab im URL-Query statt nur lokalem State - erlaubt // Deep-Links von der Command Palette (z.B. /admin?tab=material). const [suchparameter, setSuchparameter] = useSearchParams(); const tab = suchparameter.get("tab") as Tab | null; diff --git a/frontend/src/pages/AktePage.tsx b/frontend/src/pages/AktePage.tsx index 734e706..521c53c 100644 --- a/frontend/src/pages/AktePage.tsx +++ b/frontend/src/pages/AktePage.tsx @@ -58,7 +58,7 @@ export function AktePage() { )} - {/* UI-007 (Epic 20): nach dem QR-Scan (MOBILE-002) landet man hier - die + {/* nach dem QR-Scan (MOBILE-002) landet man hier - die Kernaktionen sollen direkt sichtbar sein, nicht erst am Seitenende. */}
diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx index a143920..8835342 100644 --- a/frontend/src/pages/DashboardPage.tsx +++ b/frontend/src/pages/DashboardPage.tsx @@ -118,10 +118,6 @@ export function DashboardPage() { const pruefungenUeberfaellig = prueftermine.filter((p) => p.status === "abgelaufen").length; const ablaufdatenAbgelaufen = ablaufdaten.filter((a) => a.status === "abgelaufen").length; - // UI-004 (Epic 20): "Was ist einsatzbereit und was muss ich jetzt tun?" in - // 5 Sekunden beantwortbar - eine Aufgaben-Karte statt Zahlen über sechs - // gleichrangige Karten verteilt suchen zu müssen. Keine neuen Daten, nur - // Zusammenfassung der bereits geladenen Kennzahlen mit Direktlinks. const aufgaben = [ kennzahlen && kennzahlen.anzahl_offener_fehlbestaende > 0 ? { text: `${kennzahlen.anzahl_offener_fehlbestaende} offene Fehlbestände`, ziel: "/fehlbestaende" } diff --git a/frontend/src/pages/FehlbestandListePage.tsx b/frontend/src/pages/FehlbestandListePage.tsx index ba946fc..33352f5 100644 --- a/frontend/src/pages/FehlbestandListePage.tsx +++ b/frontend/src/pages/FehlbestandListePage.tsx @@ -4,7 +4,7 @@ import { apiRequest } from "../api/client"; import { useAuth } from "../auth/AuthContext"; import type { Fehlbestand, Material, Objekt } from "../api/types"; -// UI-008 (Epic 20): Status war bisher immer badge-neutral, unabhängig vom +// Status war bisher immer badge-neutral, unabhängig vom // tatsächlichen Zustand - andere Listen (Mängel, Ausgabe) unterscheiden längst // visuell zwischen offen/erledigt. const STATUS_BADGE: Record = { diff --git a/frontend/src/pages/MangelListePage.tsx b/frontend/src/pages/MangelListePage.tsx index e05f60a..a9e8462 100644 --- a/frontend/src/pages/MangelListePage.tsx +++ b/frontend/src/pages/MangelListePage.tsx @@ -14,7 +14,7 @@ const STATUS_LABEL: Record = { erledigt: "Erledigt", }; -// UI-008 (Epic 20): Status-Badge war immer neutral, unabhängig vom Zustand. +// Status-Badge war immer neutral, unabhängig vom Zustand. const STATUS_BADGE: Record = { neu: "badge-warning", in_bearbeitung: "badge-warning", @@ -45,7 +45,7 @@ export function MangelListePage() { const [nurOffene, setNurOffene] = useState(true); const [suchparameter] = useSearchParams(); - // UI-007 (Epic 20): Quick Action "Mangel melden" aus der Objektakte springt + // Quick Action "Mangel melden" aus der Objektakte springt // hierher mit ?objekt_id=X und wählt das Objekt direkt vor. const [objektId, setObjektId] = useState(() => { const wert = Number(suchparameter.get("objekt_id")); diff --git a/frontend/src/pages/ObjektListPage.tsx b/frontend/src/pages/ObjektListPage.tsx index f006531..a567cc9 100644 --- a/frontend/src/pages/ObjektListPage.tsx +++ b/frontend/src/pages/ObjektListPage.tsx @@ -5,10 +5,8 @@ import { apiRequest, ApiError } from "../api/client"; import type { Objekt } from "../api/types"; import { BarcodeScanner } from "../components/BarcodeScanner"; -// Prompt 11 Screen 1: Standort/Objekt wählen. Objekt-Code (MOBILE-002) → -// Direktsprung zur Akte (Zielseite laut Kachel 15), sonst füllt der Scan -// dasselbe Textfeld wie die manuelle Suche (Kamera fällt bei Etikettschaden -// auf Tippen zurück). +// Objekt-Code-Scan springt direkt zur Akte, sonst füllt er dasselbe Textfeld +// wie die manuelle Suche (Kamera fällt bei Etikettschaden auf Tippen zurück). export function ObjektListPage() { const navigate = useNavigate(); const [objekte, setObjekte] = useState([]); @@ -18,7 +16,7 @@ export function ObjektListPage() { const [scannerOffen, setScannerOffen] = useState(false); const [suchparameter, setSuchparameter] = useSearchParams(); - // UI-002 (Epic 20): Quick Action "QR scannen" aus der Command Palette springt + // Quick Action "QR scannen" aus der Command Palette springt // hierher mit ?scan=1 und öffnet den Scanner direkt, statt nur die Liste zu zeigen. useEffect(() => { if (suchparameter.get("scan") === "1") { diff --git a/frontend/src/pages/admin/GeraeteInstanzenListe.tsx b/frontend/src/pages/admin/GeraeteInstanzenListe.tsx index 074aa81..11a6436 100644 --- a/frontend/src/pages/admin/GeraeteInstanzenListe.tsx +++ b/frontend/src/pages/admin/GeraeteInstanzenListe.tsx @@ -15,7 +15,7 @@ const STATUS_LABEL: Record = { in_reparatur: "In Reparatur", }; -// UI-008 (Epic 20): Status-Badge war immer neutral, unabhängig vom Zustand. +// Status-Badge war immer neutral, unabhängig vom Zustand. const STATUS_BADGE: Record = { einsatzbereit: "badge-success", defekt: "badge-danger", diff --git a/frontend/src/pages/kontrolle/PositionCard.tsx b/frontend/src/pages/kontrolle/PositionCard.tsx index 78a6e60..227cef5 100644 --- a/frontend/src/pages/kontrolle/PositionCard.tsx +++ b/frontend/src/pages/kontrolle/PositionCard.tsx @@ -21,7 +21,7 @@ function ablaufFarbe(ablaufdatum: string): string | undefined { return "var(--color-success)"; } -// UI-006 (Epic 20): "Fehlende oder problematische Positionen klar hervorheben" - +// "Fehlende oder problematische Positionen klar hervorheben" - // Rand-Farbe macht eine Abweichung auch nach dem Speichern noch auf einen Blick // sichtbar, nicht nur kurz während des Nachfüll-Dialogs. function rahmenFarbe(status: PositionZustand["status"], passt: boolean): string {