Workshop-Anforderungen, erster Teil: was ohne Migration geht

Anforderung 1 — Freiwilliger vs unfreiwilliger Austritt. Die Liste der
Beendigungsarten zieht aus TerminatePanel.tsx nach lib/beendigung.ts um: der
Berichtemanager braucht sie ebenso, und zwei Listen liefen auseinander. Zwei
neue Arten (Beendigung in der Probezeit, je Seite). Auf wessen Betreiben
beendet wurde, wird aus der Art **abgeleitet** und nicht daneben gespeichert
— als zweites freies Feld liesse sich "Entlassung, freiwillig" erfassen. Das
Dropdown im Formular schraenkt die Auswahl darunter ein.

Drei Gruppen statt zwei: Befristungsablauf geschieht auf niemandes
Betreiben, ein Nichtantritt ist kein Austritt. Beide einer Seite
zuzuschlagen wuerde jede Fluktuationsquote verfaelschen.

Anforderung 2 — Namensfilter in "Anstehend", ab neun Eintraegen.

Anforderung 3 — die zwei Unterschriftenfelder im gedruckten Blatt sind weg;
"Firmenfahrzeug" steht in beiden Checklisten. has_dienstwagen sagt, ob eines
zusteht, nicht ob es uebergeben wurde.

Anforderung 4 — "+794 weitere" ist ein Knopf geworden; die Namen waren
vorher nur ueber den Export erreichbar. Stammdatenaenderung und
Gehaltsanpassung stehen nicht mehr zur Auswahl: die eine entsteht bei jeder
geaenderten Telefonnummer, die andere ist ein totes Ereignis, seit das
Gehalt in Loga liegt. Neu ist der Untertyp — Beendigungsart beim Austritt,
Art der Abwesenheit bei der Langzeitabwesenheit, im Bericht und im Export.

Anforderung 10 — zwei Kacheln. "Aktives Dienstverhaeltnis" ist nicht
dasselbe wie "Aktive Mitarbeiter:innen": dort steht, wer heute arbeitet,
hier, mit wem ein Vertrag laeuft. Sichtbar waren 806 und 10, addieren musste
man selbst.
This commit is contained in:
2026-09-15 22:35:47 +02:00
parent 1cbed1a8f5
commit 8d0c9b4b65
15 changed files with 426 additions and 48 deletions

View File

@@ -1,6 +1,13 @@
import { NextResponse, type NextRequest } from "next/server";
import { exportFilename, exportResponseHeaders, toCsv, toXlsx, type ExportColumn } from "@/lib/export";
import { EVENT_TYPE_LABELS, parseEventDateParam, parseEventType, type OrgLookups, type ReportEvent } from "@/lib/reports";
import {
EVENT_TYPE_LABELS,
parseEventDateParam,
parseEventSubtype,
parseEventType,
type OrgLookups,
type ReportEvent,
} from "@/lib/reports";
import { loadEventHistory, loadOrgLookups } from "@/lib/reports-data";
import { requireHrUser } from "@/lib/auth/require-hr";
import { withUser } from "@/lib/db";
@@ -22,6 +29,10 @@ export async function GET(request: NextRequest) {
loadOrgLookups(tx),
loadEventHistory(tx, {
eventType: eventType ?? undefined,
// Ohne diese Zeile exportierte die Schaltfläche neben der Auswertung
// etwas anderes, als auf dem Bildschirm steht — die Einschränkung auf
// die Beendigungsart fiele beim Export still weg.
eventSubtype: parseEventSubtype(params.get("eventSubtype"), eventType) ?? undefined,
division: params.get("division") ?? undefined,
location: params.get("location") ?? undefined,
from: parseEventDateParam(params.get("from")),
@@ -43,6 +54,9 @@ function eventExportColumns(lookups: OrgLookups): ExportColumn<ReportEvent>[] {
return [
{ header: "Datum", get: (e) => e.event_date, kind: "date" },
{ header: "Ereignistyp", get: (e) => EVENT_TYPE_LABELS[e.event_type] ?? e.event_type },
// Beendigungsart bzw. Art der Langzeitabwesenheit. Leer bei allen
// Ereignissen, die keinen Untertyp kennen — eine Versetzung hat keinen.
{ header: "Untertyp", get: (e) => e.subtype ?? "" },
{ header: "Vorname", get: (e) => e.first_name },
{ header: "Nachname", get: (e) => e.last_name },
{ header: "Position", get: (e) => e.job_title },