Zum Inhalt

Belegnummern je Workflow-Stufe

Ein Auftrag durchläuft Angebot, Auftragsbestätigung, Lieferschein und Rechnung. Ab Werk tragen alle vier dieselbe Nummer — die Auftragsnummer aus Auftrag → Nummer. Der Belegtyp entsteht allein aus der Workflow-Stufe des Status: derselbe Vorgang druckt sich als Angebot, wenn er auf „Angebot" steht, und als Rechnung, wenn er auf „Rechnung" steht.

Für viele Labore reicht das. Wer eine eigene Rechnungsnummer braucht — etwa weil die Buchhaltung einen lückenlosen, eigenen Rechnungsnummernkreis verlangt —, richtet ihn hier ein.

Was hier steht und was nicht

Diese Seite beschreibt den Weg über Statusregeln. Er kommt ohne Schemaänderung aus und läuft auf jeder Installation. Seine Grenzen stehen unten unter Was dieser Weg nicht kann — sie sind real, und sie gehören gelesen, bevor man den Rechnungsnummernkreis darauf umstellt.


Wie es funktioniert

Eine Statusregel (Administration → Statusverwaltung → Statusregeln) verbindet einen Status mit einem Feld und einer Vorgabe. Wechselt ein Auftrag in diesen Status, wird die Vorgabe aufgelöst und ins Feld geschrieben.

Drei Eigenschaften machen daraus einen brauchbaren Nummernkreis:

  • Der Zähler ist echt. [STATUS_COUNT] zieht den Zähler dieses Status, atomar reserviert. Zwei gleichzeitige Statuswechsel bekommen zwei verschiedene Nummern.
  • Vergeben wird einmal. Nur leere Felder werden gefüllt. Ein Rückschritt und erneuter Vorlauf vergibt keine zweite Nummer, und ein zweiter Klick auf denselben Status auch nicht.
  • Der Zeitpunkt ist der Statuswechsel, nicht der Druck. Ein dreimal gedrucktes Angebot hat dreimal dieselbe Nummer.

Die Werksvorgabe

Eine frisch installierte V1-kompatible Datenbank (db:install --v1) bringt vier Statusregeln mit:

Status Feld Vorlage Ergebnis
Angebot Angebotsnummer (W4102) AN-[YYYY]-[STATUS_COUNT\|0000] AN-2026-0001
Auftrag Auftragsnummer (W4103) AB-[YYYY]-[STATUS_COUNT\|0000] AB-2026-0001
Lieferung Liefernummer (W4104) LS-[YYYY]-[STATUS_COUNT\|0000] LS-2026-0001
Rechnung Rechnungsnummer (W4105) RE-[YYYY]-[STATUS_COUNT\|0000] RE-2026-0001

Die Vorgangsnummer (Nummer) bleibt daneben bestehen und ändert sich nicht. Sie identifiziert den Vorgang, die Belegnummern identifizieren die Belege.

Bestandsinstallationen bekommen diese Regeln nicht

Ein Update legt sie nicht an. Wer heute seine Rechnungsnummer über die Auftragsnummer führt, soll das nicht dadurch verlieren, dass er eine neue Version einspielt — die Umstellung ist eine Entscheidung, keine Nebenwirkung. Der nächste Abschnitt beschreibt sie.

Kein [STATUS_SHORT] in den Vorlagen

Naheliegend wäre [STATUS_SHORT]-[YYYY]-[STATUS_COUNT]. Das geht schief: die ausgelieferten Buchungsstatus tragen als Kürzel „AB" für Angebot und gar nichts für Auftrag. Das Angebot bekäme AB-2026-0001, der Auftrag -2026-0001. Die Belegart steht fest, also steht auch ihr Kürzel fest — deshalb ausgeschriebene Präfixe.


Selbst einrichten

Am Beispiel der Rechnungsnummer.

1. Statusregel anlegen. Administration → Statusverwaltung → Statusregeln, Status Rechnung wählen, Feld Rechnungsnummer (W4105), Vorgabewert:

RE-[YYYY]-[STATUS_COUNT|0000]

2. Zählerstand setzen. Administration → Nummernkreise, Zeile des Rechnungsstatus. Läuft schon eine Rechnungsserie, den Zähler auf die zuletzt vergebene Nummer setzen — sonst beginnt der Kreis bei 1 und kollidiert mit dem Bestand.

3. Rücksetz-Rhythmus wählen. In derselben Zeile. Die Vorlage muss unterscheiden können, was der Rhythmus trennt: ein monatlicher Reset verlangt [YYYY][MM] in der Vorlage, sonst entsteht RE-2026-0001 im Januar und im Februar. Die Prüfung meldet das als reset_finer_than_template, bevor gespeichert wird.

4. Die Rechnungsnummer zur BT-1 machen. Ohne diesen Schritt trägt die E-Rechnung weiterhin die Auftragsnummer. Administration → Berichtsverwaltung → Variablen, für den Berichtstyp des Auftragsbelegs:

Variable Wert
zugferd_invoice_number_field W4105

Ab dann gilt für BT-1 der Inhalt dieses Feldes — auch wenn er leer ist. Das ist Absicht: ein stiller Rückfall auf die Auftragsnummer erzeugte eine formal gültige Rechnung mit einer Nummer, die der Buchhaltung nichts sagt. Ein leeres Feld wird stattdessen zum sichtbaren Fehler.


