feat(mitarbeiter): Vorgesetzter auch fuer Personen ohne Verzeichnis (#43)
Prüfung / pruefung (push) Canceled after 0s
Prüfung / e2e (push) Canceled after 0s

This commit was merged in pull request #43.
This commit is contained in:
2026-10-04 15:10:34 +00:00
parent 0fa41b9e08
commit 0060a55387
19 changed files with 683 additions and 49 deletions
+115
View File
@@ -6,12 +6,15 @@ import {
mitarbeiterAktivSetzen,
mitarbeiterAnlegen,
mitarbeiterBearbeiten,
vorgesetztenSetzen,
} from "@/server/services/mitarbeiter";
import {
abteilungsNamen,
geraeteDesMitarbeiters,
mitarbeiterHolen,
mitarbeiterListe,
moeglicheVorgesetzte,
vorgesetzterVon,
} from "@/server/queries/mitarbeiter";
import { datenbankLeeren, datenbankVerfuegbar, testPrisma } from "./helpers/db";
@@ -40,6 +43,118 @@ describe.runIf(datenbankVerfuegbar)("Mitarbeiter", () => {
await datenbankLeeren();
});
describe("Vorgesetzter", () => {
it("laesst sich fuer eine von Hand angelegte Person setzen", async () => {
// Der Fall, der vorher gar nicht ging: ohne Verzeichnisquelle gab es kein
// Feld fuer die Zuordnung (#020).
const { admin } = await grundbestand();
const maria = await mitarbeiterAnlegen({ vorname: "Maria", nachname: "Huber" }, admin);
const petra = await mitarbeiterAnlegen({ vorname: "Petra", nachname: "Klein" }, admin);
expect(maria.herkunft).toBe(Herkunft.MANUELL);
await vorgesetztenSetzen(maria.id, petra.id, admin);
expect(await vorgesetzterVon(maria.id, admin)).toEqual({
id: petra.id,
anzeigename: "Petra Klein",
});
});
it("entfernt die Zuordnung bei leerer Angabe", async () => {
const { admin } = await grundbestand();
const maria = await mitarbeiterAnlegen({ vorname: "Maria", nachname: "Huber" }, admin);
const petra = await mitarbeiterAnlegen({ vorname: "Petra", nachname: "Klein" }, admin);
await vorgesetztenSetzen(maria.id, petra.id, admin);
await vorgesetztenSetzen(maria.id, "", admin);
expect(await vorgesetzterVon(maria.id, admin)).toBeUndefined();
});
it("laesst niemanden sein eigener Vorgesetzter sein", async () => {
const { admin } = await grundbestand();
const maria = await mitarbeiterAnlegen({ vorname: "Maria", nachname: "Huber" }, admin);
await expect(vorgesetztenSetzen(maria.id, maria.id, admin)).rejects.toThrow(/eigener Vorgesetzter/);
});
it("weist eine Schleife ueber zwei Personen ab", async () => {
const { admin } = await grundbestand();
const a = await mitarbeiterAnlegen({ vorname: "A", nachname: "Eins" }, admin);
const b = await mitarbeiterAnlegen({ vorname: "B", nachname: "Zwei" }, admin);
await vorgesetztenSetzen(b.id, a.id, admin);
await expect(vorgesetztenSetzen(a.id, b.id, admin)).rejects.toThrow(/Schleife/);
});
it("weist eine Schleife ueber drei Personen ab", async () => {
// Die Datenbank faengt nur die kuerzeste ab; diese braucht den Gang nach
// oben im Dienst.
const { admin } = await grundbestand();
const a = await mitarbeiterAnlegen({ vorname: "A", nachname: "Eins" }, admin);
const b = await mitarbeiterAnlegen({ vorname: "B", nachname: "Zwei" }, admin);
const c = await mitarbeiterAnlegen({ vorname: "C", nachname: "Drei" }, admin);
await vorgesetztenSetzen(b.id, a.id, admin);
await vorgesetztenSetzen(c.id, b.id, admin);
await expect(vorgesetztenSetzen(a.id, c.id, admin)).rejects.toThrow(/Schleife/);
});
it("gilt nur innerhalb desselben Kunden", async () => {
const { eigene, admin } = await grundbestand();
const fremd = await testPrisma.kunde.create({ data: { name: "Fremd GmbH", kuerzel: "FREMD" } });
const hier = await testPrisma.mitarbeiter.create({
data: { kundeId: eigene.id, vorname: "Maria", nachname: "Huber", anzeigename: "Maria Huber" },
});
const dort = await testPrisma.mitarbeiter.create({
data: { kundeId: fremd.id, vorname: "Petra", nachname: "Klein", anzeigename: "Petra Klein" },
});
await expect(vorgesetztenSetzen(hier.id, dort.id, admin)).rejects.toThrow(/selben Kunden/);
// Und auch an der Service-Schicht vorbei nicht: der zusammengesetzte
// Fremdschluessel haelt dieselbe Grenze.
await expect(
testPrisma.mitarbeiter.update({
where: { id: hier.id },
data: { vorgesetzterId: dort.id },
}),
).rejects.toThrow(/Mitarbeiter_vorgesetzter_gleicher_kunde/);
});
it("bietet zur Auswahl nur aktive Kollegen desselben Kunden, ohne die Person selbst", async () => {
const { eigene, admin } = await grundbestand();
const fremd = await testPrisma.kunde.create({ data: { name: "Fremd GmbH", kuerzel: "FREMD" } });
const maria = await mitarbeiterAnlegen({ vorname: "Maria", nachname: "Huber" }, admin);
const petra = await mitarbeiterAnlegen({ vorname: "Petra", nachname: "Klein" }, admin);
const weg = await mitarbeiterAnlegen({ vorname: "Alt", nachname: "Kollege" }, admin);
await mitarbeiterAktivSetzen(weg.id, false, admin);
await testPrisma.mitarbeiter.create({
data: { kundeId: fremd.id, vorname: "Fremd", nachname: "Person", anzeigename: "Fremd Person" },
});
expect(eigene.id).toBe(maria.kundeId);
const auswahl = await moeglicheVorgesetzte(maria.id, admin);
expect(auswahl.map((eintrag) => eintrag.id)).toEqual([petra.id]);
});
it("schreibt die Aenderung ins Protokoll, mit Namen", async () => {
const { admin } = await grundbestand();
const maria = await mitarbeiterAnlegen({ vorname: "Maria", nachname: "Huber" }, admin);
const petra = await mitarbeiterAnlegen({ vorname: "Petra", nachname: "Klein" }, admin);
await vorgesetztenSetzen(maria.id, petra.id, admin);
await vorgesetztenSetzen(maria.id, null, admin);
const eintraege = await testPrisma.protokoll.findMany({
where: { entitaet: "Mitarbeiter", entitaetId: maria.id },
orderBy: { erstelltAm: "asc" },
select: { aktion: true },
});
// Das Anlegen protokolliert selbst - hier zaehlt, was danach kam.
expect(eintraege.map((e) => e.aktion).slice(1)).toEqual([
"Vorgesetzter auf Petra Klein gesetzt",
"Vorgesetzter entfernt",
]);
});
});
describe("Anlegen", () => {
it("bildet den Anzeigenamen aus Vor- und Nachname, wenn keiner angegeben ist", async () => {
const { admin } = await grundbestand();