diff --git a/lib/offboarding.ts b/lib/offboarding.ts index 1465c85..669e869 100644 --- a/lib/offboarding.ts +++ b/lib/offboarding.ts @@ -66,15 +66,25 @@ export function fortschritt(staende: AufgabenStand[]): Fortschritt { /** * Ob eine Person offzuboarden ist — die Regel hinter dem Reiter. * - * Nur ein echter Austritt zählt. No Show scheidet zwar mit demselben Status - * „Ausgetreten" aus, hat aber nie einen Tag gearbeitet: keinen IT-Zugang, der - * eingerichtet wurde, keine GKK-Anmeldung, kein Dienstzettel. Ein Reiter mit - * einer leeren Liste wäre dort ein Etikett ohne Inhalt. + * Geprüft wird `exit_date`, nicht `status`. Eine künftige Beendigung setzt + * beide Felder sofort — terminate_employee schreibt `exit_date` unabhängig + * davon, ob der Stichtag schon erreicht ist —, während `status` erst am + * Stichtag selbst auf „Ausgetreten" wechselt. Bis dahin steht die Person + * weiterhin als „Aktiv"; die vier Wochen bis zum Austritt sind aber genau die + * Zeit, in der IT-Zugänge, Hardware und Anmeldungen abgewickelt werden. Mit + * `status` als Bedingung bliebe der Reiter bis zum letzten Arbeitstag + * unsichtbar — zu spät, um dort etwas vorzubereiten. * - * Wird die Person wiedereingestellt, wechselt der Status weg von - * „Ausgetreten", und die Regel verneint wieder — die Checkliste bleibt in den - * Daten stehen, nur ihr Reiter verschwindet, solange sie ohne Gegenstand ist. + * No Show hat `exit_date` ebenfalls gesetzt (den Eintrittstag), aber nie + * einen Tag gearbeitet: keinen IT-Zugang, der eingerichtet wurde, keine + * GKK-Anmeldung, kein Dienstzettel. Ein Reiter mit einer leeren Liste wäre + * dort ein Etikett ohne Inhalt — deshalb der Ausschluss über `exit_reason`. + * + * Wird die Person wiedereingestellt, setzt rehire_employee `exit_date` und + * `exit_reason` ausdrücklich auf null zurück, und die Regel verneint wieder — + * die Checkliste bleibt in den Daten stehen, nur ihr Reiter verschwindet, + * solange sie ohne Gegenstand ist. */ -export function gehoertOffboarding(employee: { status: string; exit_reason: string | null }): boolean { - return employee.status === "Ausgetreten" && employee.exit_reason !== "No Show"; +export function gehoertOffboarding(employee: { exit_date: string | null; exit_reason: string | null }): boolean { + return employee.exit_date !== null && employee.exit_reason !== "No Show"; } diff --git a/tests/unit/offboarding.test.ts b/tests/unit/offboarding.test.ts index 38186a3..4383960 100644 --- a/tests/unit/offboarding.test.ts +++ b/tests/unit/offboarding.test.ts @@ -93,23 +93,29 @@ describe("istErledigt", () => { }); describe("gehoertOffboarding", () => { - // Die Regel hinter dem Reiter: er erscheint bei einem echten Austritt, - // nicht bei jedem, der denselben Status „Ausgetreten" trägt. - it("bejaht bei einem echten Austritt", () => { - expect(gehoertOffboarding({ status: "Ausgetreten", exit_reason: "Kündigung AN" })).toBe(true); + // Geprüft wird exit_date, nicht status: eine künftige Beendigung setzt + // exit_date sofort, aber status erst am Stichtag selbst. Bis dahin steht + // die Person weiterhin als „Aktiv" — mit status als Bedingung bliebe der + // Reiter bis zum letzten Arbeitstag unsichtbar, genau dann, wenn er + // gebraucht wird. + it("bejaht bei einem bereits wirksamen Austritt", () => { + expect(gehoertOffboarding({ exit_date: "2026-08-01", exit_reason: "Kündigung AN" })).toBe(true); }); - it("verneint bei No Show, obwohl der Status derselbe ist", () => { + it("bejaht schon bei einem erst künftig wirksamen Austritt", () => { + expect(gehoertOffboarding({ exit_date: "2099-01-01", exit_reason: "Kündigung AN" })).toBe(true); + }); + + it("verneint bei No Show, obwohl exit_date ebenso gesetzt ist", () => { // Nie einen Tag gearbeitet: kein IT-Zugang, keine GKK-Anmeldung, kein // Dienstzettel. Der Reiter wäre ein Etikett ohne Inhalt. - expect(gehoertOffboarding({ status: "Ausgetreten", exit_reason: "No Show" })).toBe(false); + expect(gehoertOffboarding({ exit_date: "2026-08-01", exit_reason: "No Show" })).toBe(false); }); - it("verneint für eine aktive Person", () => { - expect(gehoertOffboarding({ status: "Aktiv", exit_reason: null })).toBe(false); - }); - - it("verneint für eine geplante Person", () => { - expect(gehoertOffboarding({ status: "Geplant", exit_reason: null })).toBe(false); + it("verneint ohne Austritt — auch nach einer Wiedereinstellung, die exit_date zurücksetzt", () => { + // Beides führt auf dieselbe Datenlage: wer nie ausgeschieden ist, und wer + // wiedereingestellt wurde (rehire_employee setzt exit_date und + // exit_reason ausdrücklich auf null), sehen für diese Regel gleich aus. + expect(gehoertOffboarding({ exit_date: null, exit_reason: null })).toBe(false); }); });