import type { TenantDb } from "@/server/db"; export type NumberKey = "customer" | "work_order" | "emergency" | "report"; const DEFAULT_PREFIX: Record = { customer: "K-", work_order: "A-", emergency: "N-", report: "B-", }; /** * Allocate the next number of a tenant sequence, e.g. "A-00042". * The increment is a single UPDATE … RETURNING (atomic); the very first call per key * creates the row and retries once if a concurrent call created it first. */ export async function nextNumber(db: TenantDb, tenantId: string, key: NumberKey): Promise { for (let attempt = 0; attempt < 3; attempt++) { const existing = await db.numberSequence.findFirst({ where: { tenantId, key }, select: { id: true } }); if (existing) { const seq = await db.numberSequence.update({ where: { id: existing.id }, data: { nextValue: { increment: 1 } }, }); return format(seq.prefix, seq.nextValue - 1, seq.padding); } try { const seq = await db.numberSequence.create({ data: { tenantId, key, prefix: DEFAULT_PREFIX[key], nextValue: 2 }, }); return format(seq.prefix, 1, seq.padding); } catch (err) { if ((err as { code?: string }).code !== "P2002") throw err; // unique race → retry via update path } } throw new Error(`could not allocate number for ${key}`); } function format(prefix: string, value: number, padding: number): string { return `${prefix}${String(value).padStart(padding, "0")}`; }