feat(personal): PERS-001/002 Person fachlich von Benutzer getrennt
Neue Tabelle person (Migration 0034, Backfill bestehender Benutzer 1:1 per Zeilennummer, keine Datenverluste). Benutzer.person_id optional - Login kann bestehende Person verknüpfen oder legt automatisch eine neue an (Rückwärtskompatibilität zum bisherigen Anlegen-Flow). /personen-CRUD (admin-only), neue PersonSection.tsx im Personal-Tab, BenutzerSection um Personen-Auswahl erweitert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
This commit is contained in:
@@ -243,6 +243,95 @@ async def test_unbefristete_qualifikation_erscheint_nicht_im_dashboard(client, a
|
||||
assert response.json() == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_person_ohne_benutzer_anlegbar(client, admin_user):
|
||||
"""PERS-001: Person kann ohne jeden Systemzugang existieren (z.B. Jugendgruppe)."""
|
||||
token = await login(client, "admin1")
|
||||
person = await client.post(
|
||||
"/api/v1/personen",
|
||||
json={"name": "Max Mustermann (Jugendgruppe)", "geburtsdatum": "2012-04-01"},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
assert person.status_code == 201
|
||||
body = person.json()
|
||||
assert body["name"] == "Max Mustermann (Jugendgruppe)"
|
||||
assert body["geburtsdatum"] == "2012-04-01"
|
||||
|
||||
liste = await client.get("/api/v1/personen", headers=auth_header(token))
|
||||
assert any(p["id"] == body["id"] for p in liste.json())
|
||||
|
||||
geaendert = await client.patch(
|
||||
f"/api/v1/personen/{body['id']}", json={"kontakt": "Erziehungsberechtigter: 0170..."}, headers=auth_header(token)
|
||||
)
|
||||
assert geaendert.json()["kontakt"] == "Erziehungsberechtigter: 0170..."
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mitarbeiter_darf_person_nicht_anlegen(client, mitarbeiter_user):
|
||||
token = await login(client, "mitarbeiter1")
|
||||
response = await client.post("/api/v1/personen", json={"name": "Jemand"}, headers=auth_header(token))
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_benutzer_bekommt_automatisch_verknuepfte_person(client, admin_user):
|
||||
"""PERS-002: bestehender Flow (Benutzer ohne explizite person_id anlegen)
|
||||
bleibt unverändert - Person wird automatisch mitangelegt."""
|
||||
token = await login(client, "admin1")
|
||||
benutzer = await client.post(
|
||||
"/api/v1/benutzer",
|
||||
json={"name": "Auto-Person Helfer", "login": "autoperson1", "passwort": "test-passwort-123"},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
assert benutzer.status_code == 201
|
||||
person_id = benutzer.json()["person_id"]
|
||||
assert person_id is not None
|
||||
|
||||
personen = await client.get("/api/v1/personen", headers=auth_header(token))
|
||||
assert any(p["id"] == person_id and p["name"] == "Auto-Person Helfer" for p in personen.json())
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_benutzer_mit_bestehender_person_verknuepfen(client, admin_user):
|
||||
"""PERS-002: bereits erfasste Person (z.B. aus der Jugendgruppe) bekommt
|
||||
nachträglich einen Login, ohne dass eine zweite Person entsteht."""
|
||||
token = await login(client, "admin1")
|
||||
person = await client.post("/api/v1/personen", json={"name": "Bestehende Person"}, headers=auth_header(token))
|
||||
person_id = person.json()["id"]
|
||||
|
||||
benutzer = await client.post(
|
||||
"/api/v1/benutzer",
|
||||
json={
|
||||
"name": "Bestehende Person",
|
||||
"login": "bestehendeperson1",
|
||||
"passwort": "test-passwort-123",
|
||||
"person_id": person_id,
|
||||
},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
assert benutzer.status_code == 201
|
||||
assert benutzer.json()["person_id"] == person_id
|
||||
|
||||
personen = await client.get("/api/v1/personen", headers=auth_header(token))
|
||||
assert len([p for p in personen.json() if p["id"] == person_id]) == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_benutzer_mit_unbekannter_person_id_abgelehnt(client, admin_user):
|
||||
token = await login(client, "admin1")
|
||||
response = await client.post(
|
||||
"/api/v1/benutzer",
|
||||
json={
|
||||
"name": "X",
|
||||
"login": "unbekanntperson1",
|
||||
"passwort": "test-passwort-123",
|
||||
"person_id": 999999,
|
||||
},
|
||||
headers=auth_header(token),
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_qualifikation_erfassen_steht_in_historie(client, admin_user, mitarbeiter_user):
|
||||
from datetime import date
|
||||
|
||||
Reference in New Issue
Block a user