import type { Transaction } from "../generated/kysely-tailordb"; /** * Shared APPROVED→LOCKED transition primitive used by both lockTimecard (single-card * relock after a LOCKED correction) and closeTimecardPeriod (period bulk close). * * Sets status=LOCKED and stamps lockedAt/lockedBy so the close event is attributed. * The `WHERE status='APPROVED'` guard is belt-and-braces: callers already pre-check the * status under a forUpdate lock, but this keeps a concurrent transition from re-locking * a card that has since left APPROVED. Runs inside the caller's transaction (db is trx). * * A single `now` is passed by the caller (or defaulted here) so every card locked in one * close carries the same lockedAt instant. Returns the updated rows via returningAll. */ export async function lockApprovedTimecards( db: Transaction, ids: string[], actorId: string, now: Date = new Date(), ) { return db .updateTable("Timecard") .set({ status: "LOCKED", lockedAt: now, lockedBy: actorId }) .where("id", "in", ids) .where("status", "=", "APPROVED") .returningAll() .execute(); }