import type { CommandContext } from "@tailor-platform/erp-kit/core"; import type { Transaction } from "../generated/kysely-tailordb"; import type { ReportedSpanInput } from "./_timeCalculation"; import type { Schema, WorkRule } from "./types"; /** A categorized span produced by a classification strategy. */ export interface ClassifiedSpan { /** Category key stored on CalculatedTimeBlock.category (strategy-defined vocabulary). */ category: string; /** Category key used to bind a TimeEntryCode / premium pin (strategy-defined vocabulary). */ codeCategory: string; startAt: Date; endAt: Date; minutes: number; calculationTagKeys: string[]; sourceReportedBlockIds: string[]; } export interface ClassifyInput { assignmentId: string; workDate: Date; reportedBlocks: ReportedSpanInput[]; workRule: WorkRule; holidayKind: "STATUTORY" | "PRESCRIBED" | null; } /** * Pluggable, per-jurisdiction time-classification strategy. The core resolves the effective * WorkRule, the holiday (scoped to the rule's calendar), and the current ReportedTimeBlocks, * then delegates categorization + premium stacking to the strategy. The core owns no period * or week concept: a strategy that needs period context (e.g. US FLSA weekly overtime) queries * it itself through the passed transaction. The core then binds each returned span to a * TimeEntryCode by its `codeCategory` and stores its `category`. */ export interface TimeClassificationStrategy { classify( db: Transaction, input: ClassifyInput, ctx: CommandContext, ): ClassifiedSpan[] | Promise; /** * The set of workdays that must be re-derived together when `workDate` changes. A daily strategy * (the JP default) classifies each day independently, so a change to one day affects only that day * and this may be omitted (the core recalculates just the changed day). A strategy that aggregates * across a period — e.g. US FLSA weekly overtime, where moving hours on one day shifts the * overtime allocation across the whole week — must return every workday in that period so the core * re-derives the neighbours too; otherwise their CalculatedTimeBlocks go stale after a single-day * reported-block write. Must include `workDate` itself. */ recalculationWindow?( db: Transaction, input: { assignmentId: string; workDate: Date }, ctx: CommandContext, ): Date[] | Promise; }