Workshop-Anforderungen, erster Teil: was ohne Migration geht
Anforderung 1 — Freiwilliger vs unfreiwilliger Austritt. Die Liste der Beendigungsarten zieht aus TerminatePanel.tsx nach lib/beendigung.ts um: der Berichtemanager braucht sie ebenso, und zwei Listen liefen auseinander. Zwei neue Arten (Beendigung in der Probezeit, je Seite). Auf wessen Betreiben beendet wurde, wird aus der Art **abgeleitet** und nicht daneben gespeichert — als zweites freies Feld liesse sich "Entlassung, freiwillig" erfassen. Das Dropdown im Formular schraenkt die Auswahl darunter ein. Drei Gruppen statt zwei: Befristungsablauf geschieht auf niemandes Betreiben, ein Nichtantritt ist kein Austritt. Beide einer Seite zuzuschlagen wuerde jede Fluktuationsquote verfaelschen. Anforderung 2 — Namensfilter in "Anstehend", ab neun Eintraegen. Anforderung 3 — die zwei Unterschriftenfelder im gedruckten Blatt sind weg; "Firmenfahrzeug" steht in beiden Checklisten. has_dienstwagen sagt, ob eines zusteht, nicht ob es uebergeben wurde. Anforderung 4 — "+794 weitere" ist ein Knopf geworden; die Namen waren vorher nur ueber den Export erreichbar. Stammdatenaenderung und Gehaltsanpassung stehen nicht mehr zur Auswahl: die eine entsteht bei jeder geaenderten Telefonnummer, die andere ist ein totes Ereignis, seit das Gehalt in Loga liegt. Neu ist der Untertyp — Beendigungsart beim Austritt, Art der Abwesenheit bei der Langzeitabwesenheit, im Bericht und im Export. Anforderung 10 — zwei Kacheln. "Aktives Dienstverhaeltnis" ist nicht dasselbe wie "Aktive Mitarbeiter:innen": dort steht, wer heute arbeitet, hier, mit wem ein Vertrag laeuft. Sichtbar waren 806 und 10, addieren musste man selbst.
This commit is contained in:
@@ -6,6 +6,7 @@ import { loadPlacements } from "./placement";
|
||||
import { LEERE_CRITERIA, passtImSpeicher, type Criteria } from "./report-criteria";
|
||||
import {
|
||||
deriveStatusAsOf,
|
||||
EREIGNIS_UNTERTYP,
|
||||
EVENT_DATE_OPEN,
|
||||
parseStatuses,
|
||||
todayIso,
|
||||
@@ -102,7 +103,15 @@ export function applyCriteria<O>(
|
||||
}
|
||||
|
||||
export type SnapshotFilters = ReportFilters & { asOf?: string };
|
||||
export type EventFilters = { eventType?: HistoryEventType; division?: string; location?: string; from?: string; to?: string };
|
||||
export type EventFilters = {
|
||||
eventType?: HistoryEventType;
|
||||
/** Beendigungsart bzw. Art der Langzeitabwesenheit — nur mit eventType sinnvoll. */
|
||||
eventSubtype?: string;
|
||||
division?: string;
|
||||
location?: string;
|
||||
from?: string;
|
||||
to?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Für jede Einheit vorberechnen, welcher Bereich, welche Abteilung und
|
||||
@@ -281,7 +290,14 @@ export async function loadEventHistory(tx: Tx, filters: EventFilters): Promise<R
|
||||
|
||||
const [history, employees, assignments, orgMaps] = await Promise.all([
|
||||
historyQuery().execute(),
|
||||
tx.selectFrom("employees").select(["id", "first_name", "last_name", "job_title", "location_id"]).orderBy("id").execute(),
|
||||
tx
|
||||
.selectFrom("employees")
|
||||
// exit_reason/absence_type für den Untertyp eines Ereignisses — siehe
|
||||
// ReportEvent.subtype in lib/reports.ts, dort steht auch, wo die Grenze
|
||||
// dieser Zuordnung liegt.
|
||||
.select(["id", "first_name", "last_name", "job_title", "location_id", "exit_reason", "absence_type"])
|
||||
.orderBy("id")
|
||||
.execute(),
|
||||
tx
|
||||
.selectFrom("position_assignments as a")
|
||||
.innerJoin("om_positions as p", "p.id", "a.position_id")
|
||||
@@ -311,6 +327,12 @@ export async function loadEventHistory(tx: Tx, filters: EventFilters): Promise<R
|
||||
spans.get(h.employee_id)?.find((s2) => s2.from <= h.event_date && (s2.to === null || s2.to > h.event_date))?.unitId ?? null;
|
||||
if (allowedUnits && (!unitId || !allowedUnits.has(unitId))) continue;
|
||||
|
||||
const subtype = untertypVon(h.event_type, emp);
|
||||
// Der Untertyp schränkt nur innerhalb seines Ereignistyps ein. Ohne die
|
||||
// erste Hälfte fielen bei „Alle Ereignistypen" sämtliche Zeilen ohne
|
||||
// Untertyp heraus — eine Versetzung hat keine Beendigungsart.
|
||||
if (filters.eventSubtype && EREIGNIS_UNTERTYP[h.event_type] && subtype !== filters.eventSubtype) continue;
|
||||
|
||||
events.push({
|
||||
employee_id: emp.id,
|
||||
first_name: emp.first_name,
|
||||
@@ -321,7 +343,24 @@ export async function loadEventHistory(tx: Tx, filters: EventFilters): Promise<R
|
||||
event_date: h.event_date,
|
||||
event_type: h.event_type,
|
||||
description: h.description,
|
||||
subtype,
|
||||
});
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Untertyp eines Ereignisses, gelesen von der Person.
|
||||
*
|
||||
* `Rückkehr` erbt die Art der Abwesenheit bewusst nicht: sie wird beim
|
||||
* Zurückkommen zurückgesetzt, und was dort heute steht, gehört zur nächsten
|
||||
* Abwesenheit, nicht zur beendeten.
|
||||
*/
|
||||
function untertypVon(
|
||||
typ: HistoryEventType,
|
||||
emp: { exit_reason: string | null; absence_type: string | null }
|
||||
): string | null {
|
||||
if (typ === "Austritt") return emp.exit_reason;
|
||||
if (typ === "Karenz") return emp.absence_type;
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user