@@ -665,7 +702,7 @@ export function ReportsPageClient(props: ReportsPageClientProps) {
TT.MM.JJJJ, Systemwerte statt Anzeigenamen (Active, Working, Employee). Ohne Location ID und
Position ID — dafür fehlen die Kennungen des Zielsystems.
- Status im Export: {statusExportLabel}
+
diff --git a/lib/report-criteria.ts b/lib/report-criteria.ts
index ef083eb..8db6f2a 100644
--- a/lib/report-criteria.ts
+++ b/lib/report-criteria.ts
@@ -1,5 +1,6 @@
import { ABSENCE_TYPES } from "./absence";
import { AUSTRITTSART_LABELS, AUSTRITTSARTEN, BEENDIGUNGSART_WERTE } from "./beendigung";
+import { fmtDate } from "./format";
import { HAY_GRADE_WERTE } from "./hay-grade";
import { KUENDIGUNGSSCHUTZ_GRUENDE } from "./kuendigungsschutz";
import { MITARBEITERARTEN } from "./mitarbeiterart";
@@ -179,6 +180,49 @@ export function anzahlKriterien(c: Criteria): number {
return n;
}
+/**
+ * Die gesetzten Kriterien in Worten.
+ *
+ * Die Exportkarten nannten nur den Status. Die übrigen Kriterien stehen
+ * eingeklappt weiter oben und wirken auf jeden Export dieser Seite genauso —
+ * wer eines gesetzt und vergessen hatte, lud eine Datei herunter, die nach dem
+ * ganzen Haus aussah und einen Ausschnitt enthielt. Bei einer Datei für ein
+ * Zielsystem merkt das niemand mehr, sobald sie dort eingespielt ist: dort
+ * fehlen dann Personen, und es sieht aus wie ein Datenstand, nicht wie ein
+ * Filter.
+ *
+ * `anzahlKriterien` daneben zählt dasselbe; hier steht, *was* es ist.
+ */
+export function beschreibeKriterien(c: Criteria): string[] {
+ const teile: string[] = [];
+
+ for (const k of AUSWAHL_KRITERIEN) {
+ const wert = c.auswahl[k.key];
+ if (!wert) continue;
+ teile.push(`${k.label}: ${k.optionen.find((o) => o.wert === wert)?.label ?? wert}`);
+ }
+
+ for (const k of JANEIN_KRITERIEN) {
+ const wert = c.jaNein[k.key];
+ if (wert) teile.push(`${k.label}: ${wert}`);
+ }
+
+ for (const k of ZEITRAUM_KRITERIEN) {
+ const z = c.zeitraum[k.key];
+ if (!z) continue;
+ if (z.von && z.bis) teile.push(`${k.label} ${fmtDate(z.von)} bis ${fmtDate(z.bis)}`);
+ else if (z.von) teile.push(`${k.label} ab ${fmtDate(z.von)}`);
+ else if (z.bis) teile.push(`${k.label} bis ${fmtDate(z.bis)}`);
+ }
+
+ const { stundenVon: von, stundenBis: bis } = c;
+ if (von !== undefined && bis !== undefined) teile.push(`Wochenstunden ${von} bis ${bis}`);
+ else if (von !== undefined) teile.push(`Wochenstunden ab ${von}`);
+ else if (bis !== undefined) teile.push(`Wochenstunden bis ${bis}`);
+
+ return teile;
+}
+
/** Alle Parameternamen, die zu den Kriterien gehören — zum Zurücksetzen. */
export function kriterienParameter(): string[] {
return [
diff --git a/tests/unit/report-criteria.test.ts b/tests/unit/report-criteria.test.ts
index 9668e1c..4afcdb4 100644
--- a/tests/unit/report-criteria.test.ts
+++ b/tests/unit/report-criteria.test.ts
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import {
anzahlKriterien,
AUSWAHL_KRITERIEN,
+ beschreibeKriterien,
JANEIN_KRITERIEN,
kriterienParameter,
LEERE_CRITERIA,
@@ -58,6 +59,52 @@ describe("parseCriteria", () => {
});
});
+describe("beschreibeKriterien", () => {
+ it("sagt nichts, wenn nichts eingeschränkt ist", () => {
+ expect(beschreibeKriterien(LEERE_CRITERIA)).toEqual([]);
+ });
+
+ it("nennt jedes gesetzte Kriterium beim Namen", () => {
+ const c = aus({ employment: "Teilzeit", dienstwagen: "ja", entryFrom: "2024-01-01", hoursTo: "30" });
+ expect(beschreibeKriterien(c)).toEqual([
+ "Beschäftigungsart: Teilzeit",
+ "Dienstwagen: ja",
+ "Eintritt ab 01.01.2024",
+ "Wochenstunden bis 30",
+ ]);
+ });
+
+ it("unterscheidet ab, bis und den geschlossenen Zeitraum", () => {
+ expect(beschreibeKriterien(aus({ entryFrom: "2020-06-01" }))).toEqual(["Eintritt ab 01.06.2020"]);
+ expect(beschreibeKriterien(aus({ entryTo: "2020-06-01" }))).toEqual(["Eintritt bis 01.06.2020"]);
+ expect(beschreibeKriterien(aus({ entryFrom: "2020-01-01", entryTo: "2020-12-31" }))).toEqual([
+ "Eintritt 01.01.2020 bis 31.12.2020",
+ ]);
+ });
+
+ it("zeigt die Beschriftung, nicht den gespeicherten Wert", () => {
+ // Bei der Austrittsart gehen die beiden auseinander; auf der Karte nützt
+ // nur das, was auch im Auswahlfeld steht.
+ const kriterium = AUSWAHL_KRITERIEN.find((k) => k.key === "austrittsart")!;
+ const option = kriterium.optionen[0];
+ expect(beschreibeKriterien(aus({ austrittsart: option.wert }))).toEqual([`${kriterium.label}: ${option.label}`]);
+ });
+
+ it("beschreibt so viele Kriterien, wie anzahlKriterien zählt", () => {
+ // Die Zahl am Aufklapper und der Text auf der Exportkarte dürfen nicht
+ // auseinanderlaufen: sonst meldet die eine Stelle eine Einschränkung, die
+ // die andere nicht benennt.
+ const alle = {
+ ...Object.fromEntries(AUSWAHL_KRITERIEN.map((k) => [k.key, k.optionen[0].wert])),
+ ...Object.fromEntries(JANEIN_KRITERIEN.map((k) => [k.key, "ja"])),
+ ...Object.fromEntries(ZEITRAUM_KRITERIEN.map((k) => [`${k.key}From`, "2024-01-01"])),
+ hoursFrom: "10",
+ };
+ const c = aus(alle);
+ expect(beschreibeKriterien(c)).toHaveLength(anzahlKriterien(c));
+ });
+});
+
describe("kriterienParameter", () => {
it("nennt jeden Parameter, den parseCriteria liest", () => {
// „Zurücksetzen" räumt anhand dieser Liste auf. Fehlt darin ein Name,