Files
alpenwerk-hr/lib/wiedereintritt.ts
Andrei Laas c3e19606e2
All checks were successful
CI / Lint, Typen, Tests, Build (push) Successful in 11m58s
CI / Migrationen auf leerer Datenbank (push) Successful in 10m24s
Die Cornerstone-ID als eigenes, freiwilliges Feld
Cornerstone fuehrt jede Person unter einer eigenen Kennung. Der Export
dorthin trug in "User ID" und "Username" bisher die Alpenwerk-UUID --
richtig, solange es nichts Besseres gab, aber nicht die Kennung, unter
der Cornerstone die Person kennt. Jetzt steht dort diese Spalte.

Freiwillig, weil die Zuordnungstabelle des Kunden fuer 434 der 784
Personen keine Kennung liefert. Eindeutig, weil eine Kennung genau einer
Person gehoert. Als Text, weil fuehrende Nullen in einer numerischen
Spalte verlorengingen.

Ohne hinterlegte Kennung bleiben User ID und Username **leer**. Ein
Rueckfall auf die UUID braechte zwei Kennungsarten in eine Datei, ohne
dass es auffiele, und legte in Cornerstone eine zweite Person neben der
bestehenden an. Eine fehlende Angabe soll fehlen; dafuer gibt es einen
eigenen Test.

Fuenf Funktionen mussten mit -- dieselbe Liste und derselbe Grund wie bei
der Firmen-E-Mail: hire_employee und rehire_employee teilen sich den
Schritt "Person", change_employee_data macht das Feld aenderbar,
apply_due_pending_changes sorgt dafuer, dass eine datierte Aenderung
nicht verfaellt, app_feld_karte haelt den Eintrag in der Historie
richtigstellbar. Die Migration ist wieder erzeugt, nicht abgeschrieben,
und prueft jede der fuenf einzeln.

Erfasst wird das Feld in der Akte, in "Daten aendern", bei Einstellung
und Wiedereintritt sowie ueber den Massenimport; es steht im
Mitarbeiterexport und fuellt im Cornerstone-Export User ID und Username.
2026-09-28 10:13:52 +02:00

97 lines
4.9 KiB
TypeScript

import type { HireDraftData } from "@/components/hire/types";
import { MITARBEITERART_STANDARD } from "./mitarbeiterart";
import type { Database } from "./types";
type EmployeeRow = Database["public"]["Tables"]["employees"]["Row"];
// Eine bestehende Person als Vorbelegung für den Wiedereintritt.
//
// Der Kunde wollte für die Wiedereinstellung denselben Assistenten wie für
// eine Neueinstellung, „bereits mit den hier festgelegten Daten
// prepopulated". Diese Abbildung ist genau das: die Zeile der Person in die
// Form, die der Assistent führt.
//
// ── Warum genau die Felder des Assistenten und keines mehr ──────────
//
// Der Rückgabetyp ist `Partial<HireDraftData>` und nicht ein eigener. Damit
// lässt sich hier nur eintragen, was der Assistent auch zeigt — und das ist
// die Bedingung dafür, dass er nichts verschickt, was niemand gesehen hat.
//
// Konkret fehlen Anschrift, Staatsbürgerschaft und Aufenthaltstitel: der
// Assistent fragt sie auch bei einer Neueinstellung nicht (sie werden später
// über „Daten ändern" gepflegt). `rehire_employee` lässt jedes nicht
// übermittelte Feld unangetastet stehen, sie bleiben also, wie sie sind.
//
// ── Was bewusst NICHT übernommen wird ───────────────────────────────
//
// * **Die Planstelle.** Sie ist beim Wiedereintritt immer neu zu wählen:
// die alte kann besetzt, ausgelaufen oder ganz entfallen sein. Ein
// vorbelegter Platz, den es so nicht mehr gibt, wäre schlimmer als ein
// leeres Feld — er sieht nach einer Antwort aus.
// * **Das Eintrittsdatum.** Der alte Eintritt ist Geschichte; das neue
// Datum ist die eigentliche Angabe dieses Vorgangs.
// * **Der Austritt.** Datum, Grund und Austrittsart räumt
// `rehire_employee` weg.
// * **Die Angehörigen.** Sie stehen schon in der Akte; der Assistent würde
// sie ein zweites Mal anlegen.
//
// Die Personalnummer kommt mit, aber nur zur Anzeige: es ist dieselbe Person,
// und `rehire_employee` fasst die Spalte nicht an.
export function vorbelegungAus(employee: EmployeeRow): Partial<HireDraftData> {
return {
personnelNumber: String(employee.personnel_number),
firstName: employee.first_name,
lastName: employee.last_name,
titlePrefix: employee.title_prefix ?? [],
titleSuffix: employee.title_suffix ?? [],
gender: employee.gender,
birthDate: employee.birth_date,
svNummer: employee.sv_nummer ?? "",
email: employee.email ?? "",
// Vorbelegt wie die private Adresse, obwohl eine Dienstadresse beim
// Austritt meist abgedreht wird: der Assistent schickt das Feld in jedem
// Fall mit, und leer geliefert löschte es die gespeicherte Adresse
// stillschweigend. Sichtbar vorbelegt lässt sie sich bewusst ersetzen
// oder leeren.
companyEmail: employee.company_email ?? "",
// Aus demselben Grund vorbelegt wie die Firmenadresse: der Assistent
// schickt das Feld in jedem Fall mit, und leer geliefert löschte es die
// gespeicherte Kennung stillschweigend.
cornerstoneId: employee.cornerstone_id ?? "",
phone: employee.phone ?? "",
locationId: employee.location_id,
besetzung: employee.source,
contractType: employee.contract_type,
contractEndDate: employee.contract_end_date ?? "",
employmentType: employee.employment_type,
// Als Text, weil das Feld im Assistenten eines ist: ein leeres Zahlenfeld
// landete sonst als 0 im Entwurf.
weeklyHours: String(employee.weekly_hours),
paygrade: employee.paygrade,
workerType: employee.worker_type,
mitarbeiterart: employee.mitarbeiterart ?? MITARBEITERART_STANDARD,
collectiveAgreement: employee.collective_agreement,
workDays: employee.work_days,
isBetriebsrat: employee.is_betriebsrat,
hasDienstwagen: employee.has_dienstwagen,
// Die Antriebsart steht auf null, sobald kein Wagen da ist. Der Assistent
// führt sie trotzdem mit, damit sie beim Anhaken wieder da ist —
// „Verbrenner" ist dabei die Vorgabe, nicht eine Behauptung.
dienstwagenArt: employee.dienstwagen_art ?? "Verbrenner",
isLateraleFuehrung: employee.is_laterale_fuehrung,
isCLevel: employee.is_c_level,
emergencyContactName: employee.emergency_contact_name ?? "",
emergencyContactPhone: employee.emergency_contact_phone ?? "",
emergencyContactRelation: employee.emergency_contact_relation ?? "",
hasKuendigungsschutz: employee.has_kuendigungsschutz,
kuendigungsschutzGrund: employee.kuendigungsschutz_grund ?? "",
kuendigungsschutzAb: employee.kuendigungsschutz_ab ?? "",
kuendigungsschutzBis: employee.kuendigungsschutz_bis ?? "",
istBeguenstigtBehindert: employee.ist_beguenstigt_behindert,
behinderungGrad: employee.behinderung_grad === null ? "" : String(employee.behinderung_grad),
behinderungAb: employee.behinderung_ab ?? "",
behinderungBis: employee.behinderung_bis ?? "",
};
}