Im Feld Manager stand die Personalnummer der vorgesetzten Person -- also der Wert, der in derselben Zeile als Local System ID gefuehrt wird. Cornerstone verknuepft aber ueber die User ID. Der Verweis lief damit entweder ins Leere oder, schlimmer, auf jemand anderen, dessen User ID zufaellig aussieht wie eine Personalnummer. Leer, wenn die vorgesetzte Person selbst keine Cornerstone-ID traegt. Aus demselben Grund wie bei User ID und Username: eine Kennung der falschen Art ist schlimmer als keine, weil niemand ihr ansieht, dass sie falsch ist. Bei 435 von 785 Personen fehlt die Kennung noch -- das ist eine Luecke in der Zuordnungstabelle, kein Fehler im Export. Die Abbildung im Kontext heisst entsprechend managerKennung und traegt jetzt Zeichenketten, damit der Typ selbst keine Nummer mehr zulaesst.
47 lines
2.2 KiB
TypeScript
47 lines
2.2 KiB
TypeScript
import { NextResponse, type NextRequest } from "next/server";
|
|
import { baueCornerstoneZeile, CORNERSTONE_CSV, cornerstoneSpalten, type CornerstoneKontext } from "@/lib/cornerstone";
|
|
import { loadKontierungen } from "@/lib/cost-centers";
|
|
import { exportFilename, exportResponseHeaders, toCsv, toXlsx } from "@/lib/export";
|
|
import { exportParameter, ladeExportMitarbeiter } from "@/lib/export-auswahl";
|
|
import { todayIso } from "@/lib/format";
|
|
import { requireHrUser } from "@/lib/auth/require-hr";
|
|
import { withUser } from "@/lib/db";
|
|
|
|
// Der Export für Cornerstone — Spalten und Zuordnung stehen in
|
|
// lib/cornerstone.ts.
|
|
//
|
|
// Dieselben Personen wie im vollständigen Export daneben, mit denselben
|
|
// Filtern (lib/export-auswahl.ts). Wer nur die Aktiven einspielen will,
|
|
// stellt das auf der Berichtsseite ein, bevor er exportiert.
|
|
export async function GET(request: NextRequest) {
|
|
const gate = await requireHrUser();
|
|
if ("denied" in gate) return gate.denied;
|
|
|
|
const { format, asOf, filters } = exportParameter(request.nextUrl.searchParams);
|
|
const stichtag = asOf ?? todayIso();
|
|
|
|
const { zeilen } = await withUser(gate.userId, async (tx) => {
|
|
const { rows, managerKennung } = await ladeExportMitarbeiter(tx, { asOf, filters });
|
|
|
|
// Die eine Angabe, die die gemeinsame Auswahl nicht mitbringt: die
|
|
// Kostenstelle hängt an der Planstelle, nicht an der Person. Erst jetzt,
|
|
// weil erst jetzt feststeht, um welche Planstellen es geht.
|
|
const positionIds = [...new Set(rows.map((r) => r.position_id).filter((id): id is string => Boolean(id)))];
|
|
const kontext: CornerstoneKontext = {
|
|
managerKennung,
|
|
kostenstelle: await loadKontierungen(tx, { asOf: stichtag, positionIds }),
|
|
};
|
|
|
|
return { zeilen: rows.map((r) => baueCornerstoneZeile(r, kontext)) };
|
|
});
|
|
|
|
const filename = exportFilename("cornerstone-export", format);
|
|
// Form und Spalten kommen beide aus lib/cornerstone.ts — siehe dort.
|
|
const body =
|
|
format === "xlsx"
|
|
? await toXlsx(zeilen, cornerstoneSpalten(), "Worksheet")
|
|
: toCsv(zeilen, cornerstoneSpalten(), CORNERSTONE_CSV);
|
|
// Derselbe Umweg über Blob wie in den anderen Exporten (TS#59417).
|
|
return new NextResponse(new Blob([body as BlobPart]), { headers: exportResponseHeaders(filename, format) });
|
|
}
|