Kuendigungsschutz bekommt einen Personenkreis, die Behinderung eigene Felder
Anforderungen 5 und 5a aus dem Workshop. Migration 20260915120000.
Bisher gab es ein Kennzeichen und ein Enddatum. Das beantwortet "darf hier
ohne Weiteres beendet werden?" — nicht aber, *warum* jemand geschuetzt ist,
und davon haengt ab, wer zustimmen muss. Nachzusehen war das nur im
Papierakt, also dort, wo unter Zeitdruck niemand nachsieht.
Zwoelf Personenkreise als CHECK auf text und nicht als Aufzaehlungstyp: die
Liste ist Rechtslage und aendert sich mit dem Gesetz, ein Typ liesse einen
zurueckgenommenen Wert fuer immer stehen. Die Oberflaeche liest dieselbe
Liste aus lib/kuendigungsschutz.ts; ein Test liest die Migration und haelt
beide gegeneinander, damit die begruendete Doppelung keine stille wird.
Die begueenstigte Behinderung bekommt Kennzeichen, Grad, Beginn und Ende —
vier Spalten und nicht eine zusammengesetzte, weil in Excel danach
gefiltert und summiert wird. Datenbankseitig sind sie *nicht* an den
Personenkreis gekettet: eine solche Bedingung scheiterte genau dann, wenn
jemand den Kreis korrigiert und der Grad noch dransteht. Die Oberflaeche
stellt den Zusammenhang her.
Dazu zwei Dinge, die auf dem Weg auffielen:
* Der Nachtlauf wendete bei einer auf spaeter datierten Aenderung nur
Person und Vertrag an — die ganze Gruppe "role" fiel weg. Betriebsrat,
Dienstwagen, Kollektivvertrag, Arbeitstage, Teilzeit und
Kuendigungsschutz wurden erfasst, in der Historie vermerkt, protokolliert
und am Stichtag nicht geschrieben. Sichtbar wurde das nie. Die neuen
Felder haetten den Fehler geerbt; er ist jetzt fuer alle behoben.
* Der Mitarbeiter-Export filterte ohne Stichtag ueber die Spalte `status`,
mit Stichtag ueber die Ableitung. Der Export nach "Ausgetreten" liess
damit genau die Leute aus, die gerade ausgetreten sind.
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { SelectField, TextField } from "@/components/ui/Field";
|
||||
import {
|
||||
BEGUENSTIGUNG_AB_GRAD,
|
||||
GRUND_BEGUENSTIGT_BEHINDERT,
|
||||
KUENDIGUNGSSCHUTZ_GRUENDE,
|
||||
} from "@/lib/kuendigungsschutz";
|
||||
import type { CollectiveAgreement, DienstwagenArt, Weekday, WorkerType } from "@/lib/types";
|
||||
|
||||
const WEEKDAYS: Weekday[] = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"];
|
||||
@@ -30,6 +35,25 @@ export type RoleEmploymentValue = {
|
||||
* einer erfundenen Zahl. Leer heisst „bis auf Weiteres".
|
||||
*/
|
||||
kuendigungsschutzBis: string;
|
||||
/**
|
||||
* Der Personenkreis — freiwillig, aus demselben Grund wie das Enddatum:
|
||||
* der Bestand trägt das Kennzeichen seit 20260814120000 ohne Grund, und ein
|
||||
* Pflichtfeld hätte jede Änderung an diesen Zeilen blockiert.
|
||||
*/
|
||||
kuendigungsschutzGrund: string;
|
||||
/** Beginn des Schutzes — ebenfalls freiwillig. */
|
||||
kuendigungsschutzAb: string;
|
||||
/**
|
||||
* Begünstigte Behinderung. Eigenes Kennzeichen und nicht aus dem
|
||||
* Personenkreis abgeleitet: die Begünstigung besteht unabhängig davon, ob
|
||||
* sie als Kündigungsschutz geführt wird. Die Oberfläche stellt den
|
||||
* Zusammenhang her, die Datenbank koppelt die beiden nicht.
|
||||
*/
|
||||
istBeguenstigtBehindert: boolean;
|
||||
/** Grad in Prozent laut Bescheid. Als Text, weil ein leeres Zahlenfeld sonst 0 wäre. */
|
||||
behinderungGrad: string;
|
||||
behinderungAb: string;
|
||||
behinderungBis: string;
|
||||
};
|
||||
|
||||
// Shared by the hire wizard (StepVertrag) and DatenAendernPanel — both edit
|
||||
@@ -134,14 +158,79 @@ export function RoleEmploymentFields({ value, onChange }: { value: RoleEmploymen
|
||||
gibt. Anders als dort aber freiwillig — leer heisst „bis auf
|
||||
Weiteres", nicht „vergessen". */}
|
||||
{value.hasKuendigungsschutz && (
|
||||
<TextField
|
||||
label="Geschützt bis"
|
||||
dense
|
||||
type="date"
|
||||
value={value.kuendigungsschutzBis}
|
||||
onChange={(v) => onChange({ kuendigungsschutzBis: v })}
|
||||
hint="Optional. Leer lassen, solange das Ende nicht feststeht."
|
||||
<>
|
||||
<SelectField
|
||||
label="Personenkreis"
|
||||
dense
|
||||
value={value.kuendigungsschutzGrund}
|
||||
onChange={(v) => onChange({ kuendigungsschutzGrund: v })}
|
||||
options={[
|
||||
{ value: "", label: "Nicht erfasst" },
|
||||
...KUENDIGUNGSSCHUTZ_GRUENDE.map((g) => ({ value: g, label: g })),
|
||||
]}
|
||||
hint="Bestimmt, wer einer Beendigung zustimmen muss."
|
||||
/>
|
||||
<TextField
|
||||
label="Geschützt ab"
|
||||
dense
|
||||
type="date"
|
||||
value={value.kuendigungsschutzAb}
|
||||
onChange={(v) => onChange({ kuendigungsschutzAb: v })}
|
||||
hint="Optional."
|
||||
/>
|
||||
<TextField
|
||||
label="Geschützt bis"
|
||||
dense
|
||||
type="date"
|
||||
value={value.kuendigungsschutzBis}
|
||||
onChange={(v) => onChange({ kuendigungsschutzBis: v })}
|
||||
hint="Optional. Leer lassen, solange das Ende nicht feststeht."
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* ── Begünstigte Behinderung ──────────────────────────────────
|
||||
Eigener Block und nicht innerhalb des Kündigungsschutzes: die
|
||||
Begünstigung besteht für sich, auch wenn niemand sie als Schutz
|
||||
führt. Der Haken setzt sich mit, wenn der Personenkreis gewählt
|
||||
wird — das ist eine Hilfe der Oberfläche, keine Bedingung der
|
||||
Datenbank, und er lässt sich danach wieder abwählen. */}
|
||||
<div className="grid grid-cols-1 items-end gap-3 sm:grid-cols-2">
|
||||
<label className="flex items-center gap-2 text-sm text-ink">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={value.istBeguenstigtBehindert || value.kuendigungsschutzGrund === GRUND_BEGUENSTIGT_BEHINDERT}
|
||||
onChange={(e) => onChange({ istBeguenstigtBehindert: e.target.checked })}
|
||||
/>
|
||||
Begünstigt behindert
|
||||
</label>
|
||||
{(value.istBeguenstigtBehindert || value.kuendigungsschutzGrund === GRUND_BEGUENSTIGT_BEHINDERT) && (
|
||||
<>
|
||||
<TextField
|
||||
label="Grad der Behinderung"
|
||||
dense
|
||||
type="number"
|
||||
value={value.behinderungGrad}
|
||||
onChange={(v) => onChange({ behinderungGrad: v })}
|
||||
hint={`In Prozent laut Bescheid. Die Begünstigung beginnt bei ${BEGUENSTIGUNG_AB_GRAD}%.`}
|
||||
/>
|
||||
<TextField
|
||||
label="Bescheid ab"
|
||||
dense
|
||||
type="date"
|
||||
value={value.behinderungAb}
|
||||
onChange={(v) => onChange({ behinderungAb: v })}
|
||||
/>
|
||||
<TextField
|
||||
label="Bescheid bis"
|
||||
dense
|
||||
type="date"
|
||||
value={value.behinderungBis}
|
||||
onChange={(v) => onChange({ behinderungBis: v })}
|
||||
hint="Leer heisst unbefristet."
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,6 +14,7 @@ import { SlideOver } from "@/components/ui/SlideOver";
|
||||
import { useToast } from "@/components/ui/Toast";
|
||||
import { brauchtAufenthaltstitel, UN_COUNTRIES } from "@/lib/countries";
|
||||
import { STUNDEN_GRUENDE } from "@/lib/absence";
|
||||
import { GRUND_BEGUENSTIGT_BEHINDERT } from "@/lib/kuendigungsschutz";
|
||||
import { fmtFullName, todayIso } from "@/lib/format";
|
||||
import { isValidSvnr, requiresAustrianSvnr } from "@/lib/svnr";
|
||||
import { EMERGENCY_RELATIONS, type ContractType, type Database, type EmploymentType, type GenderType } from "@/lib/types";
|
||||
@@ -86,6 +87,14 @@ export function DatenAendernPanel({
|
||||
hasDienstwagen: employee.has_dienstwagen ?? false,
|
||||
hasKuendigungsschutz: employee.has_kuendigungsschutz ?? false,
|
||||
kuendigungsschutzBis: employee.kuendigungsschutz_bis ?? "",
|
||||
kuendigungsschutzGrund: employee.kuendigungsschutz_grund ?? "",
|
||||
kuendigungsschutzAb: employee.kuendigungsschutz_ab ?? "",
|
||||
istBeguenstigtBehindert: employee.ist_beguenstigt_behindert ?? false,
|
||||
// Als Text und nicht als Zahl: ein leeres Zahlenfeld wäre 0, und 0
|
||||
// bedeutet hier „kein Bescheid", nicht „Grad null".
|
||||
behinderungGrad: employee.behinderung_grad === null ? "" : String(employee.behinderung_grad),
|
||||
behinderungAb: employee.behinderung_ab ?? "",
|
||||
behinderungBis: employee.behinderung_bis ?? "",
|
||||
dienstwagenArt: employee.dienstwagen_art ?? "Verbrenner",
|
||||
isLateraleFuehrung: employee.is_laterale_fuehrung ?? false,
|
||||
isCLevel: employee.is_c_level ?? false,
|
||||
@@ -93,6 +102,10 @@ export function DatenAendernPanel({
|
||||
function updateRole(patch: Partial<RoleEmploymentValue>) {
|
||||
setRole((prev) => ({ ...prev, ...patch }));
|
||||
}
|
||||
// Dieselbe Regel wie in RoleEmploymentFields: der Personenkreis zieht das
|
||||
// Kennzeichen mit. Hier noch einmal, weil nicht das Formular speichert,
|
||||
// sondern diese Seite — und was gezeigt wird, muss auch abgeschickt werden.
|
||||
const istBehindert = role.istBeguenstigtBehindert || role.kuendigungsschutzGrund === GRUND_BEGUENSTIGT_BEHINDERT;
|
||||
|
||||
function handleEmploymentTypeChange(value: EmploymentType) {
|
||||
setEmploymentType(value);
|
||||
@@ -165,7 +178,16 @@ export function DatenAendernPanel({
|
||||
has_dienstwagen: role.hasDienstwagen,
|
||||
dienstwagen_art: role.hasDienstwagen ? role.dienstwagenArt : "",
|
||||
has_kuendigungsschutz: role.hasKuendigungsschutz,
|
||||
// Leer statt des Wertes, wenn das Kennzeichen weg ist: die Bedingung
|
||||
// in der Datenbank duldet keinen Rest ohne Bezug, und die Funktion
|
||||
// räumt ihn auf demselben Weg weg wie beim Dienstwagen.
|
||||
kuendigungsschutz_bis: role.hasKuendigungsschutz ? role.kuendigungsschutzBis : "",
|
||||
kuendigungsschutz_grund: role.hasKuendigungsschutz ? role.kuendigungsschutzGrund : "",
|
||||
kuendigungsschutz_ab: role.hasKuendigungsschutz ? role.kuendigungsschutzAb : "",
|
||||
ist_beguenstigt_behindert: istBehindert,
|
||||
behinderung_grad: istBehindert ? role.behinderungGrad : "",
|
||||
behinderung_ab: istBehindert ? role.behinderungAb : "",
|
||||
behinderung_bis: istBehindert ? role.behinderungBis : "",
|
||||
// Die Teilzeitvariante wird nur mitgeschickt, wenn sich die Stunden
|
||||
// tatsächlich ändern. Sonst schriebe jede Adressänderung den Wert
|
||||
// erneut — und setzte ihn bei „Vertragliche Stundenänderung" sogar
|
||||
|
||||
Reference in New Issue
Block a user