diff --git a/components/employees/EmployeeDetail.tsx b/components/employees/EmployeeDetail.tsx index 94fecd6..2f2f76e 100644 --- a/components/employees/EmployeeDetail.tsx +++ b/components/employees/EmployeeDetail.tsx @@ -217,20 +217,44 @@ export function EmployeeDetail(props: EmployeeDetailProps) { {tab === "HR-Notizen" && } + {/* Der `key` an jedem Panel ist kein Feinschliff, sondern der Unterschied + zwischen „zeigt Altes" und „schreibt Altes zurück". + + Die Panels bleiben eingebunden, damit ihr Ein- und Ausfahren laufen + kann. Sie belegen ihre Felder aber mit useState(employee.…) vor, und + das läuft nur beim ersten Aufbau. Nach einer Beförderung bringt + router.refresh() zwar die frische Akte herein — der Zustand im Panel + bleibt der von vorhin. Beim nächsten Speichern geht er als Ganzes an + change_employee_data, und der eben gesetzte Hay-Grade steht wieder + auf dem alten Wert. Gemeldet im Test vom 29.09. (H.05). + + employees.updated_at wechselt bei jeder Änderung an der Zeile + (Trigger trg_employees_touch_updated_at), also genau dann, wenn die + Vorbelegung neu zu lesen ist — und sonst nie. Der Wiedereintritts- + Assistent darunter macht es seit jeher so. */} setPanel(null)} employee={employee} openPositions={openPositions} /> setPanel(null)} employee={employee} openPositions={openPositions} /> - setPanel(null)} employee={employee} status={status} /> + setPanel(null)} + employee={employee} + status={status} + /> setPanel(null)} employee={employee} @@ -238,6 +262,7 @@ export function EmployeeDetail(props: EmployeeDetailProps) { locationCountry={location?.country} /> setPanel(null)} employee={employee} diff --git a/db/migrations/20260929160000_wiedereintritt_status_cast.sql b/db/migrations/20260929160000_wiedereintritt_status_cast.sql new file mode 100644 index 0000000..3431f24 --- /dev/null +++ b/db/migrations/20260929160000_wiedereintritt_status_cast.sql @@ -0,0 +1,103 @@ +-- Wiedereintritt: der Umwandlungsschritt beim Status, zum zweiten Mal +-- +-- rehire_employee scheitert bei jedem Aufruf mit +-- +-- column "status" is of type employment_status but expression is of type text +-- +-- Der case-Ausdruck liefert `text` (beide Zweige sind Literale ohne Typ), die +-- Spalte ist ein Aufzählungstyp, und Postgres wandelt beim Zuweisen nicht von +-- selbst um. Genau dieser Fehler wurde am 10.08. mit +-- 20260810130000_fix_rehire_status_cast.sql behoben. +-- +-- ═══ Warum er wieder da ist ═══════════════════════════════════════ +-- +-- Vier spätere Migrationen haben rehire_employee neu erzeugt und dabei den +-- Zusatz nicht mitgenommen: 20260917100000 (Austrittsart), 20260917130000 +-- (Wiedereintritt mit Stammdaten), 20260923120000 (Firmen-E-Mail) und +-- 20260928100000 (Cornerstone-ID). +-- +-- Die ersten beiden haben den Rumpf aus einer älteren Datei kopiert — der +-- Fall, vor dem der Abschnitt „create or replace aus veraltetem Muster" warnt. +-- Die letzten beiden sind aus der **laufenden** Definition erzeugt worden und +-- haben damit getreu weitergetragen, was seit dem 17.09. dort stand. Daraus +-- die Lehre, die vorher nicht dastand: das Erzeugen aus dem laufenden Stand +-- schützt davor, Verhalten zu **verlieren** — nicht davor, einen bereits +-- vorhandenen Fehler **mitzunehmen**. Dagegen hilft nur eine Selbstprüfung, +-- die das Erwartete benennt, statt nur das Neue zu prüfen. +-- +-- Deshalb steht unten nicht bloss „der Zusatz ist da", sondern eine Prüfung, +-- die jede künftige Neuerzeugung dieser Funktion mitnehmen kann. + +do $migration$ +declare + v_alt constant text := $anker$status = case when v_date <= current_date then 'Aktiv' else 'Geplant' end,$anker$; + v_neu constant text := $anker$status = (case when v_date <= current_date then 'Aktiv' else 'Geplant' end)::employment_status,$anker$; + v_def text; + v_anzahl int; +begin + select pg_get_functiondef(p.oid) into v_def + from pg_proc p join pg_namespace n on n.oid = p.pronamespace + where n.nspname = 'public' and p.proname = 'rehire_employee' and p.prokind = 'f'; + + if v_def is null then + raise exception 'rehire_employee ist nicht vorhanden.'; + end if; + + -- Schon in Ordnung? Dann nichts tun. Die Migration soll auch auf einer + -- Datenbank durchlaufen, auf der die Funktion aus einer künftigen Datei mit + -- Umwandlung entstanden ist. + if v_def like '%end)::employment_status%' then + raise notice 'rehire_employee wandelt den Status bereits um.'; + return; + end if; + + v_anzahl := (length(v_def) - length(replace(v_def, v_alt, ''))) / length(v_alt); + if v_anzahl <> 1 then + raise exception 'Die Statuszuweisung kommt % mal vor, erwartet genau einmal.', v_anzahl; + end if; + + execute replace(v_def, v_alt, v_neu); +end +$migration$; + + +-- Selbstprüfung. +-- +-- Geprüft wird die Umwandlung **und** alles, was an dieser Funktion schon +-- einmal verlorengegangen ist. Wer sie das nächste Mal neu erzeugt, kopiert +-- diesen Block am besten mit. +do $$ +declare + v_def text; +begin + select pg_get_functiondef(p.oid) into v_def + from pg_proc p join pg_namespace n on n.oid = p.pronamespace + where n.nspname = 'public' and p.proname = 'rehire_employee' and p.prokind = 'f'; + + if v_def not like '%end)::employment_status%' then + raise exception 'rehire_employee wandelt den Status nicht um — der Wiedereintritt scheitert bei jedem Aufruf.'; + end if; + if v_def not like '%require_hr_admin()%' then + raise exception 'rehire_employee prueft die Rechte nicht.'; + end if; + if v_def not like '%search_path%' then + raise exception 'rehire_employee hat keinen festen search_path.'; + end if; + -- Die Stammdaten, die der Wiedereintritt seit 20260917130000 mitschreibt. + -- Ohne sie zeigt der Assistent Felder an und wirft ihre Werte weg. + if v_def not like '%cornerstone_id%' then + raise exception 'rehire_employee hat die Cornerstone-ID verloren.'; + end if; + if v_def not like '%company_email%' then + raise exception 'rehire_employee hat die Firmen-E-Mail verloren.'; + end if; + if v_def not like '%title_prefix%' then + raise exception 'rehire_employee hat die Titel verloren.'; + end if; + if v_def not like '%paygrade%' then + raise exception 'rehire_employee hat den Hay-Grade verloren.'; + end if; + + raise notice 'rehire_employee: Statusumwandlung und Stammdaten vollstaendig.'; +end +$$;