chore(repo): initialize planarchy workspace

This commit is contained in:
2026-03-14 14:31:09 +01:00
commit dd55d0e78b
769 changed files with 166461 additions and 0 deletions
@@ -0,0 +1,126 @@
import { describe, expect, it } from "vitest";
import {
calculateAllocation,
calculateTotalCost,
countWorkingDays,
isWorkday,
} from "../allocation/calculator.js";
const stdAvailability = {
monday: 8,
tuesday: 8,
wednesday: 8,
thursday: 8,
friday: 8,
};
describe("isWorkday", () => {
it("returns true for Monday", () => {
expect(isWorkday(new Date("2025-01-06"), stdAvailability)).toBe(true); // Monday
});
it("returns false for Saturday", () => {
expect(isWorkday(new Date("2025-01-04"), stdAvailability)).toBe(false); // Saturday
});
it("returns false for Sunday", () => {
expect(isWorkday(new Date("2025-01-05"), stdAvailability)).toBe(false); // Sunday
});
});
describe("countWorkingDays", () => {
it("counts 5 days in a Mon-Fri week", () => {
const start = new Date("2025-01-06"); // Monday
const end = new Date("2025-01-10"); // Friday
expect(countWorkingDays(start, end, stdAvailability)).toBe(5);
});
it("counts 10 days over two Mon-Fri weeks", () => {
const start = new Date("2025-01-06"); // Monday
const end = new Date("2025-01-17"); // Friday
expect(countWorkingDays(start, end, stdAvailability)).toBe(10);
});
it("counts 0 for a weekend-only range", () => {
const start = new Date("2025-01-04"); // Saturday
const end = new Date("2025-01-05"); // Sunday
expect(countWorkingDays(start, end, stdAvailability)).toBe(0);
});
it("counts same day as 1 if it's a workday", () => {
const day = new Date("2025-01-06"); // Monday
expect(countWorkingDays(day, day, stdAvailability)).toBe(1);
});
});
describe("calculateAllocation", () => {
it("calculates cost for a full week at 8h/day and 100 EUR/h (10000 cents)", () => {
const result = calculateAllocation({
lcrCents: 10000, // 100 EUR/h
hoursPerDay: 8,
startDate: new Date("2025-01-06"), // Monday
endDate: new Date("2025-01-10"), // Friday
availability: stdAvailability,
});
expect(result.workingDays).toBe(5);
expect(result.totalHours).toBe(40);
// 5 days × 8h × 10000 cents/h = 400000 cents = 4000 EUR
expect(result.totalCostCents).toBe(400000);
expect(result.dailyCostCents).toBe(80000);
expect(result.dailyBreakdown).toHaveLength(5);
});
it("skips weekend days in breakdown", () => {
const result = calculateAllocation({
lcrCents: 10000,
hoursPerDay: 8,
startDate: new Date("2025-01-04"), // Saturday
endDate: new Date("2025-01-12"), // Sunday
availability: stdAvailability,
});
expect(result.workingDays).toBe(5);
const weekendDays = result.dailyBreakdown.filter((d) => !d.isWorkday);
expect(weekendDays).toHaveLength(4); // 2 weekends
});
it("caps hours at available hours if requested > available", () => {
const limitedAvailability = { ...stdAvailability, monday: 4 };
const result = calculateAllocation({
lcrCents: 10000,
hoursPerDay: 8, // Requested more than available
startDate: new Date("2025-01-06"), // Monday only
endDate: new Date("2025-01-06"),
availability: limitedAvailability,
});
expect(result.totalHours).toBe(4); // Capped at availability
expect(result.totalCostCents).toBe(40000); // 4h × 10000 cents
});
it("returns zero for date range with no working days", () => {
const result = calculateAllocation({
lcrCents: 10000,
hoursPerDay: 8,
startDate: new Date("2025-01-04"), // Saturday
endDate: new Date("2025-01-05"), // Sunday
availability: stdAvailability,
});
expect(result.workingDays).toBe(0);
expect(result.totalHours).toBe(0);
expect(result.totalCostCents).toBe(0);
});
});
describe("calculateTotalCost", () => {
it("calculates correctly", () => {
// 10000 cents/h × 8h × 5 days = 400000 cents
expect(calculateTotalCost(10000, 8, 5)).toBe(400000);
});
it("returns 0 for 0 working days", () => {
expect(calculateTotalCost(10000, 8, 0)).toBe(0);
});
});