feat(drafts): DB drafts with deferred numbering — create-as-draft (no number), assign number on finalize (offers/invoices/issued-orders)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -413,6 +413,76 @@ export async function previewIssuedOrderNumber(
|
||||
return { number, next_number: number };
|
||||
}
|
||||
|
||||
/**
|
||||
* Deferred-assign helpers — used when a draft (number-less) document is
|
||||
* finalized. Each runs inside a transaction (the caller's `tx` if provided,
|
||||
* otherwise a fresh `prisma.$transaction`), reads the row's current number, and:
|
||||
* - if it is already set (non-null/non-empty), returns it unchanged
|
||||
* (idempotent — finalizing twice never re-numbers / double-consumes); else
|
||||
* - calls the existing per-type generator (which consumes the sequence under
|
||||
* the same row lock) and writes the number onto the row.
|
||||
* The sequence is consumed exactly once, atomically with the row write.
|
||||
*/
|
||||
export async function assignOfferNumber(
|
||||
id: number,
|
||||
tx?: TxClient,
|
||||
): Promise<string> {
|
||||
const run = async (client: TxClient): Promise<string> => {
|
||||
const row = await client.quotations.findUnique({
|
||||
where: { id },
|
||||
select: { quotation_number: true },
|
||||
});
|
||||
if (row?.quotation_number) return row.quotation_number;
|
||||
const number = await generateOfferNumber(client);
|
||||
await client.quotations.update({
|
||||
where: { id },
|
||||
data: { quotation_number: number },
|
||||
});
|
||||
return number;
|
||||
};
|
||||
return tx ? run(tx) : prisma.$transaction(run);
|
||||
}
|
||||
|
||||
export async function assignInvoiceNumber(
|
||||
id: number,
|
||||
tx?: TxClient,
|
||||
): Promise<string> {
|
||||
const run = async (client: TxClient): Promise<string> => {
|
||||
const row = await client.invoices.findUnique({
|
||||
where: { id },
|
||||
select: { invoice_number: true },
|
||||
});
|
||||
if (row?.invoice_number) return row.invoice_number;
|
||||
const { number } = await generateInvoiceNumber(undefined, client);
|
||||
await client.invoices.update({
|
||||
where: { id },
|
||||
data: { invoice_number: number },
|
||||
});
|
||||
return number;
|
||||
};
|
||||
return tx ? run(tx) : prisma.$transaction(run);
|
||||
}
|
||||
|
||||
export async function assignIssuedOrderNumber(
|
||||
id: number,
|
||||
tx?: TxClient,
|
||||
): Promise<string> {
|
||||
const run = async (client: TxClient): Promise<string> => {
|
||||
const row = await client.issued_orders.findUnique({
|
||||
where: { id },
|
||||
select: { po_number: true },
|
||||
});
|
||||
if (row?.po_number) return row.po_number;
|
||||
const { number } = await generateIssuedOrderNumber(undefined, client);
|
||||
await client.issued_orders.update({
|
||||
where: { id },
|
||||
data: { po_number: number },
|
||||
});
|
||||
return number;
|
||||
};
|
||||
return tx ? run(tx) : prisma.$transaction(run);
|
||||
}
|
||||
|
||||
/** Release an issued-order number back to the pool (decrement if highest). */
|
||||
export async function releaseIssuedOrderNumber(
|
||||
year?: number,
|
||||
|
||||
Reference in New Issue
Block a user