Phase 3: Einsatz- und Uebungserfassung
Schnellerfassung im Alarmfall, sechs Zeitstempel mit Ausrueckzeit, Anfahrt und Hilfsfrist, Staerke nach FwDV 3, Personalvorschlag mit Qualifikationsstand, Einsatzbericht als PDF, Jahresexport fuer die Gemeinde, Statistik und Uebungen mit Anwesenheitsliste. Dazu das Einsatzportal fuer Fremdwehren: ein signierter Link ohne Anmeldung, zeitlich und mengenbegrenzt, der Stichwort, Ort, Zeiten und Lagemeldungen zeigt und Meldungen mit Foto annimmt. Es sind die ersten oeffentlich erreichbaren Endpunkte in FLORIAN. Acht neue Tabellen, alle mit organisationId und Row Level Security. Ein freigegebener Einsatzbericht ist unveraenderlich; ein Datenbanktrigger setzt das durch. Koordinaten liegen doppelt — als Dezimalgrad und als PostGIS-Punkt, zusammengehalten von einem Trigger. 57 neue Tests (32 Unit, 14 gegen eine echte Datenbank, 11 E2E). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
bc62a9c1e8
commit
91954c402b
@@ -0,0 +1,127 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
EINHEITEN,
|
||||
staerkeAlsText,
|
||||
staerkeBerechnen,
|
||||
staerkeHinweise,
|
||||
taktischeEinheit,
|
||||
type Funktion,
|
||||
} from "@/lib/einsatz/staerke";
|
||||
|
||||
/**
|
||||
* Stärke nach FwDV 3.
|
||||
*
|
||||
* Die Zahlen stehen später im Einsatzbericht und in der Meldung an die
|
||||
* Gemeinde. Wer die Zuordnung ändert, ändert damit die Statistik der ganzen
|
||||
* Wehr — deshalb steht sie hier ausführlich unter Test.
|
||||
*/
|
||||
|
||||
/** Die Besetzung einer Gruppe nach FwDV 3. */
|
||||
const GRUPPE: Funktion[] = [
|
||||
"GRUPPENFUEHRER",
|
||||
"MASCHINIST",
|
||||
"MELDER",
|
||||
"TRUPPFUEHRER",
|
||||
"TRUPPMANN",
|
||||
"TRUPPFUEHRER",
|
||||
"TRUPPMANN",
|
||||
"TRUPPFUEHRER",
|
||||
"TRUPPMANN",
|
||||
];
|
||||
|
||||
/** Die Besetzung einer Staffel. */
|
||||
const STAFFEL: Funktion[] = [
|
||||
"GRUPPENFUEHRER",
|
||||
"MASCHINIST",
|
||||
"TRUPPFUEHRER",
|
||||
"TRUPPMANN",
|
||||
"TRUPPFUEHRER",
|
||||
"TRUPPMANN",
|
||||
];
|
||||
|
||||
describe("staerkeBerechnen", () => {
|
||||
it("zählt eine Gruppe als 1/3/5/9", () => {
|
||||
const staerke = staerkeBerechnen(GRUPPE);
|
||||
|
||||
expect(staerke).toEqual({ fuehrer: 1, unterfuehrer: 3, mannschaft: 5, gesamt: 9 });
|
||||
expect(staerkeAlsText(staerke)).toBe("1/3/5/9");
|
||||
});
|
||||
|
||||
it("zählt eine Staffel als 1/2/3/6", () => {
|
||||
expect(staerkeAlsText(staerkeBerechnen(STAFFEL))).toBe("1/2/3/6");
|
||||
});
|
||||
|
||||
it("zählt einen Trupp als 0/1/1/2", () => {
|
||||
expect(staerkeAlsText(staerkeBerechnen(["TRUPPFUEHRER", "TRUPPMANN"]))).toBe("0/1/1/2");
|
||||
});
|
||||
|
||||
it("zählt jede Führungsfunktion als Führer", () => {
|
||||
const staerke = staerkeBerechnen([
|
||||
"EINSATZLEITER",
|
||||
"ZUGFUEHRER",
|
||||
"GRUPPENFUEHRER",
|
||||
"STAFFELFUEHRER",
|
||||
]);
|
||||
|
||||
expect(staerke.fuehrer).toBe(4);
|
||||
expect(staerke.mannschaft).toBe(0);
|
||||
});
|
||||
|
||||
it("zählt den Maschinisten zur Mannschaft", () => {
|
||||
// Regional unterschiedlich — dieser Test hält die getroffene Festlegung
|
||||
// fest, damit eine Änderung auffällt statt durchzurutschen.
|
||||
const staerke = staerkeBerechnen(["MASCHINIST"]);
|
||||
expect(staerke.mannschaft).toBe(1);
|
||||
expect(staerke.unterfuehrer).toBe(0);
|
||||
});
|
||||
|
||||
it("liefert für niemanden lauter Nullen", () => {
|
||||
expect(staerkeAlsText(staerkeBerechnen([]))).toBe("0/0/0/0");
|
||||
});
|
||||
});
|
||||
|
||||
describe("taktischeEinheit", () => {
|
||||
it("erkennt die Einheiten der FwDV 3", () => {
|
||||
expect(taktischeEinheit(staerkeBerechnen(GRUPPE)).einheit).toBe("Gruppe");
|
||||
expect(taktischeEinheit(staerkeBerechnen(STAFFEL)).einheit).toBe("Staffel");
|
||||
expect(taktischeEinheit(staerkeBerechnen(["TRUPPFUEHRER", "TRUPPMANN"])).einheit).toBe("Trupp");
|
||||
});
|
||||
|
||||
it("nennt die überzähligen Kräfte", () => {
|
||||
const zehn = [...GRUPPE, "TRUPPMANN" as Funktion];
|
||||
const ergebnis = taktischeEinheit(staerkeBerechnen(zehn));
|
||||
|
||||
expect(ergebnis.einheit).toBe("Gruppe");
|
||||
expect(ergebnis.ueberzaehlig).toBe(1);
|
||||
});
|
||||
|
||||
it("gibt bei einer einzelnen Kraft keine Einheit zurück", () => {
|
||||
const ergebnis = taktischeEinheit(staerkeBerechnen(["GRUPPENFUEHRER"]));
|
||||
expect(ergebnis.einheit).toBeNull();
|
||||
expect(ergebnis.ueberzaehlig).toBe(1);
|
||||
});
|
||||
|
||||
it("kennt die Sollstärken", () => {
|
||||
expect(EINHEITEN.map((einheit) => einheit.staerke)).toEqual([2, 6, 9, 18]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("staerkeHinweise", () => {
|
||||
it("meldet, wenn niemand erfasst ist", () => {
|
||||
expect(staerkeHinweise(staerkeBerechnen([]))[0]).toContain("noch niemand erfasst");
|
||||
});
|
||||
|
||||
it("meldet eine fehlende Führungskraft", () => {
|
||||
const hinweise = staerkeHinweise(staerkeBerechnen(["TRUPPFUEHRER", "TRUPPMANN"]));
|
||||
expect(hinweise.some((hinweis) => hinweis.includes("Führungskraft"))).toBe(true);
|
||||
});
|
||||
|
||||
it("meldet den Alleingang", () => {
|
||||
const hinweise = staerkeHinweise(staerkeBerechnen(["GRUPPENFUEHRER"]));
|
||||
expect(hinweise.some((hinweis) => hinweis.includes("Alleine"))).toBe(true);
|
||||
});
|
||||
|
||||
it("schweigt bei einer vollständigen Gruppe", () => {
|
||||
expect(staerkeHinweise(staerkeBerechnen(GRUPPE))).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user