Vorlagen-Bausteine

Token Ergibt
[YYYY] / [YY] Jahr, vierstellig / zweistellig
[MM] / [DD] Monat / Tag
[STATUS_COUNT] Zähler dieses Status, atomar hochgezählt
[STATUS_COUNT\|0000] derselbe Zähler, auf vier Stellen aufgefüllt
[STATUS_NAME] / [STATUS_SHORT] Titel / Kürzel des Status
[GLOBAL_COUNTER_1] … globaler Zähler aus den Grundeinstellungen

Zum Padding: |0000 ist eine Lesehilfe, keine Grenze. Die 10 000. Rechnung wird fünfstellig statt abgeschnitten — eine verstümmelte Nummer wäre der schlechtere Tausch.

Nicht denselben globalen Zähler nehmen

counter_1 ziehen bereits die Auftragsnummer und die Kalibrierscheinnummer. Eine Belegnummer daraus springt, sobald irgendwo eine Kalibrierung entsteht. Statuszähler sind je Status getrennt und deshalb der richtige Ort.


Was geprüft wird

Beim Speichern einer Vorlage — an jedem Weg, auch über das MCP-Werkzeug und den Kategorie-Paket-Import:

Meldung Bedeutung
unbalanced_brackets Fehler. Klammern passen nicht zusammen; wird abgelehnt.
no_counter Kein Zähler-Token — jede Nummer fiele identisch aus.
multiple_counters Mehrere Zähler in einer Vorlage: mehrdeutig beim Rückwärtslesen.
counter_adjacent_digit Ziffer direkt am Zähler: RE1 + 2 liest sich wie RE + 12. Feste Breite trennt sie.
reset_finer_than_template Der Zähler setzt öfter zurück, als die Vorlage unterscheidet.
empty_now_on_number Fehler. „Jetzt leeren" auf der Vorgangsnummer; wird abgelehnt.

Zur letzten Zeile: Die Vorgangsnummer identifiziert den Vorgang und darf in der Datenbank nicht leer sein. Sie beim Statuswechsel zu leeren, um „Platz für eine neue Nummer" zu schaffen, endet in einem Speicherfehler an der Spalte — weit weg von der Regel, die ihn verursacht hat.


Was dieser Weg nicht kann

Ehrliche Grenzen. Sie folgen daraus, dass die Nummer in einem Feld steht und nicht in einem eigenen Belegjournal:

  • Keine Kollisionsprüfung. Die Belegnummern liegen in custom_fields. Die Eindeutigkeitsprüfung, die es für Spalten gibt, greift dort nicht — eine doppelte Rechnungsnummer würde gespeichert.
  • Kein Dubletten-Bericht. Es gibt keine Auswertung, die zwei gleiche Rechnungsnummern findet.
  • Eine Nummer je Belegart und Auftrag. Bei Teilrechnungen trägt jede dieselbe Nummer, denn es gibt nur ein Feld. Wer Teilrechnungen stellt, sollte diesen Weg für die Rechnungsnummer nicht nutzen.
  • Nur der Leitstatus vergibt. Führt die Installation zwei Status derselben Stufe („Rechnung" und „Rechnung gestellt"), bekommt nur einer die Regel. Zwei Regeln mit demselben Präfix hätten zwei Zähler — und dieselbe Nummer käme zweimal heraus.
  • Übersprungene Stufen bleiben leer. Geht ein Auftrag direkt von „Auftrag" auf „Rechnung", bleibt die Liefernummer leer. Das ist gewollt: eine Lieferscheinnummer für einen Lieferschein, den es nie gab, wäre eine Lüge im Nummernkreis.

Die Feldverwaltung kann die Basis-Vorlage zurückholen

Die vier Belegfelder haben keine Vorgabe auf Basis-Ebene mehr — sie zöge sonst beim Anlegen des Auftrags, also bevor es einen Beleg gibt.

Wird ein solches Feld in der Feldverwaltung bearbeitet und gespeichert, schreibt der Abgleich mit der V1-Feldkonfiguration die dort hinterlegte Vorgabe zurück. Danach zieht das Feld wieder beim Anlegen. Erkennbar daran, dass neue Aufträge sofort eine Rechnungsnummer tragen. Abhilfe bis auf Weiteres: die Basis-Vorgabe des Feldes in der Feldverwaltung wieder leeren.


Prüfen, ob es läuft

docker exec calserver-api-v2 php artisan tinker
// Welche Statusregeln vergeben Nummern?
DB::table('additional_field')
    ->where('type', 'status')
    ->whereNotNull('default_value')
    ->where('default_value', '!=', '')
    ->get(['object_uID', 'column_name', 'default_value']);

// Zählerstände der Buchungsstatus
DB::table('status')
    ->where('type', 'booking')
    ->orderBy('sort_order')
    ->get(['title', 'short_title', 'counter', 'counter_reset']);

Ein Auftrag, den man über die Stufen schiebt, muss danach vier verschiedene Nummern tragen — und beim zweiten Durchlauf durch dieselbe Stufe keine neue bekommen.