refactor(api): extract timeline cost load support
This commit is contained in:
@@ -1,88 +1,75 @@
|
||||
import { VacationType } from "@capakraken/db";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
const { calculateAllocationMock } = vi.hoisted(() => ({
|
||||
calculateAllocationMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@capakraken/engine", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("@capakraken/engine")>();
|
||||
return {
|
||||
...actual,
|
||||
calculateAllocation: calculateAllocationMock,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../router/timeline-cost-load-support.js", () => ({
|
||||
buildTimelineAbsenceDays: vi.fn(),
|
||||
loadTimelineCalculationRules: vi.fn(),
|
||||
}));
|
||||
|
||||
import {
|
||||
buildTimelineAbsenceDays,
|
||||
loadTimelineCalculationRules,
|
||||
} from "../router/timeline-cost-support.js";
|
||||
} from "../router/timeline-cost-load-support.js";
|
||||
import { calculateTimelineAllocationDailyCost } from "../router/timeline-cost-support.js";
|
||||
|
||||
const buildTimelineAbsenceDaysMock = vi.mocked(buildTimelineAbsenceDays);
|
||||
const loadTimelineCalculationRulesMock = vi.mocked(loadTimelineCalculationRules);
|
||||
|
||||
describe("timeline cost support", () => {
|
||||
it("falls back to default calculation rules when the optional model is unavailable", async () => {
|
||||
const rules = await loadTimelineCalculationRules({
|
||||
vacation: {
|
||||
findMany: async () => [],
|
||||
},
|
||||
} as never);
|
||||
|
||||
expect(rules.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("expands approved vacations, sickness, and public holidays into absence days", async () => {
|
||||
const result = await buildTimelineAbsenceDays({
|
||||
vacation: {
|
||||
findMany: async () => [
|
||||
{
|
||||
startDate: new Date("2026-04-03T00:00:00.000Z"),
|
||||
endDate: new Date("2026-04-04T00:00:00.000Z"),
|
||||
type: VacationType.VACATION,
|
||||
isHalfDay: false,
|
||||
},
|
||||
{
|
||||
startDate: new Date("2026-04-05T00:00:00.000Z"),
|
||||
endDate: new Date("2026-04-05T00:00:00.000Z"),
|
||||
type: VacationType.SICK,
|
||||
isHalfDay: true,
|
||||
},
|
||||
{
|
||||
startDate: new Date("2026-04-06T00:00:00.000Z"),
|
||||
endDate: new Date("2026-04-06T00:00:00.000Z"),
|
||||
type: VacationType.PUBLIC_HOLIDAY,
|
||||
isHalfDay: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
} as never, "resource_1", new Date("2026-04-01T00:00:00.000Z"), new Date("2026-04-10T00:00:00.000Z"));
|
||||
|
||||
expect(result.absenceDays).toEqual([
|
||||
{
|
||||
date: new Date("2026-04-03T00:00:00.000Z"),
|
||||
type: "VACATION",
|
||||
},
|
||||
{
|
||||
date: new Date("2026-04-04T00:00:00.000Z"),
|
||||
type: "VACATION",
|
||||
},
|
||||
{
|
||||
date: new Date("2026-04-05T00:00:00.000Z"),
|
||||
type: "SICK",
|
||||
isHalfDay: true,
|
||||
},
|
||||
{
|
||||
date: new Date("2026-04-06T00:00:00.000Z"),
|
||||
type: "PUBLIC_HOLIDAY",
|
||||
},
|
||||
]);
|
||||
expect(result.legacyVacationDates).toEqual([
|
||||
new Date("2026-04-03T00:00:00.000Z"),
|
||||
new Date("2026-04-04T00:00:00.000Z"),
|
||||
]);
|
||||
});
|
||||
|
||||
it("treats missing optional vacation tables as no absences", async () => {
|
||||
const result = await buildTimelineAbsenceDays({
|
||||
vacation: {
|
||||
findMany: async () => {
|
||||
throw {
|
||||
code: "P2021",
|
||||
message: "The table `vacations` does not exist.",
|
||||
meta: { table: "vacations" },
|
||||
};
|
||||
},
|
||||
},
|
||||
} as never, "resource_1", new Date("2026-04-01T00:00:00.000Z"), new Date("2026-04-10T00:00:00.000Z"));
|
||||
|
||||
expect(result).toEqual({
|
||||
absenceDays: [],
|
||||
legacyVacationDates: [],
|
||||
it("builds timeline allocation daily cost from loaded absences and rules", async () => {
|
||||
buildTimelineAbsenceDaysMock.mockResolvedValueOnce({
|
||||
absenceDays: [{ date: new Date("2026-04-03T00:00:00.000Z"), type: "VACATION" }],
|
||||
legacyVacationDates: [new Date("2026-04-03T00:00:00.000Z")],
|
||||
});
|
||||
loadTimelineCalculationRulesMock.mockResolvedValueOnce([{ id: "rule_1" }] as never);
|
||||
calculateAllocationMock.mockReturnValueOnce({ dailyCostCents: 54_321 });
|
||||
|
||||
await expect(
|
||||
calculateTimelineAllocationDailyCost({
|
||||
db: {} as never,
|
||||
resourceId: "resource_1",
|
||||
lcrCents: 5_000,
|
||||
hoursPerDay: 8,
|
||||
startDate: new Date("2026-04-01T00:00:00.000Z"),
|
||||
endDate: new Date("2026-04-10T00:00:00.000Z"),
|
||||
availability: {
|
||||
monday: 8,
|
||||
tuesday: 8,
|
||||
wednesday: 8,
|
||||
thursday: 8,
|
||||
friday: 8,
|
||||
} as never,
|
||||
includeSaturday: true,
|
||||
}),
|
||||
).resolves.toBe(54_321);
|
||||
|
||||
expect(buildTimelineAbsenceDaysMock).toHaveBeenCalledWith(
|
||||
{},
|
||||
"resource_1",
|
||||
new Date("2026-04-01T00:00:00.000Z"),
|
||||
new Date("2026-04-10T00:00:00.000Z"),
|
||||
);
|
||||
expect(loadTimelineCalculationRulesMock).toHaveBeenCalledWith({});
|
||||
expect(calculateAllocationMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
lcrCents: 5_000,
|
||||
hoursPerDay: 8,
|
||||
includeSaturday: true,
|
||||
vacationDates: [new Date("2026-04-03T00:00:00.000Z")],
|
||||
absenceDays: [{ date: new Date("2026-04-03T00:00:00.000Z"), type: "VACATION" }],
|
||||
calculationRules: [{ id: "rule_1" }],
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user