Neues Wartungskonzept: Wartungsplan+Position+Intervall (zeit/km/ Betriebsstunden, kombinierbar - fällig sobald ein Kriterium erreicht ist), Wartungsauftrag mit intern/externer Werkstatt, Status offen/ in_arbeit/erledigt, Kosten, Historie, Dokument-Anhang. Ad-hoc-Aufträge ohne Plan möglich (z.B. kleinere Reparatur). Admin-Tab "Wartungspläne". Objektakte-Redesign (Epic 21, Nutzer-Feedback "wirkt nicht modern"): CSS-Grid statt Karten-Stapel, einspaltig mobil, zweispaltig ab 900px; Fahrzeug-Objekte zeigen Wartung/Fahrzeugdaten prominent, Geräte/ Rucksäcke die Beladung. Dabei gefundene Lücke: Beladung (Soll/Ist je Position) fehlte in der Akte komplett, nur über eine laufende Kontrolle sichtbar - jetzt eigene Karte. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
215 lines
7.5 KiB
Python
215 lines
7.5 KiB
Python
from datetime import date
|
|
|
|
import pytest
|
|
|
|
from app.models.objekt import Objekt
|
|
from app.services.datumshilfen import plus_monate
|
|
from tests.conftest import auth_header, login
|
|
|
|
|
|
async def _objekt_mit_typ(db_session, hauptserver_id, *, code, name, objekttyp, standort):
|
|
objekt = Objekt(
|
|
code=code,
|
|
name=name,
|
|
objekttyp_id=objekttyp.id,
|
|
standort_id=standort.id,
|
|
zustaendiger_server_id=hauptserver_id,
|
|
)
|
|
db_session.add(objekt)
|
|
await db_session.flush()
|
|
return objekt
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_wartungsplan_mit_intervall_anlegen(client, admin_user, objekttyp_factory):
|
|
token = await login(client, "admin1")
|
|
objekttyp = await objekttyp_factory("RTW-Test")
|
|
|
|
response = await client.post(
|
|
"/api/v1/wartungsplaene",
|
|
json={
|
|
"objekttyp_id": objekttyp.id,
|
|
"name": "RTW Standard",
|
|
"positionen": [
|
|
{
|
|
"wartungsart": "Ölwechsel",
|
|
"intervalle": [{"typ": "zeit", "wert": 12}, {"typ": "km", "wert": 15000}],
|
|
}
|
|
],
|
|
},
|
|
headers=auth_header(token),
|
|
)
|
|
assert response.status_code == 201
|
|
body = response.json()
|
|
assert len(body["positionen"]) == 1
|
|
assert len(body["positionen"][0]["intervalle"]) == 2
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_nie_durchgefuehrte_wartung_ist_faellig(
|
|
client, db_session, hauptserver_id, admin_user, objekttyp_factory, standort_factory
|
|
):
|
|
token = await login(client, "admin1")
|
|
objekttyp = await objekttyp_factory("RTW-Test2")
|
|
standort = await standort_factory("Standort-W2")
|
|
objekt = await _objekt_mit_typ(
|
|
db_session, hauptserver_id, code="RTW-W2", name="RTW W2", objekttyp=objekttyp, standort=standort
|
|
)
|
|
objekt_id = objekt.id
|
|
|
|
await client.post(
|
|
"/api/v1/wartungsplaene",
|
|
json={"objekttyp_id": objekttyp.id, "name": "Plan", "positionen": [{"wartungsart": "Ölwechsel"}]},
|
|
headers=auth_header(token),
|
|
)
|
|
|
|
response = await client.get(f"/api/v1/objekte/{objekt_id}/faellige-wartungen", headers=auth_header(token))
|
|
assert response.status_code == 200
|
|
body = response.json()
|
|
assert len(body) == 1
|
|
assert body[0]["faellig"] is True
|
|
assert body[0]["wartungsart"] == "Ölwechsel"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_wartungsauftrag_erledigen_macht_zeit_intervall_nicht_faellig(
|
|
client, db_session, hauptserver_id, admin_user, objekttyp_factory, standort_factory
|
|
):
|
|
token = await login(client, "admin1")
|
|
objekttyp = await objekttyp_factory("RTW-Test3")
|
|
standort = await standort_factory("Standort-W3")
|
|
objekt = await _objekt_mit_typ(
|
|
db_session, hauptserver_id, code="RTW-W3", name="RTW W3", objekttyp=objekttyp, standort=standort
|
|
)
|
|
objekt_id = objekt.id
|
|
|
|
plan = await client.post(
|
|
"/api/v1/wartungsplaene",
|
|
json={
|
|
"objekttyp_id": objekttyp.id,
|
|
"name": "Plan",
|
|
"positionen": [{"wartungsart": "Ölwechsel", "intervalle": [{"typ": "zeit", "wert": 12}]}],
|
|
},
|
|
headers=auth_header(token),
|
|
)
|
|
position_id = plan.json()["positionen"][0]["id"]
|
|
|
|
auftrag = await client.post(
|
|
"/api/v1/wartungsauftraege",
|
|
json={"objekt_id": objekt_id, "wartungsplan_position_id": position_id, "wartungsart": "Ölwechsel"},
|
|
headers=auth_header(token),
|
|
)
|
|
assert auftrag.status_code == 201
|
|
auftrag_id = auftrag.json()["id"]
|
|
|
|
erledigt = await client.post(
|
|
f"/api/v1/wartungsauftraege/{auftrag_id}/erledigen",
|
|
json={"erledigt_am": date.today().isoformat()},
|
|
headers=auth_header(token),
|
|
)
|
|
assert erledigt.status_code == 200
|
|
assert erledigt.json()["status"] == "erledigt"
|
|
|
|
faellig = await client.get(f"/api/v1/objekte/{objekt_id}/faellige-wartungen", headers=auth_header(token))
|
|
assert faellig.json()[0]["faellig"] is False
|
|
assert faellig.json()[0]["faellig_am"] == plus_monate(date.today(), 12).isoformat()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_km_intervall_wird_zuerst_faellig_trotz_gueltigem_zeit_intervall(
|
|
client, db_session, hauptserver_id, admin_user, objekttyp_factory, standort_factory
|
|
):
|
|
""""je nachdem was zuerst eintritt" - km-Schwelle erreicht, obwohl das
|
|
Zeit-Intervall noch nicht abgelaufen ist."""
|
|
from app.models.fahrzeugdetails import Fahrzeugdetails
|
|
|
|
token = await login(client, "admin1")
|
|
objekttyp = await objekttyp_factory("RTW-Test4")
|
|
standort = await standort_factory("Standort-W4")
|
|
objekt = await _objekt_mit_typ(
|
|
db_session, hauptserver_id, code="RTW-W4", name="RTW W4", objekttyp=objekttyp, standort=standort
|
|
)
|
|
objekt_id = objekt.id
|
|
|
|
db_session.add(Fahrzeugdetails(objekt_id=objekt_id, kilometerstand=20000))
|
|
await db_session.flush()
|
|
|
|
plan = await client.post(
|
|
"/api/v1/wartungsplaene",
|
|
json={
|
|
"objekttyp_id": objekttyp.id,
|
|
"name": "Plan",
|
|
"positionen": [
|
|
{
|
|
"wartungsart": "Ölwechsel",
|
|
"intervalle": [{"typ": "zeit", "wert": 12}, {"typ": "km", "wert": 15000}],
|
|
}
|
|
],
|
|
},
|
|
headers=auth_header(token),
|
|
)
|
|
position_id = plan.json()["positionen"][0]["id"]
|
|
|
|
auftrag = await client.post(
|
|
"/api/v1/wartungsauftraege",
|
|
json={"objekt_id": objekt_id, "wartungsplan_position_id": position_id, "wartungsart": "Ölwechsel"},
|
|
headers=auth_header(token),
|
|
)
|
|
auftrag_id = auftrag.json()["id"]
|
|
await client.post(
|
|
f"/api/v1/wartungsauftraege/{auftrag_id}/erledigen",
|
|
json={"erledigt_am": date.today().isoformat(), "kilometerstand_bei_erledigung": 5000},
|
|
headers=auth_header(token),
|
|
)
|
|
|
|
faellig = await client.get(f"/api/v1/objekte/{objekt_id}/faellige-wartungen", headers=auth_header(token))
|
|
body = faellig.json()[0]
|
|
assert body["faellig"] is True
|
|
assert body["faellig_bei_km"] == 20000
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_ad_hoc_reparatur_ohne_wartungsplan_mit_externer_werkstatt(
|
|
client, admin_user, standort_factory, objekt_factory
|
|
):
|
|
token = await login(client, "admin1")
|
|
standort = await standort_factory("Standort-W5")
|
|
await objekt_factory(name="RTW W5", code="RTW-W5", standort=standort)
|
|
objekte = await client.get("/api/v1/objekte", headers=auth_header(token))
|
|
objekt_id = [o for o in objekte.json() if o["code"] == "RTW-W5"][0]["id"]
|
|
|
|
auftrag = await client.post(
|
|
"/api/v1/wartungsauftraege",
|
|
json={
|
|
"objekt_id": objekt_id,
|
|
"wartungsart": "Bremsleuchte defekt",
|
|
"werkstatt_intern": False,
|
|
"werkstatt_name": "KFZ Meyer GmbH",
|
|
},
|
|
headers=auth_header(token),
|
|
)
|
|
assert auftrag.status_code == 201
|
|
body = auftrag.json()
|
|
assert body["wartungsplan_position_id"] is None
|
|
assert body["werkstatt_intern"] is False
|
|
assert body["werkstatt_name"] == "KFZ Meyer GmbH"
|
|
assert body["status"] == "offen"
|
|
|
|
in_arbeit = await client.patch(
|
|
f"/api/v1/wartungsauftraege/{body['id']}/status",
|
|
json={"status": "in_arbeit"},
|
|
headers=auth_header(token),
|
|
)
|
|
assert in_arbeit.json()["status"] == "in_arbeit"
|
|
|
|
erledigt = await client.post(
|
|
f"/api/v1/wartungsauftraege/{body['id']}/erledigen",
|
|
json={"kosten": "89.90"},
|
|
headers=auth_header(token),
|
|
)
|
|
assert erledigt.json()["status"] == "erledigt"
|
|
assert erledigt.json()["kosten"] == "89.90"
|
|
|
|
historie = await client.get(f"/api/v1/wartungsauftraege?objekt_id={objekt_id}", headers=auth_header(token))
|
|
assert len(historie.json()) == 1
|