The bell is a shared pile: every active HR person sees every open note, regardless of who wrote it. That was agreed and it stays the default — this narrows it, it never widens it. You can now untick colleagues whose notes you do not want to see. What gets stored is the *exceptions*, not the selection. The difference shows the day someone new joins HR: had the selection been stored, she would be invisible to everyone until each person ticked her, and nobody would notice her follow-ups piling up. This way she is visible from day one and hiding her is a deliberate act. Same reasoning that made notes a shared inbox in the first place — the silent gap is worse than a row too many. Own notes always come through: `note_mutes` rejects a self-reference, and the predicate says so again rather than depending on a check constraint staying put. Notes with no author come through too — hiding one because nobody knows who wrote it is exactly the loss this list exists to prevent. The rule lives in lib/notes.ts as one SQL expression because two places need it: the bell in the header and the "Anstehend" card on the dashboard. Two copies drift, and then the card counts something the bell does not show. No SQL function and no audit row, unlike anything that touches employee data — this is a personal display preference, and an audit trail recording every tick would make finding real changes harder. Same pattern as saved reports and hire drafts, and the owner policy on note_mutes means a row for someone else cannot be written even with invented values. The checkbox flips immediately and flips back if saving fails; the list gets clicked through several at a time and a round trip per tick feels like hesitation. Verified: 19 tests, five mutation-checked (or→and, dropping the own-notes clause, inverting `not exists`, inverting the default, and losing the email fallback each turn them red). Typecheck, lint, schema drift, 477 tests and the build are clean. Not seen in a browser: login goes through the company account and the database is unreachable — the migration is reviewed but has not been run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
647 lines
24 KiB
TypeScript
647 lines
24 KiB
TypeScript
// Von Hand gepflegt, passend zu db/migrations/*.sql.
|
|
//
|
|
// Erzeugt wird hier nichts: scripts/check-schema-types.mjs haelt die Datei
|
|
// Spalte fuer Spalte gegen die Migrationen und meldet jede Abweichung.
|
|
|
|
export type EmploymentStatus = "Aktiv" | "Karenz" | "Geplant" | "Ausgetreten";
|
|
export type EmploymentType = "Vollzeit" | "Teilzeit";
|
|
export type ContractType = "unbefristet" | "befristet";
|
|
export type PaygradeType = "A" | "B" | "C" | "D" | "E" | "F";
|
|
export type SourceType = "Intern" | "Extern";
|
|
export type GenderType = "m" | "w";
|
|
export type WorkerType = "Angestellte:r" | "Arbeiter:in";
|
|
export type CollectiveAgreement = "Handel" | "Süßwaren";
|
|
export type Weekday = "Mo" | "Di" | "Mi" | "Do" | "Fr" | "Sa" | "So";
|
|
|
|
/**
|
|
* Antriebsart des Dienstwagens.
|
|
*
|
|
* Bewusst keine dritte Möglichkeit „unbekannt": die Angabe hängt per CHECK
|
|
* an has_dienstwagen, und wer einen Dienstwagen hat, weiss auch, ob er lädt
|
|
* oder tankt.
|
|
*/
|
|
export type DienstwagenArt = "Verbrenner" | "Elektro";
|
|
|
|
/**
|
|
* Gesetzlich geregelte Teilzeiten.
|
|
*
|
|
* Keine Abwesenheiten: die Person arbeitet, nur kürzer. Als Zustand geführt,
|
|
* damit sich auswerten lässt, wer gerade in einer ist — mit einem optionalen
|
|
* Enddatum, weil nicht jede ein bekanntes Ende hat.
|
|
*/
|
|
export type TeilzeitArt = "Bildungsteilzeit" | "Elternteilzeit" | "Pflegeteilzeit" | "Wiedereingliederungsteilzeit";
|
|
|
|
/**
|
|
* Verhältnis zum Notfallkontakt.
|
|
*
|
|
* Auswahlliste statt Freitext, damit sich danach auswerten lässt und nicht
|
|
* „Gattin", „Ehefrau" und „Frau" nebeneinander stehen. „Sonstige" ist der
|
|
* Ausweg für alles, was hier fehlt — ohne ihn wäre die Liste eine Anmassung.
|
|
*
|
|
* In der Datenbank bleibt die Spalte `text`: eine Aufzählung dort würde jede
|
|
* Ergänzung zu einer Migration machen, und diese Liste wird sich ändern.
|
|
*/
|
|
export const EMERGENCY_RELATIONS = [
|
|
"Gattin/Gatte",
|
|
"Lebensgefährtin/Lebensgefährte",
|
|
"Mutter",
|
|
"Vater",
|
|
"Tochter",
|
|
"Sohn",
|
|
"Schwester",
|
|
"Bruder",
|
|
"Freundin/Freund",
|
|
"Sonstige",
|
|
] as const;
|
|
|
|
export type EmergencyRelation = (typeof EMERGENCY_RELATIONS)[number];
|
|
|
|
/**
|
|
* Eine einzelne Feldänderung im Protokoll.
|
|
*
|
|
* `vorher` und `nachher` sind bewusst Text: die Datenbank stellt jeden Typ
|
|
* über ::text dar, damit ein Datum, eine Zahl und eine Liste von Arbeitstagen
|
|
* in derselben Spalte nebeneinander stehen können. Für die Anzeige reicht
|
|
* das; gerechnet wird damit nicht.
|
|
*/
|
|
export type AuditChange = { feld: string; vorher: string | null; nachher: string | null };
|
|
export type RelationshipType = "Ehepartner:in" | "Lebenspartner:in" | "Kind" | "Sonstige";
|
|
export type NoteCategory = "Allgemein" | "Vertraulich" | "Personalgespräch" | "Wiedervorlage" | "Lob / Anerkennung";
|
|
// Single HR-only role (see docs/decisions/0001-hr-only-access.md). Kept as a
|
|
// union (not a string literal) so a future hr_admin/hr_user split, if ever
|
|
// technically required, is a type-level addition, not a rewrite.
|
|
export type ProfileRole = "hr";
|
|
/** Etikett einer Organisationseinheit; die Struktur steckt in parent_id. */
|
|
export type OrgUnitType = "Gesellschaft" | "Bereich" | "Abteilung" | "Team";
|
|
export type HistoryEventType =
|
|
| "Eintritt"
|
|
| "Beförderung"
|
|
| "Versetzung"
|
|
| "Karenz"
|
|
| "Vertragsänderung"
|
|
| "Stammdatenänderung"
|
|
| "Austritt"
|
|
| "Wiedereintritt"
|
|
| "Reorganisation"
|
|
| "Gehaltsanpassung"
|
|
| "Rückkehr";
|
|
export type PendingChangeType =
|
|
| "transfer"
|
|
| "promotion"
|
|
| "karenz_start"
|
|
| "karenz_return"
|
|
| "contract_change"
|
|
| "reorg";
|
|
export type PendingChangeStatus = "pending" | "applied" | "cancelled";
|
|
|
|
export type Database = {
|
|
public: {
|
|
Tables: {
|
|
locations: {
|
|
Row: { id: string; name: string; country: string };
|
|
Insert: { id?: string; name: string; country: string };
|
|
Update: Partial<{ id: string; name: string; country: string }>;
|
|
};
|
|
profiles: {
|
|
Row: {
|
|
id: string;
|
|
email: string;
|
|
full_name: string | null;
|
|
role: ProfileRole;
|
|
is_active: boolean;
|
|
created_by: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
};
|
|
Insert: {
|
|
id: string;
|
|
email: string;
|
|
full_name?: string | null;
|
|
role?: ProfileRole;
|
|
is_active?: boolean;
|
|
created_by?: string | null;
|
|
created_at?: string;
|
|
updated_at?: string;
|
|
};
|
|
Update: Partial<{
|
|
id: string;
|
|
email: string;
|
|
full_name: string | null;
|
|
role: ProfileRole;
|
|
is_active: boolean;
|
|
created_by: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}>;
|
|
};
|
|
employees: {
|
|
Row: {
|
|
id: string;
|
|
personnel_number: number;
|
|
first_name: string;
|
|
last_name: string;
|
|
gender: GenderType;
|
|
birth_date: string;
|
|
sv_nummer: string | null;
|
|
nationality: string;
|
|
/** Aufenthaltstitel — nur ausserhalb von EU, EWR und Schweiz erhoben. */
|
|
hat_aufenthaltstitel: boolean;
|
|
/** Gültig bis, falls befristet. Nur mit dem Kennzeichen zusammen erlaubt. */
|
|
aufenthaltstitel_bis: string | null;
|
|
address: string | null;
|
|
postal_code: string | null;
|
|
city: string | null;
|
|
address_country: string | null;
|
|
/** Private Adresse, freiwillig — eindeutig, wenn angegeben. */
|
|
email: string | null;
|
|
phone: string | null;
|
|
job_title: string;
|
|
location_id: string;
|
|
employment_type: EmploymentType;
|
|
weekly_hours: number;
|
|
/** @deprecated Salary is out of MVP scope; column kept only for pre-existing data. */
|
|
monthly_salary_gross: number | null;
|
|
contract_type: ContractType;
|
|
contract_end_date: string | null;
|
|
paygrade: PaygradeType;
|
|
source: SourceType;
|
|
status: EmploymentStatus;
|
|
entry_date: string;
|
|
exit_date: string | null;
|
|
exit_reason: string | null;
|
|
karenz_start_date: string | null;
|
|
karenz_return_date: string | null;
|
|
absence_type: string | null;
|
|
avatar_color: string | null;
|
|
worker_type: WorkerType;
|
|
collective_agreement: CollectiveAgreement;
|
|
work_days: Weekday[];
|
|
is_betriebsrat: boolean;
|
|
has_dienstwagen: boolean;
|
|
/** Null genau dann, wenn kein Dienstwagen vorhanden ist — chk_dienstwagen_art. */
|
|
dienstwagen_art: DienstwagenArt | null;
|
|
/** Besonderer Kündigungsschutz — löst beim Austritt eine Warnung aus. */
|
|
has_kuendigungsschutz: boolean;
|
|
/** Ende des Schutzes, falls bekannt. Nur mit dem Kennzeichen zusammen erlaubt. */
|
|
kuendigungsschutz_bis: string | null;
|
|
/** Bildungs-, Eltern-, Pflege- oder Wiedereingliederungsteilzeit; null bei einer gewöhnlichen Regelung. */
|
|
teilzeit_art: TeilzeitArt | null;
|
|
/** Ende der Teilzeit, falls bekannt. Nur mit einer Variante zusammen erlaubt. */
|
|
teilzeit_bis: string | null;
|
|
/** Nur gemeinsam gesetzt oder gemeinsam leer — chk_emergency_contact. */
|
|
emergency_contact_name: string | null;
|
|
emergency_contact_phone: string | null;
|
|
emergency_contact_relation: string | null;
|
|
is_laterale_fuehrung: boolean;
|
|
is_c_level: boolean;
|
|
title_prefix: string[];
|
|
title_suffix: string[];
|
|
created_at: string;
|
|
updated_at: string;
|
|
};
|
|
Insert: {
|
|
id?: string;
|
|
first_name: string;
|
|
last_name: string;
|
|
gender: GenderType;
|
|
birth_date: string;
|
|
sv_nummer?: string | null;
|
|
nationality?: string;
|
|
hat_aufenthaltstitel?: boolean;
|
|
aufenthaltstitel_bis?: string | null;
|
|
address?: string | null;
|
|
postal_code?: string | null;
|
|
city?: string | null;
|
|
address_country?: string | null;
|
|
email?: string | null;
|
|
phone?: string | null;
|
|
job_title: string;
|
|
location_id: string;
|
|
employment_type?: EmploymentType;
|
|
weekly_hours?: number;
|
|
contract_type?: ContractType;
|
|
contract_end_date?: string | null;
|
|
paygrade?: PaygradeType;
|
|
source?: SourceType;
|
|
status?: EmploymentStatus;
|
|
entry_date: string;
|
|
exit_date?: string | null;
|
|
exit_reason?: string | null;
|
|
karenz_start_date?: string | null;
|
|
karenz_return_date?: string | null;
|
|
absence_type?: string | null;
|
|
avatar_color?: string | null;
|
|
worker_type?: WorkerType;
|
|
collective_agreement?: CollectiveAgreement;
|
|
work_days?: Weekday[];
|
|
is_betriebsrat?: boolean;
|
|
has_dienstwagen?: boolean;
|
|
dienstwagen_art?: DienstwagenArt | null;
|
|
has_kuendigungsschutz?: boolean;
|
|
kuendigungsschutz_bis?: string | null;
|
|
teilzeit_art?: TeilzeitArt | null;
|
|
teilzeit_bis?: string | null;
|
|
emergency_contact_name?: string | null;
|
|
emergency_contact_phone?: string | null;
|
|
emergency_contact_relation?: string | null;
|
|
is_laterale_fuehrung?: boolean;
|
|
is_c_level?: boolean;
|
|
title_prefix?: string[];
|
|
title_suffix?: string[];
|
|
created_at?: string;
|
|
updated_at?: string;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["employees"]["Insert"]>;
|
|
};
|
|
employee_history: {
|
|
Row: {
|
|
id: string;
|
|
employee_id: string;
|
|
event_date: string;
|
|
event_type: HistoryEventType;
|
|
description: string;
|
|
/** Feldweise Änderungen — dieselbe Form wie audit_log.changes. */
|
|
changes: AuditChange[] | null;
|
|
/** Der geplante Vorgang, solange die Änderung noch nicht wirksam ist. */
|
|
pending_id: string | null;
|
|
created_at: string;
|
|
};
|
|
Insert: {
|
|
id?: string;
|
|
employee_id: string;
|
|
event_date: string;
|
|
event_type: HistoryEventType;
|
|
description: string;
|
|
changes?: AuditChange[] | null;
|
|
pending_id?: string | null;
|
|
created_at?: string;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["employee_history"]["Insert"]>;
|
|
};
|
|
employee_dependents: {
|
|
Row: {
|
|
id: string;
|
|
employee_id: string;
|
|
first_name: string;
|
|
last_name: string;
|
|
relationship: RelationshipType;
|
|
sv_nummer: string | null;
|
|
birth_date: string;
|
|
created_at: string;
|
|
};
|
|
Insert: {
|
|
id?: string;
|
|
employee_id: string;
|
|
first_name: string;
|
|
last_name: string;
|
|
relationship: RelationshipType;
|
|
sv_nummer?: string | null;
|
|
birth_date: string;
|
|
created_at?: string;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["employee_dependents"]["Insert"]>;
|
|
};
|
|
employee_notes: {
|
|
Row: {
|
|
id: string;
|
|
employee_id: string;
|
|
author_user_id: string | null;
|
|
author_name: string;
|
|
category: NoteCategory;
|
|
note_text: string;
|
|
due_date: string | null;
|
|
done: boolean;
|
|
done_at: string | null;
|
|
done_by: string | null;
|
|
created_at: string;
|
|
};
|
|
Insert: {
|
|
id?: string;
|
|
employee_id: string;
|
|
author_user_id?: string | null;
|
|
author_name: string;
|
|
category?: NoteCategory;
|
|
note_text: string;
|
|
due_date?: string | null;
|
|
done?: boolean;
|
|
done_at?: string | null;
|
|
done_by?: string | null;
|
|
created_at?: string;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["employee_notes"]["Insert"]>;
|
|
};
|
|
hire_drafts: {
|
|
Row: { id: string; created_by: string | null; step: number; payload: Record<string, unknown>; updated_at: string };
|
|
Insert: { id?: string; created_by?: string | null; step?: number; payload: Record<string, unknown>; updated_at?: string };
|
|
Update: Partial<Database["public"]["Tables"]["hire_drafts"]["Insert"]>;
|
|
};
|
|
saved_reports: {
|
|
Row: { id: string; created_by: string | null; name: string; config: Record<string, unknown>; created_at: string };
|
|
Insert: { id?: string; created_by?: string | null; name: string; config: Record<string, unknown>; created_at?: string };
|
|
Update: Partial<Database["public"]["Tables"]["saved_reports"]["Insert"]>;
|
|
};
|
|
audit_log: {
|
|
Row: {
|
|
id: string;
|
|
occurred_at: string;
|
|
actor_user_id: string | null;
|
|
actor_name: string;
|
|
action: string;
|
|
target_label: string;
|
|
target_employee_id: string | null;
|
|
details: string | null;
|
|
/**
|
|
* Feldweise Änderungen. Null bei Einträgen aus der Zeit vor
|
|
* 20260803140000_audit_changes_detail.sql — dort wurden nur die
|
|
* Feldnamen behalten, nicht die Werte, und das lässt sich nicht
|
|
* nachliefern.
|
|
*/
|
|
changes: AuditChange[] | null;
|
|
};
|
|
Insert: {
|
|
id?: string;
|
|
occurred_at?: string;
|
|
actor_user_id?: string | null;
|
|
actor_name: string;
|
|
action: string;
|
|
target_label: string;
|
|
target_employee_id?: string | null;
|
|
details?: string | null;
|
|
changes?: AuditChange[] | null;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["audit_log"]["Insert"]>;
|
|
};
|
|
pending_org_changes: {
|
|
Row: {
|
|
id: string;
|
|
employee_id: string;
|
|
change_type: PendingChangeType;
|
|
effective_date: string;
|
|
payload: Record<string, unknown>;
|
|
status: PendingChangeStatus;
|
|
created_by: string | null;
|
|
created_at: string;
|
|
applied_at: string | null;
|
|
};
|
|
Insert: {
|
|
id?: string;
|
|
employee_id: string;
|
|
change_type: PendingChangeType;
|
|
effective_date: string;
|
|
payload: Record<string, unknown>;
|
|
status?: PendingChangeStatus;
|
|
created_by?: string | null;
|
|
created_at?: string;
|
|
applied_at?: string | null;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["pending_org_changes"]["Insert"]>;
|
|
};
|
|
// ── SAP-OM-Modell ──────────────────────────────────────────
|
|
// O: rekursiv über parent_id, unit_type ist nur ein Etikett.
|
|
org_units: {
|
|
Row: {
|
|
id: string;
|
|
org_number: string;
|
|
name: string;
|
|
parent_id: string | null;
|
|
unit_type: OrgUnitType;
|
|
valid_from: string;
|
|
valid_to: string | null;
|
|
created_at: string;
|
|
};
|
|
Insert: {
|
|
id?: string;
|
|
org_number: string;
|
|
name: string;
|
|
parent_id?: string | null;
|
|
unit_type: OrgUnitType;
|
|
valid_from?: string;
|
|
valid_to?: string | null;
|
|
created_at?: string;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["org_units"]["Insert"]>;
|
|
};
|
|
// C: Katalog der Tätigkeiten.
|
|
jobs: {
|
|
Row: { id: string; code: string; title: string; created_at: string };
|
|
Insert: { id?: string; code: string; title: string; created_at?: string };
|
|
Update: Partial<Database["public"]["Tables"]["jobs"]["Insert"]>;
|
|
};
|
|
// S: Planstelle. Der Name om_positions stammt aus der Zeit, in der die
|
|
// alte positions-Tabelle noch danebenstand; sie ist inzwischen weg.
|
|
om_positions: {
|
|
Row: {
|
|
id: string;
|
|
position_number: string;
|
|
org_unit_id: string;
|
|
job_id: string;
|
|
is_chief: boolean;
|
|
valid_from: string;
|
|
valid_to: string | null;
|
|
created_at: string;
|
|
};
|
|
Insert: {
|
|
id?: string;
|
|
position_number: string;
|
|
org_unit_id: string;
|
|
job_id: string;
|
|
is_chief?: boolean;
|
|
valid_from?: string;
|
|
valid_to?: string | null;
|
|
created_at?: string;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["om_positions"]["Insert"]>;
|
|
};
|
|
// Die Onboarding-Checkliste: je Person und Punkt eine Zeile. Welche
|
|
// Punkte es gibt, steht in lib/onboarding.ts — nicht hier.
|
|
onboarding_tasks: {
|
|
Row: {
|
|
id: string;
|
|
employee_id: string;
|
|
item_key: string;
|
|
erledigt: boolean;
|
|
wert: string | null;
|
|
kommentar: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
updated_by: string | null;
|
|
updated_by_name: string | null;
|
|
};
|
|
Insert: {
|
|
id?: string;
|
|
employee_id: string;
|
|
item_key: string;
|
|
erledigt?: boolean;
|
|
wert?: string | null;
|
|
kommentar?: string | null;
|
|
created_at?: string;
|
|
updated_at?: string;
|
|
updated_by?: string | null;
|
|
updated_by_name?: string | null;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["onboarding_tasks"]["Insert"]>;
|
|
};
|
|
// Die Offboarding-Checkliste — dieselbe Form wie onboarding_tasks, für
|
|
// den anderen Weg. Punkte in lib/offboarding.ts.
|
|
offboarding_tasks: {
|
|
Row: {
|
|
id: string;
|
|
employee_id: string;
|
|
item_key: string;
|
|
erledigt: boolean;
|
|
wert: string | null;
|
|
kommentar: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
updated_by: string | null;
|
|
updated_by_name: string | null;
|
|
};
|
|
Insert: {
|
|
id?: string;
|
|
employee_id: string;
|
|
item_key: string;
|
|
erledigt?: boolean;
|
|
wert?: string | null;
|
|
kommentar?: string | null;
|
|
created_at?: string;
|
|
updated_at?: string;
|
|
updated_by?: string | null;
|
|
updated_by_name?: string | null;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["offboarding_tasks"]["Insert"]>;
|
|
};
|
|
// Kostenstellen. Die Zuordnung hängt an der Planstelle, nicht an der
|
|
// Person: der Sitz kostet Geld, auch wenn niemand darauf sitzt.
|
|
cost_centers: {
|
|
Row: {
|
|
id: string;
|
|
code: string;
|
|
name: string;
|
|
org_unit_id: string | null;
|
|
valid_from: string;
|
|
valid_to: string | null;
|
|
created_at: string;
|
|
};
|
|
Insert: {
|
|
id?: string;
|
|
code: string;
|
|
name: string;
|
|
org_unit_id?: string | null;
|
|
valid_from?: string;
|
|
valid_to?: string | null;
|
|
created_at?: string;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["cost_centers"]["Insert"]>;
|
|
};
|
|
// A011: Planstelle kontiert auf Kostenstelle, zeitabhängig.
|
|
position_cost_centers: {
|
|
Row: {
|
|
id: string;
|
|
position_id: string;
|
|
cost_center_id: string;
|
|
valid_from: string;
|
|
valid_to: string | null;
|
|
created_at: string;
|
|
};
|
|
Insert: {
|
|
id?: string;
|
|
position_id: string;
|
|
cost_center_id: string;
|
|
valid_from: string;
|
|
valid_to?: string | null;
|
|
created_at?: string;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["position_cost_centers"]["Insert"]>;
|
|
};
|
|
// A008: Person besetzt Planstelle, zeitabhängig.
|
|
position_assignments: {
|
|
Row: {
|
|
id: string;
|
|
position_id: string;
|
|
employee_id: string;
|
|
valid_from: string;
|
|
valid_to: string | null;
|
|
created_at: string;
|
|
};
|
|
Insert: {
|
|
id?: string;
|
|
position_id: string;
|
|
employee_id: string;
|
|
valid_from: string;
|
|
valid_to?: string | null;
|
|
created_at?: string;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["position_assignments"]["Insert"]>;
|
|
// Beide Richtungen: über die Planstelle hängt die Verortung in der
|
|
// Organisation, über die Person die Verortung in der Akte. Die
|
|
// Einbettung erspart an einem Dutzend Stellen eine zweite Abfrage.
|
|
};
|
|
// Abgewählte Kolleg:innen je Person. Eine Zeile blendet deren Notizen
|
|
// aus; ohne Zeile ist alles sichtbar. Gespeichert wird das Abgewählte,
|
|
// nicht das Gewählte — sonst wäre eine neu hinzugekommene HR-Person für
|
|
// alle unsichtbar, bis jede sie einzeln anhakt.
|
|
note_mutes: {
|
|
Row: {
|
|
user_id: string;
|
|
muted_user_id: string;
|
|
created_at: string;
|
|
};
|
|
Insert: {
|
|
user_id: string;
|
|
muted_user_id: string;
|
|
created_at?: string;
|
|
};
|
|
Update: Partial<Database["public"]["Tables"]["note_mutes"]["Insert"]>;
|
|
};
|
|
};
|
|
Views: Record<string, never>;
|
|
Functions: {
|
|
hire_employee: { Args: { payload: Record<string, unknown> }; Returns: string };
|
|
terminate_employee: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
transfer_employee: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
promote_employee: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
start_karenz: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
adjust_karenz_return: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
record_karenz_return: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
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 };
|
|
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 };
|
|
// Eigenes Passwort wechseln. Die einzige mutierende Funktion **ohne**
|
|
// require_hr_admin() — sonst käme niemand aus dem erzwungenen Wechsel
|
|
// heraus, denn solange er aussteht, ist is_hr_user() false.
|
|
app_passwort_aendern: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
// Nimmt eine irrtümliche Stammdaten-/Vertragsänderung zurück. Der einzige
|
|
// Weg an der fehlenden delete-Policy auf employee_history vorbei.
|
|
delete_history_entry: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
// Berichtigt Wert und/oder Datum eines Historieneintrags.
|
|
update_history_entry: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
// Planstelle anlegen bzw. schliessen — im OM-Modell Operationen auf
|
|
// om_positions, nicht mehr auf einer eigenen Ausschreibungstabelle.
|
|
create_position: { Args: { payload: Record<string, unknown> }; Returns: string };
|
|
update_position: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
set_position_cost_center: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
set_onboarding_task: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
start_onboarding: { Args: { payload: Record<string, unknown> }; Returns: number };
|
|
set_offboarding_task: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
start_offboarding: { Args: { payload: Record<string, unknown> }; Returns: number };
|
|
delete_position: { Args: { payload: Record<string, unknown> }; Returns: void };
|
|
is_valid_svnr: { Args: { p_svnr: string; p_birth_date?: string | null }; Returns: boolean };
|
|
apply_due_pending_changes: { Args: Record<string, never>; Returns: number };
|
|
om_reporting_lines: {
|
|
Args: { p_as_of?: string };
|
|
Returns: {
|
|
employee_id: string;
|
|
position_id: string;
|
|
org_unit_id: string;
|
|
is_chief: boolean;
|
|
formal_manager_id: string | null;
|
|
acting_manager_id: string | null;
|
|
}[];
|
|
};
|
|
};
|
|
};
|
|
};
|