Gutschrift: separater Lieferschein-Nummernkreis (GoBD, luecken-frei)
Pentester R142: Uebergang Geld->betragsloser Sachwert setzte die schon vergebene Gutschriftsnummer auf null -> Luecke in der GS-Serie. Loesung: betragsloser Sachwert = Lieferschein mit eigener Lieferscheinnummer aus separatem Nummernkreis. - Schema: CreditNote.deliveryNoteNumber (nullbar, unique) + neues Model DeliveryNoteNumberRange (Default-Praefix 'LS-') + Migration. - deliveryNoteNumberRange.service (mirror, eigener Zaehler, FOR UPDATE). - Nummern lazy pro Serie, NIE freigeben: Uebergaenge behalten die jeweils vergebene Nummer der anderen Serie reserviert -> kein Doppelverbrauch, keine Luecke. effectiveNumber() liefert je nach Typ die passende (LS/GS) fuer Anzeige/PDF/Audit. - Endpunkte GET/PUT /credit-notes/delivery-note-number-range; Settings- Seite verwaltet jetzt beide Nummernkreise. PDF-Titel 'Sachwert- Uebergabe', Dateiname lieferschein-... - Frontend: Typ + displayNumber in Liste/Modal. Verifiziert: Sachwert 0 -> LS-Nr, GS-Zaehler unberuehrt; Geld -> GS-Nr; Uebergaenge behalten beide Nummern (kein Neuverbrauch, keine Luecke). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
-- Lieferschein-Nummerierung fuer betragslose Sachwert-Uebergaben:
|
||||
-- eigene Nummer am Beleg + eigener Nummernkreis (getrennt von Gutschriften).
|
||||
|
||||
ALTER TABLE `CreditNote` ADD COLUMN IF NOT EXISTS `deliveryNoteNumber` VARCHAR(191) NULL;
|
||||
|
||||
-- UNIQUE-Index auf deliveryNoteNumber (idempotent).
|
||||
SET @idx := (SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'CreditNote'
|
||||
AND INDEX_NAME = 'CreditNote_deliveryNoteNumber_key');
|
||||
SET @sql := IF(@idx = 0,
|
||||
'CREATE UNIQUE INDEX `CreditNote_deliveryNoteNumber_key` ON `CreditNote`(`deliveryNoteNumber`)',
|
||||
'SELECT 1');
|
||||
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `DeliveryNoteNumberRange` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`prefix` VARCHAR(191) NOT NULL DEFAULT 'LS-',
|
||||
`includeYear` BOOLEAN NOT NULL DEFAULT true,
|
||||
`separator` VARCHAR(191) NOT NULL DEFAULT '-',
|
||||
`padding` INT NOT NULL DEFAULT 4,
|
||||
`nextNumber` INT NOT NULL DEFAULT 1,
|
||||
`resetYearly` BOOLEAN NOT NULL DEFAULT true,
|
||||
`currentYear` INT NULL,
|
||||
`updatedAt` DATETIME(3) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
@@ -984,10 +984,14 @@ model CreditNote {
|
||||
contractId Int
|
||||
contract Contract @relation(fields: [contractId], references: [id], onDelete: Cascade)
|
||||
|
||||
// Gutschrift-Nummer aus dem Nummernkreis (z.B. GS-2026-0001). NULL bei
|
||||
// betragslosen Sachwert-Übergaben – die sind eher ein Lieferschein und
|
||||
// verbrauchen bewusst KEINE Gutschriftsnummer (Zähler bleibt unangetastet).
|
||||
// Gutschrift-Nummer aus dem Gutschrift-Nummernkreis (z.B. GS-2026-0001).
|
||||
// NULL bei betragslosen Sachwert-Übergaben (= Lieferschein, s.u.).
|
||||
number String? @unique
|
||||
// Lieferschein-/Subventionsnummer aus dem separaten Lieferschein-
|
||||
// Nummernkreis (z.B. LS-2026-0001) – nur bei betragslosen Sachwerten.
|
||||
// Beide Nummern werden lazy pro Serie vergeben und NIE wieder freigegeben
|
||||
// (keine Lücken); angezeigt wird je nach aktuellem Typ die passende.
|
||||
deliveryNoteNumber String? @unique
|
||||
|
||||
type CreditNoteType
|
||||
// Pflicht bei SACHWERT: was wird gewährt (z.B. "Smartphone Samsung A55").
|
||||
@@ -1071,6 +1075,20 @@ model CreditNoteNumberRange {
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
// Separater Nummernkreis für Lieferscheine (betragslose Sachwert-Übergaben).
|
||||
// Eigene Serie, damit die Gutschrift-Nummerierung sauber/lückenlos bleibt.
|
||||
model DeliveryNoteNumberRange {
|
||||
id Int @id @default(autoincrement())
|
||||
prefix String @default("LS-")
|
||||
includeYear Boolean @default(true)
|
||||
separator String @default("-")
|
||||
padding Int @default(4)
|
||||
nextNumber Int @default(1)
|
||||
resetYearly Boolean @default(true)
|
||||
currentYear Int?
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
// ==================== INTERNET CONTRACT DETAILS ====================
|
||||
|
||||
model InternetContractDetails {
|
||||
|
||||
Reference in New Issue
Block a user