fix(historie): Audit-Lücke bei Mangel/Personal/Objekt-Änderungen geschlossen
Bisher waren nur Kontrolle/Fehlbestand/Nachfüllung/Mindermenge/Geräteinstanz im append-only Audit-Log (historie.log() war seit Prompt 13 nie flächendeckend verdrahtet, docstring sagte das bereits so). Drei neue Ereignisse ergänzt: - mangel_gemeldet / mangel_status_geaendert (Mangel-Modul) - qualifikation_erfasst (Personal-Modul, sicherheitsrelevant: "wer hat wem wann eine Qualifikation bestätigt" hängt fachlich direkt an "wer darf fahren") - objekt_geaendert (Status-/Fahrzeug-Zuordnungsänderungen via PATCH /objekte) Lagerbewegung bewusst NICHT zusätzlich in historie dupliziert - hat bereits eigenes vollständiges Audit-Trail (Wer/Wann/Von/Nach/Grund in eigener Tabelle). Frontend: Änderungslog-Filter um geraet_instanz/mangel/benutzer_qualifikation/ objekt ergänzt (geraet_instanz fehlte dort zuvor ebenfalls). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KC8HYvv6UkCVYheYiTw9DD
This commit is contained in:
@@ -97,3 +97,18 @@ async def test_ueberfaellige_hu_macht_objekt_nicht_einsatzbereit_und_erscheint_i
|
||||
assert len(body) == 1
|
||||
assert body[0]["typ"] == "fahrzeug_hu"
|
||||
assert body[0]["status"] == "abgelaufen"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_objekt_status_aenderung_steht_in_historie(client, objekt_mit_position, admin_user):
|
||||
objekt, _material = objekt_mit_position
|
||||
token = await login(client, "admin1")
|
||||
await client.patch(f"/api/v1/objekte/{objekt.id}", json={"status": "in_wartung"}, headers=auth_header(token))
|
||||
|
||||
historie = await client.get(
|
||||
f"/api/v1/historie?entitaet_typ=objekt&entitaet_id={objekt.id}", headers=auth_header(token)
|
||||
)
|
||||
body = historie.json()
|
||||
assert len(body) == 1
|
||||
assert body[0]["ereignistyp"] == "objekt_geaendert"
|
||||
assert body[0]["neuer_wert"]["status"] == "in_wartung"
|
||||
|
||||
@@ -143,3 +143,29 @@ async def test_leitungsverantwortlicher_kann_status_aendern(client, objekt_mit_p
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["status"] == "erledigt"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mangel_meldung_und_status_aenderung_stehen_in_historie(
|
||||
client, objekt_mit_position, mitarbeiter_user, materialverantwortlicher_user
|
||||
):
|
||||
objekt, _material = objekt_mit_position
|
||||
mitarbeiter_token = await login(client, "mitarbeiter1")
|
||||
gemeldet = await client.post(
|
||||
"/api/v1/maengel",
|
||||
json={"objekt_id": objekt.id, "beschreibung": "Funkgerät ausgefallen"},
|
||||
headers=auth_header(mitarbeiter_token),
|
||||
)
|
||||
mangel_id = gemeldet.json()["id"]
|
||||
|
||||
verantwortlicher_token = await login(client, "materialverantwortlicher1")
|
||||
await client.patch(
|
||||
f"/api/v1/maengel/{mangel_id}", json={"status": "in_bearbeitung"}, headers=auth_header(verantwortlicher_token)
|
||||
)
|
||||
|
||||
historie = await client.get(
|
||||
f"/api/v1/historie?entitaet_typ=mangel&entitaet_id={mangel_id}", headers=auth_header(verantwortlicher_token)
|
||||
)
|
||||
ereignistypen = [e["ereignistyp"] for e in historie.json()]
|
||||
assert "mangel_gemeldet" in ereignistypen
|
||||
assert "mangel_status_geaendert" in ereignistypen
|
||||
|
||||
@@ -196,3 +196,35 @@ async def test_unbefristete_qualifikation_erscheint_nicht_im_dashboard(client, a
|
||||
|
||||
response = await client.get("/api/v1/dashboard/qualifikationsablaeufe", headers=auth_header(token))
|
||||
assert response.json() == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_qualifikation_erfassen_steht_in_historie(client, admin_user, mitarbeiter_user):
|
||||
from datetime import date
|
||||
|
||||
token = await login(client, "admin1")
|
||||
quali = await client.post(
|
||||
"/api/v1/qualifikationstypen",
|
||||
json={"name": "Maschinist", "kategorie": "lehrgang"},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
quali_id = quali.json()["id"]
|
||||
|
||||
erfasst = await client.post(
|
||||
f"/api/v1/benutzer/{mitarbeiter_user.id}/qualifikationen",
|
||||
json={
|
||||
"benutzer_id": mitarbeiter_user.id,
|
||||
"qualifikationstyp_id": quali_id,
|
||||
"erworben_am": date.today().isoformat(),
|
||||
},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
qualifikation_id = erfasst.json()["id"]
|
||||
|
||||
historie = await client.get(
|
||||
f"/api/v1/historie?entitaet_typ=benutzer_qualifikation&entitaet_id={qualifikation_id}",
|
||||
headers=auth_header(token),
|
||||
)
|
||||
body = historie.json()
|
||||
assert len(body) == 1
|
||||
assert body[0]["ereignistyp"] == "qualifikation_erfasst"
|
||||
|
||||
Reference in New Issue
Block a user