import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/core"; import type { Transaction } from "../generated/kysely-tailordb"; import { ShiftNotFoundError, ShiftAlreadyCancelledError } from "../lib/errors.generated"; export interface CancelShiftInput { id: string; } /** * Function: cancelShift * Description: Withdraws a single slot by stamping `cancelledAt`, the one thing a shift-schedule-level * status cannot express ("the period is confirmed but this one night shift is no longer needed"). * The row is kept rather than deleted, for the same reason a ShiftPlacement is superseded * rather than removed: a confirmed shiftSchedule is read back through its history. */ export async function run(db: Transaction, input: CancelShiftInput, _ctx: CommandContext) { const shift = await db .selectFrom("Shift") .selectAll() .where("id", "=", input.id) .forUpdate() .executeTakeFirst(); if (!shift) { return err(new ShiftNotFoundError(input.id)); } if (shift.cancelledAt !== null) { return err(new ShiftAlreadyCancelledError(input.id)); } const updated = await db .updateTable("Shift") .set({ cancelledAt: new Date() }) .where("id", "=", input.id) .returningAll() .executeTakeFirstOrThrow(); return ok({ shift: updated }); }