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
+40 -13
View File
@@ -174,11 +174,15 @@ export async function geraeteDesMitarbeiters(
/**
* Der Vorgesetzte einer Person – oder `undefined`.
*
* Die Verknuepfung laeuft ueber `vorgesetzterExterneId` und die `externeId`
* **derselben Verzeichnisquelle**: die Kennung ist nur innerhalb einer Quelle
* eindeutig, und ohne diese Einschraenkung zoege ein zweites Verzeichnis
* fremde Treffer herbei. Gefuellt wird das Feld vom Abgleich (#016); bei einer
* von Hand angelegten Person steht hier nichts, und das ist richtig so.
* Gelesen wird **allein** `vorgesetzterId`: die gepflegte Zuordnung, die der
* Abgleich aus dem Verzeichnis mitschreibt und die sich auch von Hand setzen
* laesst (#020). Vorher lief die Auskunft ueber `vorgesetzterExterneId` und die
* `externeId` derselben Quelle — richtig fuer Verzeichnis-Personen, aber eine
* von Hand angelegte Person konnte so keinen Vorgesetzten haben.
*
* Die Mandantensicht wird trotzdem noch angewandt, obwohl ein zusammengesetzter
* Fremdschluessel dieselbe Grenze haelt: die Rollensicht des Benutzers ist eine
* andere Frage als die Struktur der Daten.
*/
export async function vorgesetzterVon(
mitarbeiterId: string,
@@ -186,22 +190,45 @@ export async function vorgesetzterVon(
): Promise<{ readonly id: string; readonly anzeigename: string } | undefined> {
const person = await prisma.mitarbeiter.findFirst({
where: { AND: [{ id: mitarbeiterId }, ...(await kundenBedingung(benutzer))] },
select: { quelleId: true, vorgesetzterExterneId: true },
select: { vorgesetzterId: true },
});
if (!person?.vorgesetzterExterneId || !person.quelleId) return undefined;
if (!person?.vorgesetzterId) return undefined;
const vorgesetzter = await prisma.mitarbeiter.findFirst({
where: {
AND: [
{ quelleId: person.quelleId, externeId: person.vorgesetzterExterneId },
...(await kundenBedingung(benutzer)),
],
},
where: { AND: [{ id: person.vorgesetzterId }, ...(await kundenBedingung(benutzer))] },
select: { id: true, anzeigename: true },
});
return vorgesetzter ?? undefined;
}
/**
* Wen man als Vorgesetzten waehlen kann (#020).
*
* Nur **aktive** Personen desselben Kunden, und die Person selbst nicht. Die
* eigene Zeile und ein fremder Kunde fielen sonst erst im Dienst auf; eine
* Auswahlliste, die unmoegliche Eintraege anbietet, ist eine Falle.
*
* Laengere Schleifen werden hier **nicht** herausgefiltert: dafuer muesste die
* Liste je Eintrag die Kette hinauflaufen. Der Dienst weist sie ab, mit einem
* Satz, der sagt warum.
*/
export async function moeglicheVorgesetzte(
mitarbeiterId: string,
benutzer: HandelnderBenutzer,
): Promise<readonly { readonly id: string; readonly anzeigename: string }[]> {
const person = await prisma.mitarbeiter.findFirst({
where: { AND: [{ id: mitarbeiterId }, ...(await kundenBedingung(benutzer))] },
select: { kundeId: true },
});
if (!person) return [];
return prisma.mitarbeiter.findMany({
where: { AND: [{ kundeId: person.kundeId, aktiv: true, id: { not: mitarbeiterId } }] },
select: { id: true, anzeigename: true },
orderBy: { anzeigename: "asc" },
});
}
/** Die vorkommenden Abteilungsnamen – fuer den Filter. */
export async function abteilungsNamen(benutzer: HandelnderBenutzer): Promise<readonly string[]> {
const zeilen = await prisma.mitarbeiter.findMany({