YTD heisst bis heute, nicht bis zum Jahresende
All checks were successful
CI / Lint, Typen, Tests, Build (push) Successful in 11m29s
CI / Migrationen auf leerer Datenbank (push) Successful in 10m6s

Die Kacheln "Eintritte/Austritte (YTD)" zaehlten bis zum 31.12. und damit auch,
was erst bevorsteht: ein fuer den 01.11. erfasster Austritt stand schon im
September als geschehen da. Die Kachel sagte 2, tatsaechlich war es 1.

Der Kommentar an der Kachel nannte die Absicht seit jeher richtig -- "seit
Jahresbeginn bis heute, nicht das ganze Kalenderjahr" --, nur stand darunter
yearEnd. Was kommt, steht ohnehin in "Anstehend" daneben; die Kachel soll
sagen, was war.

Der Verweis auf den Bericht traegt denselben Zeitraum, sonst zeigte der Bericht
eine andere Zahl als die Kachel, ueber die man ihn geoeffnet hat. Und die
Variable heisst jetzt ytdBis statt yearEnd -- ein Name, der "Jahresende" sagt
und "heute" bedeutet, waere die naechste Fundstelle gewesen.
This commit is contained in:
2026-09-29 20:05:55 +02:00
parent cf5ed5c6c6
commit fe858c6c24
2 changed files with 21 additions and 7 deletions

View File

@@ -70,7 +70,10 @@ export default async function DashboardPage({
const today = todayIso(); const today = todayIso();
const year = today.slice(0, 4); const year = today.slice(0, 4);
const yearStart = `${year}-01-01`; const yearStart = `${year}-01-01`;
const yearEnd = `${year}-12-31`; // Das obere Ende des YTD-Fensters ist **heute**. Hier stand der 31.12., also
// das ganze Kalenderjahr — womit die Kacheln auch zählten, was erst
// bevorsteht (B.02).
const ytdBis = today;
// Der Vorschauzeitraum ist einstellbar, und mit ihm, was überhaupt geladen // Der Vorschauzeitraum ist einstellbar, und mit ihm, was überhaupt geladen
// wird. Deshalb steht die Auswahl in der Adresse und nicht im Browser: 90 // wird. Deshalb steht die Auswahl in der Adresse und nicht im Browser: 90
@@ -103,7 +106,7 @@ export default async function DashboardPage({
upcomingReturns, upcomingReturns,
upcomingNotes, upcomingNotes,
history, history,
} = await withUser(userId, (tx) => loadDashboardData(tx, { userId, today, yearStart, yearEnd, bisIso, arten })); } = await withUser(userId, (tx) => loadDashboardData(tx, { userId, today, yearStart, ytdBis, bisIso, arten }));
// "Aktiv" means status Aktiv — somebody on Karenz is employed but not // "Aktiv" means status Aktiv — somebody on Karenz is employed but not
// active, and is counted by its own tile instead. FTE follows the same // active, and is counted by its own tile instead. FTE follows the same
// set: Karenz contributes no capacity, so including it would overstate // set: Karenz contributes no capacity, so including it would overstate
@@ -225,16 +228,18 @@ export default async function DashboardPage({
kacheln: [ kacheln: [
{ {
// YTD: seit Jahresbeginn bis heute, nicht das ganze Kalenderjahr. // YTD: seit Jahresbeginn bis heute, nicht das ganze Kalenderjahr.
// Der Verweis trägt denselben Zeitraum — sonst zeigte der Bericht
// eine andere Zahl als die Kachel, über die man ihn geöffnet hat.
label: "Eintritte (YTD)", label: "Eintritte (YTD)",
value: hiresYtd, value: hiresYtd,
tone: "success", tone: "success",
href: `/reports?mode=events&eventType=Eintritt&from=${yearStart}&to=${yearEnd}`, href: `/reports?mode=events&eventType=Eintritt&from=${yearStart}&to=${ytdBis}`,
}, },
{ {
label: "Austritte (YTD)", label: "Austritte (YTD)",
value: exitsYtd, value: exitsYtd,
tone: "danger", tone: "danger",
href: `/reports?mode=events&eventType=Austritt&from=${yearStart}&to=${yearEnd}`, href: `/reports?mode=events&eventType=Austritt&from=${yearStart}&to=${ytdBis}`,
}, },
], ],
}, },

View File

@@ -22,13 +22,22 @@ export type DashboardParams = {
userId: string | null; userId: string | null;
today: string; today: string;
yearStart: string; yearStart: string;
yearEnd: string; /**
* Das obere Ende des YTD-Fensters — **heute**, nicht der 31.12.
*
* Hier stand das Jahresende, womit die Kacheln „Eintritte/Austritte (YTD)"
* auch zählten, was erst bevorsteht: ein für den 01.11. erfasster Austritt
* stand schon im September als geschehen da. „Year to date" heisst bis
* heute, und die Kachel soll sagen, was war — was kommt, steht in
* „Anstehend" daneben. Gemeldet im Test vom 29.09. (B.02).
*/
ytdBis: string;
bisIso: string; bisIso: string;
arten: AnstehendArt[]; arten: AnstehendArt[];
}; };
export async function loadDashboardData(tx: Tx, p: DashboardParams) { export async function loadDashboardData(tx: Tx, p: DashboardParams) {
const { userId, today, yearStart, yearEnd, bisIso, arten } = p; const { userId, today, yearStart, ytdBis, bisIso, arten } = p;
const zeigt = (art: AnstehendArt) => arten.includes(art); const zeigt = (art: AnstehendArt) => arten.includes(art);
// Elf Abfragen standen hier in einem Promise.all, das keine // Elf Abfragen standen hier in einem Promise.all, das keine
// Gleichzeitigkeit war: eine Transaktion hängt an einer Verbindung, und // Gleichzeitigkeit war: eine Transaktion hängt an einer Verbindung, und
@@ -43,7 +52,7 @@ export async function loadDashboardData(tx: Tx, p: DashboardParams) {
.select(({ fn }) => fn.countAll<string>().as("anzahl")) .select(({ fn }) => fn.countAll<string>().as("anzahl"))
.where("event_type", "in", [...types]) .where("event_type", "in", [...types])
.where("event_date", ">=", yearStart) .where("event_date", ">=", yearStart)
.where("event_date", "<=", yearEnd); .where("event_date", "<=", ytdBis);
const g = await tx const g = await tx
.selectNoFrom((eb) => [ .selectNoFrom((eb) => [