// ==================== LIEFERSCHEIN-NUMMERNKREIS ==================== // Separater Nummernkreis für Lieferscheine (betragslose Sachwert-Übergaben), // getrennt von den Gutschriften. Gleiche transaktionale Vergabe (Row-Lock via // SELECT ... FOR UPDATE), damit keine Doppelvergaben/Lücken entstehen. import prisma from '../lib/prisma.js'; import { Prisma } from '@prisma/client'; import type { NumberRangeConfig } from './creditNoteNumberRange.service.js'; export async function getOrCreateRange() { const existing = await prisma.deliveryNoteNumberRange.findFirst(); if (existing) return existing; return prisma.deliveryNoteNumberRange.create({ data: {} }); } export async function updateRange(input: Partial) { const range = await getOrCreateRange(); const data: Prisma.DeliveryNoteNumberRangeUpdateInput = {}; if (typeof input.prefix === 'string') data.prefix = input.prefix.slice(0, 40); if (typeof input.includeYear === 'boolean') data.includeYear = input.includeYear; if (typeof input.separator === 'string') data.separator = input.separator.slice(0, 5); if (typeof input.padding === 'number' && Number.isInteger(input.padding)) { data.padding = Math.min(Math.max(input.padding, 1), 10); } if (typeof input.resetYearly === 'boolean') data.resetYearly = input.resetYearly; if (typeof input.nextNumber === 'number' && Number.isInteger(input.nextNumber) && input.nextNumber >= 1) { data.nextNumber = input.nextNumber; } return prisma.deliveryNoteNumberRange.update({ where: { id: range.id }, data }); } function formatNumber(cfg: { prefix: string; includeYear: boolean; separator: string; padding: number; }, value: number, year: number): string { const padded = String(value).padStart(cfg.padding, '0'); const yearPart = cfg.includeYear ? `${year}${cfg.separator}` : ''; return `${cfg.prefix}${yearPart}${padded}`; } export async function previewNextNumber(): Promise { const range = await getOrCreateRange(); const year = new Date().getFullYear(); const value = range.resetYearly && range.currentYear !== year ? 1 : range.nextNumber; return formatNumber(range, value, year); } export async function assignNextNumber(): Promise { await getOrCreateRange(); return prisma.$transaction(async (tx) => { const rows = await tx.$queryRaw>(Prisma.sql`SELECT * FROM DeliveryNoteNumberRange ORDER BY id ASC LIMIT 1 FOR UPDATE`); const row = rows[0]; const year = new Date().getFullYear(); const resetYearly = !!row.resetYearly; const value = resetYearly && row.currentYear !== year ? 1 : row.nextNumber; const number = formatNumber( { prefix: row.prefix, includeYear: !!row.includeYear, separator: row.separator, padding: row.padding, }, value, year, ); await tx.deliveryNoteNumberRange.update({ where: { id: row.id }, data: { nextNumber: value + 1, currentYear: year }, }); return number; }); }