diff --git a/components/reports/ReportsPageClient.tsx b/components/reports/ReportsPageClient.tsx index 1f2f278..da91b17 100644 --- a/components/reports/ReportsPageClient.tsx +++ b/components/reports/ReportsPageClient.tsx @@ -644,8 +644,9 @@ export function ReportsPageClient(props: ReportsPageClientProps) {

Honestly-Report

- Teilnehmerliste für die Mitarbeiterbefragung: Personalnummer, E-Mail, Name, Standort und die + Teilnehmerliste für die Mitarbeiterbefragung: Personalnummer, Name, Standort und die Organisationskette von der eigenen Einheit bis ganz oben. Sprache immer „de“, Rolle immer „Respondee“. + Die Spalte „Email“ bleibt leer, bis die Firmen-E-Mail-Adresse erfasst wird.

Status im Export: {statusExportLabel}

diff --git a/lib/honestly.ts b/lib/honestly.ts index e8b099c..6e1d648 100644 --- a/lib/honestly.ts +++ b/lib/honestly.ts @@ -14,12 +14,18 @@ import { ancestorsOf, type OrgMaps } from "./org"; // hängt, hat hinten leere Zellen — und die oberste Einheit steht deshalb // nicht bei allen in derselben Spalte. So ist es bestellt. +// Die E-Mail-Spalte ist ein Platzhalter für die **Firmenadresse**, die es +// im Datenmodell noch nicht gibt. employees.email ist die private Adresse +// (Migration 20260811140000) und gehört nicht in eine Datei, die an einen +// fremden Anbieter geht — schon gar nicht als Adresse, an die Einladungen im +// Namen des Arbeitgebers gehen. Deshalb bleibt die Spalte leer, bis die +// Firmenadresse erfasst wird; die Spalte selbst bleibt stehen, damit die +// Zuordnung in Honestly nicht neu eingerichtet werden muss. export const HONESTLY_SPRACHE = "de"; export const HONESTLY_ROLLE = "Respondee"; export type HonestlyZeile = { personalnummer: number | string | null; - email: string | null; vorname: string; nachname: string; standort: string; @@ -58,7 +64,8 @@ export function honestlySpalten(tiefe: number): ExportColumn[] { })); return [ { header: "Personalnummer", get: (z) => z.personalnummer }, - { header: "Email", get: (z) => z.email ?? "" }, + // Platzhalter für die Firmenadresse — siehe oben. + { header: "Email", get: () => "" }, { header: "Firstname", get: (z) => z.vorname }, { header: "Last Name", get: (z) => z.nachname }, { header: "Language", get: () => HONESTLY_SPRACHE }, @@ -72,7 +79,6 @@ export function honestlySpalten(tiefe: number): ExportColumn[] { export function baueHonestlyZeilen( personen: { personnel_number: number | string | null; - email: string | null; first_name: string; last_name: string; location_id: string; @@ -83,7 +89,6 @@ export function baueHonestlyZeilen( ): { zeilen: HonestlyZeile[]; tiefe: number } { const zeilen = personen.map((p) => ({ personalnummer: p.personnel_number, - email: p.email, vorname: p.first_name, nachname: p.last_name, standort: standortName.get(p.location_id) ?? "", diff --git a/tests/unit/honestly.test.ts b/tests/unit/honestly.test.ts index b6ad44b..d4eefed 100644 --- a/tests/unit/honestly.test.ts +++ b/tests/unit/honestly.test.ts @@ -21,7 +21,9 @@ const standorte = new Map([["wien", "Wien"], ["wolkersdorf", "Wolkersdorf"]]); function person(teil: Partial[0][number]> = {}) { return { personnel_number: 4711, - email: "anna.berger@example.test", + // Die private Adresse, wie sie auf der Zeile aus der Datenbank steht — + // sie darf im Export nirgends auftauchen. + email: "anna.privat@example.test", first_name: "Anna", last_name: "Berger", location_id: "wien", @@ -97,18 +99,33 @@ describe("baueHonestlyZeilen", () => { const zeile = Object.fromEntries(honestlySpalten(tiefe).map((s) => [s.header, s.get(zeilen[0])])); expect(zeile).toMatchObject({ Personalnummer: 4711, - Email: "anna.berger@example.test", Firstname: "Anna", "Last Name": "Berger", Location: "Wien", }); }); - it("lässt eine fehlende E-Mail leer, statt sie zu erfinden", () => { - // Die Adresse ist privat und freiwillig (20260811140000). Eine leere - // Zelle fällt in Honestly auf; ein Platzhalter bekäme eine Einladung. - const { zeilen } = baueHonestlyZeilen([person({ email: null })], maps, standorte); - expect(honestlySpalten(1)[1].get(zeilen[0])).toBe(""); + it("lässt die E-Mail leer, bis es die Firmenadresse gibt", () => { + // Die Spalte ist ein Platzhalter für die Firmen-E-Mail. Die private + // Adresse (employees.email) gehört nicht in eine Datei an einen fremden + // Anbieter — auch nicht, wenn sie vorhanden ist. + const { zeilen, tiefe } = baueHonestlyZeilen([person()], maps, standorte); + const zeile = Object.fromEntries(honestlySpalten(tiefe).map((s) => [s.header, s.get(zeilen[0])])); + expect(zeile.Email).toBe(""); + }); + + it("trägt die private Adresse in keine Spalte ein", () => { + // Nicht nur „Email" prüfen: rutschte sie in eine andere Spalte, fiele es + // dort erst in Honestly auf. + const { zeilen, tiefe } = baueHonestlyZeilen([person()], maps, standorte); + const csv = toCsv(zeilen, honestlySpalten(tiefe)); + expect(csv).not.toContain("anna.privat@example.test"); + }); + + it("behält die Spalte Email, auch solange sie leer ist", () => { + // Die Zuordnung in Honestly wird einmal eingerichtet. Kommt die + // Firmenadresse später dazu, soll sich an der Datei nur der Inhalt ändern. + expect(honestlySpalten(1).map((s) => s.header)).toContain("Email"); }); it("gibt Personen ohne Einheit eine leere Kette, aber eine Zeile", () => {