Angehoerige berichtigen, und beide Abschnitte sehen gleich aus
Angehoerige liessen sich bisher nur anlegen und entfernen. Ein Tippfehler im Namen war nur zu beheben, indem man die Person loeschte und neu anlegte -- zwei Eintraege in der Akte fuer eine Korrektur, und der erste sagte "entfernt", was nicht stimmte. Jetzt steht in jeder Zeile ein Stift, wie beim Notfallkontakt. update_employee_dependent kommt bewusst **ohne** Stichtag. Hinzufuegen und Entfernen tragen einen, dort passiert etwas zu einem Zeitpunkt. Eine Berichtigung nicht: der Wert war schon vorher falsch, und ein "wirksam ab" hiesse, die Person habe bis dahin anders geheissen. Der Eintrag in der Akte nennt deshalb Vorher und Nachher statt eines Datums. In "Daten aendern" standen fuer den Notfallkontakt drei Eingabefelder, waehrend die Angehoerigen darueber als Tabelle mit Knoepfen erscheinen -- zwei Bauformen fuer denselben Zweck, direkt untereinander. Dort steht jetzt derselbe Abschnitt wie im Reiter "Stammdaten"; beide laufen ueber das "Wirksam ab" des Formulars, wie die Angehoerigen es schon taten. Damit schreibt auch nur noch eine Stelle diese drei Spalten. Vorher schickte das Formular sie zusaetzlich im eigenen Aufruf mit.
This commit is contained in:
@@ -345,6 +345,25 @@ export async function addEmployeeDependent(payload: {
|
||||
return callRpc("add_employee_dependent", payload, [`/employees/${payload.employee_id}`]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Eine Angabe berichtigen — ohne Stichtag.
|
||||
*
|
||||
* Hinzufügen und Entfernen tragen einen: dort passiert etwas zu einem
|
||||
* Zeitpunkt. Eine Berichtigung nicht — der Wert war schon vorher falsch, und
|
||||
* ein „wirksam ab" hiesse, die Person habe bis dahin anders geheissen.
|
||||
*/
|
||||
export async function updateEmployeeDependent(payload: {
|
||||
dependent_id: string;
|
||||
employee_id: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
relationship: RelationshipType;
|
||||
sv_nummer?: string;
|
||||
birth_date: string;
|
||||
}): Promise<ActionResult> {
|
||||
return callRpc("update_employee_dependent", payload, [`/employees/${payload.employee_id}`]);
|
||||
}
|
||||
|
||||
export async function deleteEmployeeDependent(payload: {
|
||||
dependent_id: string;
|
||||
employee_id: string;
|
||||
|
||||
@@ -2,34 +2,48 @@
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { addEmployeeDependent } from "@/actions/employees";
|
||||
import { addEmployeeDependent, updateEmployeeDependent } from "@/actions/employees";
|
||||
import { Button } from "@/components/ui/Button";
|
||||
import { SelectField, TextField } from "@/components/ui/Field";
|
||||
import { Modal } from "@/components/ui/Modal";
|
||||
import { useToast } from "@/components/ui/Toast";
|
||||
import { todayIso } from "@/lib/format";
|
||||
import type { RelationshipType } from "@/lib/types";
|
||||
import type { Database, RelationshipType } from "@/lib/types";
|
||||
|
||||
const RELATIONSHIPS: RelationshipType[] = ["Ehepartner:in", "Lebenspartner:in", "Kind", "Sonstige"];
|
||||
|
||||
type Dependent = Database["public"]["Tables"]["employee_dependents"]["Row"];
|
||||
|
||||
// Dasselbe Fenster für Anlegen und Berichtigen.
|
||||
//
|
||||
// Der Unterschied ist nicht die Maske, sondern der Stichtag: beim Anlegen
|
||||
// passiert etwas zu einem Zeitpunkt, beim Berichtigen war die Angabe schon
|
||||
// vorher falsch. Deshalb steht „Wirksam ab" nur im ersten Fall — ein Datum
|
||||
// bei einer Korrektur hiesse, die Person habe bis dahin anders geheissen.
|
||||
export function AddDependentModal({
|
||||
open,
|
||||
onClose,
|
||||
employeeId,
|
||||
defaultEffectiveDate,
|
||||
dependent,
|
||||
}: {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
employeeId: string;
|
||||
defaultEffectiveDate?: string;
|
||||
/** Gesetzt: berichtigen statt anlegen. */
|
||||
dependent?: Dependent;
|
||||
}) {
|
||||
const { showToast } = useToast();
|
||||
const router = useRouter();
|
||||
const [firstName, setFirstName] = useState("");
|
||||
const [lastName, setLastName] = useState("");
|
||||
const [svNummer, setSvNummer] = useState("");
|
||||
const [birthDate, setBirthDate] = useState("");
|
||||
const [relationship, setRelationship] = useState<RelationshipType>("Kind");
|
||||
const bearbeiten = Boolean(dependent);
|
||||
const [firstName, setFirstName] = useState(dependent?.first_name ?? "");
|
||||
const [lastName, setLastName] = useState(dependent?.last_name ?? "");
|
||||
const [svNummer, setSvNummer] = useState(dependent?.sv_nummer ?? "");
|
||||
const [birthDate, setBirthDate] = useState(dependent?.birth_date ?? "");
|
||||
const [relationship, setRelationship] = useState<RelationshipType>(
|
||||
(dependent?.relationship as RelationshipType) ?? "Kind"
|
||||
);
|
||||
const [effectiveDate, setEffectiveDate] = useState(defaultEffectiveDate ?? todayIso());
|
||||
const [prevDefaultEffectiveDate, setPrevDefaultEffectiveDate] = useState(defaultEffectiveDate);
|
||||
const [pending, setPending] = useState(false);
|
||||
@@ -53,12 +67,22 @@ export function AddDependentModal({
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (!firstName || !lastName || !birthDate || !effectiveDate) {
|
||||
if (!firstName || !lastName || !birthDate || (!bearbeiten && !effectiveDate)) {
|
||||
showToast("Bitte alle Pflichtfelder ausfüllen.", "error");
|
||||
return;
|
||||
}
|
||||
setPending(true);
|
||||
const result = await addEmployeeDependent({
|
||||
const result = bearbeiten
|
||||
? await updateEmployeeDependent({
|
||||
dependent_id: dependent!.id,
|
||||
employee_id: employeeId,
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
relationship,
|
||||
sv_nummer: svNummer,
|
||||
birth_date: birthDate,
|
||||
})
|
||||
: await addEmployeeDependent({
|
||||
employee_id: employeeId,
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
@@ -69,10 +93,10 @@ export function AddDependentModal({
|
||||
});
|
||||
setPending(false);
|
||||
if (result.success) {
|
||||
showToast("Angehörige:r hinzugefügt.");
|
||||
showToast(bearbeiten ? "Angaben berichtigt." : "Angehörige:r hinzugefügt.");
|
||||
router.refresh();
|
||||
onClose();
|
||||
reset();
|
||||
if (!bearbeiten) reset();
|
||||
} else {
|
||||
showToast(result.error ?? "Fehler beim Speichern.", "error");
|
||||
}
|
||||
@@ -82,20 +106,22 @@ export function AddDependentModal({
|
||||
<Modal
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
title="Angehörige:n hinzufügen"
|
||||
title={bearbeiten ? "Angehörige:n berichtigen" : "Angehörige:n hinzufügen"}
|
||||
footer={
|
||||
<>
|
||||
<Button variant="ghost" onClick={onClose}>
|
||||
Abbrechen
|
||||
</Button>
|
||||
<Button onClick={handleSubmit} pending={pending}>
|
||||
Hinzufügen
|
||||
{bearbeiten ? "Speichern" : "Hinzufügen"}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-col gap-4">
|
||||
{!bearbeiten && (
|
||||
<TextField label="Wirksam ab" required type="date" value={effectiveDate} onChange={setEffectiveDate} />
|
||||
)}
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
||||
<TextField label="Vorname" required value={firstName} onChange={setFirstName} />
|
||||
<TextField label="Nachname" required value={lastName} onChange={setLastName} />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Plus, Trash2 } from "lucide-react";
|
||||
import { Pencil, Plus, Trash2 } from "lucide-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { deleteEmployeeDependent } from "@/actions/employees";
|
||||
@@ -19,6 +19,7 @@ export function AngehoerigeSection({ employeeId, dependents, effectiveDate }: {
|
||||
const { showToast } = useToast();
|
||||
const router = useRouter();
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [bearbeitet, setBearbeitet] = useState<Dependent | null>(null);
|
||||
const [deletingId, setDeletingId] = useState<string | null>(null);
|
||||
const resolvedEffectiveDate = effectiveDate || todayIso();
|
||||
|
||||
@@ -70,6 +71,18 @@ export function AngehoerigeSection({ employeeId, dependents, effectiveDate }: {
|
||||
<td className="px-4 py-2.5 text-ink-body">{d.sv_nummer ?? "–"}</td>
|
||||
<td className="px-4 py-2.5 text-ink-body">{fmtDate(d.birth_date)}</td>
|
||||
<td className="px-4 py-2.5 text-right">
|
||||
{/* Berichtigen statt löschen-und-neu-anlegen: ein
|
||||
Tippfehler hinterliess sonst zwei Einträge in der
|
||||
Akte, und der erste sagte „entfernt", was nicht
|
||||
stimmte. */}
|
||||
<Button
|
||||
variant="icon"
|
||||
onClick={() => setBearbeitet(d)}
|
||||
aria-label={`${d.first_name} ${d.last_name} berichtigen`}
|
||||
className="hover:!text-brand-700"
|
||||
>
|
||||
<Pencil className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="icon"
|
||||
onClick={() => handleDelete(d.id)}
|
||||
@@ -88,6 +101,19 @@ export function AngehoerigeSection({ employeeId, dependents, effectiveDate }: {
|
||||
)}
|
||||
|
||||
<AddDependentModal open={modalOpen} onClose={() => setModalOpen(false)} employeeId={employeeId} defaultEffectiveDate={resolvedEffectiveDate} />
|
||||
|
||||
{/* Eigene Einbindung mit `key`: das Fenster bleibt sonst montiert und
|
||||
zeigte beim zweiten Öffnen die Felder der zuvor bearbeiteten
|
||||
Person. */}
|
||||
{bearbeitet && (
|
||||
<AddDependentModal
|
||||
key={bearbeitet.id}
|
||||
open
|
||||
onClose={() => setBearbeitet(null)}
|
||||
employeeId={employeeId}
|
||||
dependent={bearbeitet}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -31,11 +31,14 @@ export function NotfallkontaktModal({
|
||||
onClose,
|
||||
employeeId,
|
||||
kontakt,
|
||||
effectiveDate,
|
||||
}: {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
employeeId: string;
|
||||
kontakt: Notfallkontakt;
|
||||
/** Aus „Daten ändern"; ohne Angabe gilt heute. */
|
||||
effectiveDate?: string;
|
||||
}) {
|
||||
const { showToast } = useToast();
|
||||
const router = useRouter();
|
||||
@@ -57,7 +60,7 @@ export function NotfallkontaktModal({
|
||||
setPending(true);
|
||||
const result = await changeEmployeeData({
|
||||
employee_id: employeeId,
|
||||
effective_date: todayIso(),
|
||||
effective_date: effectiveDate || todayIso(),
|
||||
person: {
|
||||
emergency_contact_name: name.trim(),
|
||||
emergency_contact_phone: telefon.trim(),
|
||||
|
||||
@@ -19,11 +19,25 @@ import { NotfallkontaktModal, type Notfallkontakt } from "./NotfallkontaktModal"
|
||||
// ihn führte der einzige Weg über „Daten ändern" — ein Formular über alle
|
||||
// Stammdaten, um eine Telefonnummer einzutragen.
|
||||
|
||||
export function NotfallkontaktSection({ employeeId, kontakt }: { employeeId: string; kontakt: Notfallkontakt }) {
|
||||
export function NotfallkontaktSection({
|
||||
employeeId,
|
||||
kontakt,
|
||||
effectiveDate,
|
||||
}: {
|
||||
employeeId: string;
|
||||
kontakt: Notfallkontakt;
|
||||
/**
|
||||
* Nur, wenn der Abschnitt in „Daten ändern" steht: dann treibt dessen
|
||||
* „Wirksam ab" auch diesen Vorgang — wie bei den Angehörigen darüber.
|
||||
* Ohne Angabe gilt heute.
|
||||
*/
|
||||
effectiveDate?: string;
|
||||
}) {
|
||||
const { showToast } = useToast();
|
||||
const router = useRouter();
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [entfernt, setEntfernt] = useState(false);
|
||||
const stichtag = effectiveDate || todayIso();
|
||||
|
||||
const vorhanden = Boolean(kontakt.name);
|
||||
|
||||
@@ -33,7 +47,7 @@ export function NotfallkontaktSection({ employeeId, kontakt }: { employeeId: str
|
||||
// daraus null. Würden die Schlüssel fehlen, bliebe der Kontakt stehen.
|
||||
const result = await changeEmployeeData({
|
||||
employee_id: employeeId,
|
||||
effective_date: todayIso(),
|
||||
effective_date: stichtag,
|
||||
person: { emergency_contact_name: "", emergency_contact_phone: "", emergency_contact_relation: "" },
|
||||
contract: {},
|
||||
role: {},
|
||||
@@ -135,6 +149,7 @@ export function NotfallkontaktSection({ employeeId, kontakt }: { employeeId: str
|
||||
onClose={() => setModalOpen(false)}
|
||||
employeeId={employeeId}
|
||||
kontakt={kontakt}
|
||||
effectiveDate={stichtag}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -18,7 +18,8 @@ import { GRUND_BEGUENSTIGT_BEHINDERT } from "@/lib/kuendigungsschutz";
|
||||
import { MITARBEITERART_STANDARD } from "@/lib/mitarbeiterart";
|
||||
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";
|
||||
import { NotfallkontaktSection } from "@/components/employees/NotfallkontaktSection";
|
||||
import type { ContractType, Database, EmploymentType, GenderType } from "@/lib/types";
|
||||
|
||||
type EmployeeRow = Database["public"]["Tables"]["employees"]["Row"];
|
||||
type Dependent = Database["public"]["Tables"]["employee_dependents"]["Row"];
|
||||
@@ -66,9 +67,6 @@ export function DatenAendernPanel({
|
||||
const [email, setEmail] = useState(employee.email ?? "");
|
||||
const [companyEmail, setCompanyEmail] = useState(employee.company_email ?? "");
|
||||
const [phone, setPhone] = useState(employee.phone ?? "");
|
||||
const [notfallName, setNotfallName] = useState(employee.emergency_contact_name ?? "");
|
||||
const [notfallTelefon, setNotfallTelefon] = useState(employee.emergency_contact_phone ?? "");
|
||||
const [notfallVerhaeltnis, setNotfallVerhaeltnis] = useState(employee.emergency_contact_relation ?? "");
|
||||
|
||||
const [employmentType, setEmploymentType] = useState<EmploymentType>(employee.employment_type);
|
||||
const [weeklyHours, setWeeklyHours] = useState(String(employee.weekly_hours));
|
||||
@@ -136,12 +134,6 @@ export function DatenAendernPanel({
|
||||
showToast("Bitte ein Wirksam-ab-Datum angeben.", "error");
|
||||
return;
|
||||
}
|
||||
// Name und Nummer gehören zusammen — die Datenbank weist eines ohne das
|
||||
// andere ab, und die Meldung dort erklärt es nicht.
|
||||
if (Boolean(notfallName.trim()) !== Boolean(notfallTelefon.trim())) {
|
||||
showToast("Beim Notfallkontakt braucht es Name und Telefonnummer — oder beides leer.", "error");
|
||||
return;
|
||||
}
|
||||
setPending(true);
|
||||
const result = await changeEmployeeData({
|
||||
employee_id: employee.id,
|
||||
@@ -172,9 +164,10 @@ export function DatenAendernPanel({
|
||||
email: email.trim(),
|
||||
company_email: companyEmail.trim(),
|
||||
phone: phone.trim(),
|
||||
emergency_contact_name: notfallName.trim(),
|
||||
emergency_contact_phone: notfallTelefon.trim(),
|
||||
emergency_contact_relation: notfallVerhaeltnis.trim(),
|
||||
// Der Notfallkontakt läuft über seinen eigenen Abschnitt weiter unten
|
||||
// — wie die Angehörigen. Stünde er zusätzlich hier, schrieben zwei
|
||||
// Stellen dasselbe Feld, und welche gewinnt, hinge an der
|
||||
// Reihenfolge.
|
||||
},
|
||||
contract: {
|
||||
employment_type: employmentType,
|
||||
@@ -386,28 +379,22 @@ export function DatenAendernPanel({
|
||||
|
||||
<AngehoerigeSection employeeId={employee.id} dependents={dependents} effectiveDate={effectiveDate} />
|
||||
|
||||
{/* Unterhalb der Angehörigen und ganz am Schluss — dieselbe Reihenfolge
|
||||
wie im Reiter „Stammdaten". Aufgebaut wie „Person", „Vertrag" und
|
||||
„Rolle & Anstellung" darüber: eine Überschrift, darunter die
|
||||
Felder. Hier stand ein umrahmtes fieldset mit eigener
|
||||
Beschriftung; das hob den Abschnitt gegenüber allen anderen
|
||||
heraus, ohne dass er wichtiger wäre. */}
|
||||
<div>
|
||||
<h3 className="mb-3 text-sm font-bold text-ink">Notfallkontakt</h3>
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
||||
<TextField label="Name" dense value={notfallName} onChange={setNotfallName} />
|
||||
<TextField label="Telefon" dense type="tel" value={notfallTelefon} onChange={setNotfallTelefon} />
|
||||
<SelectField
|
||||
label="Verhältnis"
|
||||
dense
|
||||
value={notfallVerhaeltnis}
|
||||
onChange={setNotfallVerhaeltnis}
|
||||
placeholder="Bitte wählen…"
|
||||
options={EMERGENCY_RELATIONS.map((r) => ({ value: r, label: r }))}
|
||||
{/* Derselbe Abschnitt wie im Reiter „Stammdaten", unmittelbar unter den
|
||||
Angehörigen — beides Personen im Umfeld, beides dieselbe Tabelle
|
||||
mit denselben Knöpfen. Hier standen drei Eingabefelder: fachlich
|
||||
dasselbe, aber daneben eine zweite Bauform für denselben Zweck.
|
||||
Beide Abschnitte laufen jetzt über das „Wirksam ab" dieses
|
||||
Formulars. */}
|
||||
<NotfallkontaktSection
|
||||
employeeId={employee.id}
|
||||
effectiveDate={effectiveDate}
|
||||
kontakt={{
|
||||
name: employee.emergency_contact_name,
|
||||
telefon: employee.emergency_contact_phone,
|
||||
verhaeltnis: employee.emergency_contact_relation,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SlideOver>
|
||||
);
|
||||
}
|
||||
|
||||
93
db/migrations/20260924160000_angehoerige_bearbeiten.sql
Normal file
93
db/migrations/20260924160000_angehoerige_bearbeiten.sql
Normal file
@@ -0,0 +1,93 @@
|
||||
-- Angehörige lassen sich bearbeiten.
|
||||
--
|
||||
-- Bisher gab es nur Hinzufügen und Entfernen. Ein Tippfehler im Namen oder
|
||||
-- ein falsches Geburtsdatum liess sich nur beheben, indem man die Person
|
||||
-- löschte und neu anlegte — zwei Einträge in der Akte für eine Korrektur, und
|
||||
-- der erste sagt „entfernt", was nicht stimmt.
|
||||
--
|
||||
-- Anders als Hinzufügen und Entfernen **ohne Stichtag**: eine Berichtigung
|
||||
-- gilt rückwirkend, denn der Wert war schon vorher falsch. Ein „wirksam ab"
|
||||
-- hiesse, die Person habe bis dahin anders geheissen. Wer eine tatsächliche
|
||||
-- Änderung zum Stichtag abbilden will — jemand heiratet und heisst fortan
|
||||
-- anders —, entfernt und legt neu an; dafür sind die beiden Vorgänge da.
|
||||
--
|
||||
-- Der Eintrag in der Akte nennt deshalb Vorher und Nachher, nicht ein Datum.
|
||||
|
||||
create or replace function update_employee_dependent(payload jsonb)
|
||||
returns void
|
||||
language plpgsql
|
||||
set search_path to 'public', 'pg_temp'
|
||||
as $$
|
||||
declare
|
||||
v_alt employee_dependents%rowtype;
|
||||
v_employee_name text;
|
||||
v_neu_name text := (payload->>'first_name') || ' ' || (payload->>'last_name');
|
||||
v_alt_name text;
|
||||
begin
|
||||
perform require_hr_admin();
|
||||
|
||||
select * into v_alt from employee_dependents where id = (payload->>'dependent_id')::uuid;
|
||||
if not found then
|
||||
raise exception 'Angehörige:r nicht gefunden.';
|
||||
end if;
|
||||
v_alt_name := v_alt.first_name || ' ' || v_alt.last_name;
|
||||
|
||||
select first_name || ' ' || last_name into v_employee_name
|
||||
from employees where id = v_alt.employee_id;
|
||||
|
||||
-- Nur die Felder, die mitkommen. Die SV-Nummer ist freiwillig und muss
|
||||
-- sich leeren lassen, deshalb `case when ? then nullif` statt coalesce —
|
||||
-- dieselbe Form wie bei den freiwilligen Feldern der Person
|
||||
-- (20260923160000).
|
||||
update employee_dependents set
|
||||
first_name = coalesce(payload->>'first_name', first_name),
|
||||
last_name = coalesce(payload->>'last_name', last_name),
|
||||
relationship = coalesce(payload->>'relationship', relationship),
|
||||
birth_date = coalesce((payload->>'birth_date')::date, birth_date),
|
||||
sv_nummer = case when payload ? 'sv_nummer' then nullif(payload->>'sv_nummer', '') else sv_nummer end
|
||||
where id = v_alt.id;
|
||||
|
||||
insert into employee_history (employee_id, event_date, event_type, description)
|
||||
values (
|
||||
v_alt.employee_id, current_date, 'Stammdatenänderung',
|
||||
'Angehörige:r berichtigt: ' || v_alt_name || ' (' || v_alt.relationship || ') → '
|
||||
|| v_neu_name || ' (' || (payload->>'relationship') || ')'
|
||||
);
|
||||
|
||||
insert into audit_log (actor_user_id, actor_name, action, target_label, target_employee_id, details, changes)
|
||||
values (
|
||||
app_current_user_id(), current_actor_name(), 'Angehörige:r berichtigt', v_employee_name, v_alt.employee_id,
|
||||
v_alt_name || ' → ' || v_neu_name,
|
||||
app_aenderung(
|
||||
app_aenderung(
|
||||
app_aenderung(
|
||||
app_aenderung('[]'::jsonb, 'Name', v_alt_name, v_neu_name),
|
||||
'Verhältnis', v_alt.relationship, payload->>'relationship'),
|
||||
'Geburtsdatum', v_alt.birth_date::text, payload->>'birth_date'),
|
||||
'SV-Nummer', v_alt.sv_nummer, nullif(payload->>'sv_nummer', ''))
|
||||
);
|
||||
end;
|
||||
$$;
|
||||
|
||||
grant execute on function public.update_employee_dependent(payload jsonb) to alpenwerk_app;
|
||||
|
||||
|
||||
-- Selbstprüfung.
|
||||
do $$
|
||||
declare
|
||||
v_def text := pg_get_functiondef('public.update_employee_dependent(jsonb)'::regprocedure);
|
||||
begin
|
||||
if v_def not like '%require_hr_admin%' then
|
||||
raise exception 'update_employee_dependent prueft die Rechte nicht.';
|
||||
end if;
|
||||
if position('SET search_path' in v_def) = 0 then
|
||||
raise exception 'update_employee_dependent hat keinen festen search_path.';
|
||||
end if;
|
||||
if v_def like '%auth.uid()%' then
|
||||
raise exception 'update_employee_dependent ruft auth.uid().';
|
||||
end if;
|
||||
if v_def not like '%insert into audit_log%' then
|
||||
raise exception 'update_employee_dependent schreibt kein Protokoll.';
|
||||
end if;
|
||||
end
|
||||
$$;
|
||||
@@ -712,6 +712,9 @@ export type Database = {
|
||||
change_employee_data: { Args: { payload: Record<string, unknown> }; Returns: void };
|
||||
rehire_employee: { Args: { payload: Record<string, unknown> }; Returns: void };
|
||||
add_employee_dependent: { Args: { payload: Record<string, unknown> }; Returns: void };
|
||||
// Berichtigen, nicht ändern zum Stichtag: ein falscher Name war schon
|
||||
// vorher falsch. Deshalb ohne `effective_date` (20260924160000).
|
||||
update_employee_dependent: { Args: { payload: Record<string, unknown> }; Returns: void };
|
||||
delete_employee_dependent: { Args: { payload: Record<string, unknown> }; Returns: void };
|
||||
add_employee_note: { Args: { payload: Record<string, unknown> }; Returns: string };
|
||||
complete_employee_note: { Args: { payload: Record<string, unknown> }; Returns: void };
|
||||
|
||||
Reference in New Issue
Block a user