import { describe, expect, it } from "vitest"; import { kontierungAm, kontierungZum, type KontierungsZeile } from "@/lib/cost-centers"; // Eine Umkontierung ist ein Ereignis mit Stichtag. Wer nach den Kosten des // Vorjahres fragt, muss die Kostenstelle von damals bekommen — sonst // verändert jede Umkontierung rückwirkend jede alte Auswertung. function zeile(teil: Partial): KontierungsZeile { return { position_id: "p1", cost_center_id: "k1", code: "21010", name: "Fertigung", valid_from: "2020-01-01", valid_to: null, ...teil, }; } describe("kontierungZum", () => { const alt = zeile({ cost_center_id: "k1", code: "21010", valid_from: "2020-01-01", valid_to: "2026-09-01" }); const neu = zeile({ cost_center_id: "k2", code: "21090", name: "Qualitätssicherung", valid_from: "2026-09-01" }); it("liefert die Kostenstelle, die am Stichtag galt", () => { expect(kontierungZum([alt, neu], "2026-08-31")?.get("p1")?.code).toBe("21010"); expect(kontierungZum([alt, neu], "2026-09-01")?.get("p1")?.code).toBe("21090"); }); it("behandelt den Zeitraum halboffen — der letzte Tag gehört der nächsten", () => { // Sonst gälte am 01.09. beides, und welche Antwort käme, hinge an der // Reihenfolge der Zeilen. expect(kontierungZum([alt, neu], "2026-08-31").get("p1")?.code).toBe("21010"); expect(kontierungZum([neu, alt], "2026-09-01").get("p1")?.code).toBe("21090"); }); it("liefert vor Beginn der ersten Kontierung nichts", () => { expect(kontierungZum([alt, neu], "2019-12-31").has("p1")).toBe(false); }); it("liefert nach dem Ende der letzten nichts", () => { const beendet = zeile({ valid_from: "2020-01-01", valid_to: "2024-01-01" }); expect(kontierungZum([beendet], "2024-01-01").has("p1")).toBe(false); expect(kontierungZum([beendet], "2023-12-31").has("p1")).toBe(true); }); it("hält mehrere Planstellen auseinander", () => { const andere = zeile({ position_id: "p2", cost_center_id: "k3", code: "21030" }); const karte = kontierungZum([alt, neu, andere], "2026-09-01"); expect(karte.get("p1")?.code).toBe("21090"); expect(karte.get("p2")?.code).toBe("21030"); }); it("kommt mit einer leeren Liste zurecht", () => { expect(kontierungZum([], "2026-09-01").size).toBe(0); }); }); // Eine Planstelle, die erst entsteht, wird erst mit ihrem Beginn kontiert. // Zu heute gefragt hätte sie keine Kostenstelle — und die Vakanzliste, die // künftige Stellen bewusst zeigt, stünde für genau diese ohne da. Das ist beim // Prüfen gegen die echten Daten aufgefallen, nicht beim Schreiben. describe("kontierungAm", () => { const kuenftig = zeile({ position_id: "p9", valid_from: "2027-01-01", code: "21030", name: "Logistik" }); it("liefert zum Beginn der Planstelle die Kostenstelle", () => { expect(kontierungAm([kuenftig], "p9", "2027-01-01")?.code).toBe("21030"); }); it("liefert davor nichts — sie gilt ja noch nicht", () => { expect(kontierungAm([kuenftig], "p9", "2026-08-16")).toBeNull(); }); it("verwechselt Planstellen nicht", () => { expect(kontierungAm([kuenftig], "p1", "2027-01-01")).toBeNull(); }); });