User ID and Username carry the Alpenwerk UUID
All checks were successful
CI / Lint, Typen, Tests, Build (push) Successful in 11m2s
CI / Migrationen auf leerer Datenbank (push) Successful in 10m6s

Both columns now hold employees.id, and they hold the same value: in
Alpenwerk the user name and the user id never diverge. If they did,
Cornerstone would show two identities for one person and every
reference to them -- manager, reports -- could hit the wrong one.

The UUID rather than the personnel number, because it is the identifier
that never changes. A personnel number can be corrected, and the person
would then be somebody else in Cornerstone.

Local System ID keeps the personnel number as LOGA assigns it, which is
what that column is for. Customfield ID AD keeps the directory account
name (vorname.nachname); it is a separate thing from the Cornerstone
user name and always was.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-27 20:25:41 +02:00
parent 410acfe01f
commit 6717412c9f
2 changed files with 60 additions and 10 deletions

View File

@@ -99,10 +99,13 @@ export function csDatum(iso: string | null | undefined): string {
}
/**
* Der Anmeldename: vorname.nachname, klein, ohne Umlaute und Leerzeichen.
* Der Konto­name im Verzeichnisdienst: vorname.nachname, klein, ohne Umlaute.
*
* Nur für das Customfield AD. Der **Username** in Cornerstone ist etwas
* anderes: er ist die UUID aus Alpenwerk, dieselbe wie die User ID.
*
* Abgeleitet und nicht aus der dienstlichen Adresse geschnitten: die Adresse
* ist freiwillig, der Name ist es nicht. Cornerstone braucht das Feld.
* ist freiwillig, der Name ist es nicht.
*/
export function benutzername(vorname: string, nachname: string): string {
const sauber = (s: string) =>
@@ -182,21 +185,36 @@ export type CornerstoneKontext = {
/** Eine Zeile — die Zuordnung selbst, ohne Datenbank und ohne Dateiformat. */
export function baueCornerstoneZeile(p: CornerstoneQuelle, k: CornerstoneKontext): CornerstoneZeile {
const nummer = p.personnel_number;
const name = benutzername(p.first_name, p.last_name);
// Zwei Kennungen, zwei Herkünfte:
//
// User ID + Username die UUID aus Alpenwerk (employees.id)
// Local System ID die Personalnummer, wie LOGA sie vergibt
//
// Benutzername und Benutzer-ID sind in Alpenwerk stets derselbe Wert —
// liefen sie auseinander, zeigte Cornerstone zwei Kennungen für eine
// Person, und jeder Verweis darauf träfe womöglich die falsche.
//
// Die UUID und nicht die Personalnummer, weil sie die Kennung ist, die
// sich nie ändert: eine Personalnummer kann berichtigt werden, und dann
// wäre die Person in Cornerstone eine andere.
//
// Der Anmeldename des Verzeichnisdienstes steht nur im Customfield AD.
const kennung = p.id;
const nummer = String(p.personnel_number);
const adName = benutzername(p.first_name, p.last_name);
const kst = p.position_id ? k.kostenstelle.get(p.position_id) : undefined;
const chef = p.manager_id ? k.managerNummer.get(p.manager_id) : undefined;
const ausgetreten = p.status === "Ausgetreten";
return {
"User ID": String(nummer),
"Local System ID": String(nummer),
"User ID": kennung,
"Local System ID": nummer,
Prefix: p.title_prefix.join(" "),
"First Name": p.first_name,
"Middle Name": "",
"Last Name": p.last_name,
Suffix: p.title_suffix.join(" "),
Username: name,
Username: kennung,
Approver: "",
Manager: chef ? String(chef) : "",
Absent: "",
@@ -261,7 +279,7 @@ export function baueCornerstoneZeile(p: CornerstoneQuelle, k: CornerstoneKontext
// Kopfzeile, weil die Vorlage sie führt.
"Retention Rules": "",
Organisationsstufe: "",
"Customfield ID AD": name,
"Customfield ID AD": adName,
"Customfield ID Doxis": `${DOXIS_PRAEFIX}${nummer}`,
"Customfield ID Interflex": String(nummer),
"Customfield ID LGVplus": `${LGV_PRAEFIX}${nummer}`,