import type { CommandContext } from "@tailor-platform/erp-kit/core"; import type { Transaction } from "../generated/kysely-tailordb"; // The erp-kit Result discriminated union, narrowed to what this module reads — the same // `_approvalDeps.ts` trick leave-management uses, so the injected query's own error type does // not have to be nameable here. type Result = { ok: true; value: T } | { ok: false; error: { code: string } }; /** * Cross-module reads shiftSchedule needs, declared structurally rather than imported. * * shiftSchedule cannot see workforce's tables — its generated Kysely types cover its own schema * only — so "is this Assignment effective on the shift's date?" cannot be answered by a join. * Following the `_approvalDeps.ts` precedent in leave-management, the command takes the reader * as an injected function typed by the shape it uses, which keeps the module free of a compile * -time dependency on workforce while still enforcing the invariant server-side. */ export interface GetAssignmentDep { getAssignment: ( db: Transaction, input: { id: string }, ctx: CommandContext, ) => Promise>; } /** * An Assignment may staff a slot only on a date its generation actually covers. Effective dates * are whole days, so the comparison is on the date part: a generation starting on the 15th does * not cover the 1st, however the timestamps happen to be stored. */ export function isEffectiveOn( assignment: { effectiveStart: Date; effectiveEnd: Date | null }, date: Date, ): boolean { const day = (d: Date) => Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()); const on = day(date); return ( day(assignment.effectiveStart) <= on && (assignment.effectiveEnd == null || day(assignment.effectiveEnd) >= on) ); }