From 4165f3f8a10f909606dfe231eab6c1b0c88f0761 Mon Sep 17 00:00:00 2001
From: Andrei Laas
Date: Thu, 17 Sep 2026 11:50:26 +0200
Subject: [PATCH] Der Wiedereintritt war da, nur nicht erreichbar
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Aus dem Gespraech vom 17.09.2026.
Der Kunde suchte den Knopf "Wiedereintritt" an einer ausgetretenen Person
und hielt ihn fuer verschwunden — "ich dachte eigentlich, das ist schon
implementiert, das war mal drin". Er war drin. Er hing nur an
employee.status, und diese Spalte haengt nach: an einer Person, deren
Austritt erfasst und inzwischen vollzogen war, stand dort weiter "Aktiv".
Das ist mein Fehler beim Statusfix. Umgestellt waren dort `isActive` und
`canEditData` — die fuenf einzelnen Abfragen in derselben Datei blieben
stehen, dazu je eine in KarenzPanel und TerminatePanel. Jetzt liest keine
mehr die Spalte; die beiden Panels bekommen den abgeleiteten Status
uebergeben, statt ihn sich selbst aus der Zeile zu holen.
Betroffen war ausser dem Wiedereintritt auch: welcher Austritts-Knopf
erscheint ("Nicht angetreten" statt "Austritt"), die Beschriftung der
Abwesenheit, die Vorbelegung der Beendigungsart und ob die Zugehoerigkeit
angezeigt wird.
Dazu: die Niederlassung ist aus dem Reiter Organisation wieder raus. Sie
stand dort als unsere Auslegung von Anforderung 8; der Kunde hat sie im
Gespraech gestrichen ("nimm's mal hier raus"). Was mit der Anforderung
gemeint war, bleibt offen.
---
components/employees/EmployeeDetail.tsx | 33 ++++++++++++++-----
components/employees/panels/KarenzPanel.tsx | 19 ++++++++---
.../employees/panels/TerminatePanel.tsx | 8 +++--
components/employees/tabs/OrganisationTab.tsx | 29 +++++-----------
tests/components/TerminatePanel.test.tsx | 19 +++++++++--
5 files changed, 69 insertions(+), 39 deletions(-)
diff --git a/components/employees/EmployeeDetail.tsx b/components/employees/EmployeeDetail.tsx
index 1f97306..d8e7d62 100644
--- a/components/employees/EmployeeDetail.tsx
+++ b/components/employees/EmployeeDetail.tsx
@@ -117,7 +117,7 @@ export function EmployeeDetail(props: EmployeeDetailProps) {
diff --git a/components/employees/panels/TerminatePanel.tsx b/components/employees/panels/TerminatePanel.tsx
index 7517048..004b1c0 100644
--- a/components/employees/panels/TerminatePanel.tsx
+++ b/components/employees/panels/TerminatePanel.tsx
@@ -15,7 +15,7 @@ import {
beendigungsartenZu,
type Austrittsart,
} from "@/lib/beendigung";
-import type { Database } from "@/lib/types";
+import type { Database, EmploymentStatus } from "@/lib/types";
import { fmtDate, fmtName } from "@/lib/format";
type EmployeeRow = Database["public"]["Tables"]["employees"]["Row"];
@@ -28,17 +28,19 @@ type TerminatePanelProps = {
open: boolean;
onClose: () => void;
employee: EmployeeRow;
+ /** Der zum heutigen Tag abgeleitete Status — nicht `employee.status`, die Spalte hängt nach. */
+ status: EmploymentStatus;
directReportCount: number;
};
-export function TerminatePanel({ open, onClose, employee, directReportCount }: TerminatePanelProps) {
+export function TerminatePanel({ open, onClose, employee, status, directReportCount }: TerminatePanelProps) {
const { showToast } = useToast();
const router = useRouter();
const [exitDate, setExitDate] = useState("");
// Wer noch gar nicht angefangen hat, tritt fast nie aus einem anderen Grund
// aus. Die Vorbelegung nimmt den wahrscheinlichen Fall vorweg, ohne die
// übrigen zu verstellen.
- const [reason, setReason] = useState(employee.status === "Geplant" ? NO_SHOW : BEENDIGUNGSART_WERTE[0]);
+ const [reason, setReason] = useState(status === "Geplant" ? NO_SHOW : BEENDIGUNGSART_WERTE[0]);
// „Alle" statt einer Vorauswahl: die Einschränkung ist eine Hilfe beim
// Suchen, keine Pflichtangabe. Wer die gewünschte Art auswendig kennt,
// soll sie unmittelbar wählen können.
diff --git a/components/employees/tabs/OrganisationTab.tsx b/components/employees/tabs/OrganisationTab.tsx
index 81a34b2..cdf3a5c 100644
--- a/components/employees/tabs/OrganisationTab.tsx
+++ b/components/employees/tabs/OrganisationTab.tsx
@@ -19,23 +19,17 @@ type OrganisationTabProps = {
* hat die Person keine laufende Besetzung (geplanter Eintritt, Austritt).
*/
kostenstelle: { code: string; name: string } | null;
- /**
- * Die Niederlassung, an der die Person arbeitet.
- *
- * Aus dem Workshop nachgetragen (Anforderung 8, „Niederlassungen auch in
- * Zuordnung einfügen"). Sie stand bisher nur im Stammdatenblatt, obwohl sie
- * zur Einordnung gehört wie die Einheit und die Kostenstelle: wer wissen
- * will, wo jemand sitzt, sieht hier nach und nicht bei der Privatadresse.
- *
- * Anders als Einheit und Kostenstelle hängt sie **an der Person**
- * (`employees.location_id`) und nicht an der Planstelle. Deshalb steht sie
- * auch dann da, wenn es keine laufende Besetzung gibt — bei einem
- * geplanten Eintritt zum Beispiel, wo daneben „Keine laufende
- * Planstellenbesetzung" zu lesen ist.
- */
- standort: string | null;
};
+// Die Niederlassung stand hier kurzzeitig neben Einheit und Kostenstelle —
+// unsere Auslegung von „Niederlassungen auch in Zuordnung einfügen"
+// (Anforderung 8). Im Gespräch am 17.09.2026 hat der Kunde sie hier wieder
+// gestrichen: „nimm's mal hier raus, ich glaub, da brauchen wir's nicht
+// drin." Sie steht weiterhin im Vertragsblatt.
+//
+// Was mit der Anforderung gemeint war, ist damit weiterhin offen — siehe
+// docs/rueckfragen-workshop-2026-09.md.
+
export function OrganisationTab({
employeeId,
manager,
@@ -43,7 +37,6 @@ export function OrganisationTab({
directReports,
breadcrumb,
kostenstelle,
- standort,
}: OrganisationTabProps) {
return (
@@ -51,10 +44,6 @@ export function OrganisationTab({
Organisationseinheit
{breadcrumb}
-
Niederlassung
-
- {standort ?? Nicht erfasst}
-
Kostenstelle
{kostenstelle ? (
diff --git a/tests/components/TerminatePanel.test.tsx b/tests/components/TerminatePanel.test.tsx
index a7668c3..a781b30 100644
--- a/tests/components/TerminatePanel.test.tsx
+++ b/tests/components/TerminatePanel.test.tsx
@@ -3,7 +3,7 @@ import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import { TerminatePanel } from "@/components/employees/panels/TerminatePanel";
import { ToastProvider } from "@/components/ui/Toast";
-import type { Database } from "@/lib/types";
+import type { Database, EmploymentStatus } from "@/lib/types";
type EmployeeRow = Database["public"]["Tables"]["employees"]["Row"];
@@ -76,10 +76,23 @@ function mitarbeiter(teil: Partial = {}): EmployeeRow {
} as EmployeeRow;
}
-function zeige(teil: Partial = {}) {
+// Der Status kommt als eigener Wert und nicht mehr aus der Zeile: die Spalte
+// `employees.status` hängt nach, deshalb leitet die Akte ihn aus den Daten ab
+// und reicht ihn durch (siehe lib/reports.ts, deriveStatusAsOf).
+function zeige(teil: Partial = {}, status?: EmploymentStatus) {
+ // Vorgabe aus der Zeile, damit die vorhandenen Fälle unverändert das meinen,
+ // was sie meinten — `zeige({ status: "Aktiv" })` beschreibt weiterhin eine
+ // aktive Person. Der abgeleitete Status ist nur noch ein eigener Weg zum
+ // selben Wert, und die Vorgabe „Geplant" entspricht der Zeile oben.
return render(
- {}} employee={mitarbeiter(teil)} directReportCount={0} />
+ {}}
+ employee={mitarbeiter(teil)}
+ status={status ?? teil.status ?? "Geplant"}
+ directReportCount={0}
+ />
);
}