import { describe, expect, it } from "vitest"; import { AllocationStatus, type AllocationWithDetails } from "@nexus/shared"; import { buildAllocationReadModel } from "../index.js"; function makeAllocation(overrides: Partial): AllocationWithDetails { return { id: "alloc_1", resourceId: "res_1", projectId: "proj_1", startDate: new Date("2026-03-01T00:00:00.000Z"), endDate: new Date("2026-03-05T00:00:00.000Z"), hoursPerDay: 8, percentage: 100, role: "Compositor", roleId: "role_1", isPlaceholder: false, headcount: 1, dailyCostCents: 12_000, status: AllocationStatus.PROPOSED, metadata: {}, createdAt: new Date("2026-03-01T00:00:00.000Z"), updatedAt: new Date("2026-03-01T00:00:00.000Z"), resource: { id: "res_1", displayName: "Alice", eid: "E-001", lcrCents: 15_000, }, project: { id: "proj_1", name: "Project One", shortCode: "P1", status: "ACTIVE", endDate: new Date("2026-03-31T00:00:00.000Z"), }, roleEntity: { id: "role_1", name: "Compositor", color: "#111111", }, ...overrides, }; } describe("allocation read model", () => { it("splits assignments from placeholder demand rows", () => { const input: AllocationWithDetails[] = [ makeAllocation({ id: "assign_1" }), makeAllocation({ id: "demand_1", resourceId: null, isPlaceholder: true, headcount: 3, dailyCostCents: 0, resource: null, }), ]; const result = buildAllocationReadModel(input); expect(result.allocations).toHaveLength(2); expect(result.assignments).toHaveLength(1); expect(result.demands).toHaveLength(1); expect(result.assignments[0]).toMatchObject({ id: "assign_1", kind: "assignment", sourceAllocationId: "assign_1", resourceId: "res_1", isPlaceholder: false, }); expect(result.demands[0]).toMatchObject({ id: "demand_1", kind: "demand", sourceAllocationId: "demand_1", resourceId: null, isPlaceholder: true, requestedHeadcount: 3, unfilledHeadcount: 3, }); }); it("treats null-resource rows as demand for legacy safety", () => { const input: AllocationWithDetails[] = [ makeAllocation({ id: "legacy_1", resourceId: null, isPlaceholder: false, headcount: 2, dailyCostCents: 0, resource: null, }), ]; const result = buildAllocationReadModel(input); expect(result.assignments).toEqual([]); expect(result.demands).toHaveLength(1); expect(result.demands[0]?.sourceAllocationId).toBe("legacy_1"); }); });