Files
ApiCore/ApiCore-Backend/src/automation/number-format.ts
T
Nick SzaunigandClaude Opus 5.5 cfd3a187af
Backend Image / build-and-push (push) Successful in 2m15s
Frontend Image / build-and-push (push) Successful in 2m3s
feat(automation): separate lot number counters per raw material kind
With {ART} in the raw material number format (default {ART}-{YYYY}-{SEQ:4}),
beeswax and propolis each count on their own: WA-2026-0001, PR-2026-0001.
Counters live in the new AutomationSequence table (one row per rule and
scope). Without {ART} the rule keeps its single shared counter, since
separate counters behind one prefix would hand out duplicate numbers.
Resetting a rule clears all of its counters.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-07 19:33:10 +02:00

42 lines
1.6 KiB
TypeScript

// Far beyond any realistic business use (sequence numbers are a handful of
// digits) but small enough that padStart can never be tricked into
// allocating a pathologically large string - {SEQ:999999999} in a
// carelessly typed format would otherwise try to build a ~1GB string on
// every single batch/bottling creation from then on.
const MAX_SEQUENCE_PAD_WIDTH = 20;
// Placeholders: {YYYY} 4-digit year, {YY} 2-digit year, {MM} month (01-12),
// {DD} day (01-31), {SEQ} running sequence unpadded, {SEQ:N} sequence
// zero-padded to N digits. Example matching the lastenheft's own sample
// ("WH-2026-0001"): format "WH-{YYYY}-{SEQ:4}".
// `vars` fills rule-specific placeholders, e.g. { ART: 'WA' } for {ART} in
// the raw material format; a placeholder without a value stays as typed.
export function formatGeneratedNumber(
format: string,
sequence: number,
date: Date,
vars: Record<string, string> = {},
): string {
const yyyy = String(date.getFullYear());
const yy = yyyy.slice(-2);
const mm = String(date.getMonth() + 1).padStart(2, '0');
const dd = String(date.getDate()).padStart(2, '0');
const withVars = Object.entries(vars).reduce(
(result, [key, value]) => result.split(`{${key}}`).join(value),
format,
);
return withVars
.replace(/\{YYYY\}/g, yyyy)
.replace(/\{YY\}/g, yy)
.replace(/\{MM\}/g, mm)
.replace(/\{DD\}/g, dd)
.replace(/\{SEQ:(\d+)\}/g, (_match, width: string) =>
String(sequence).padStart(
Math.min(Number(width), MAX_SEQUENCE_PAD_WIDTH),
'0',
),
)
.replace(/\{SEQ\}/g, String(sequence));
}