Rechnung speichern — Ablauf und Regeln
Die Schritte beim Anlegen und Ändern einer Rechnung: Kontingent, Validierung, Dublettenprüfung, Belegblock-Sperre, gemeinsamer Einfügeweg, Rücklesen und Berechtigungen.
Das Speichern einer Rechnung läuft über einen Endpunkt (finance/invoice.save); die invoice_id entscheidet zwischen Anlage und Änderung. Jede Anlage nutzt den gemeinsamen Weg addInvoice().
Datenmodell
Die Tabellennamen tragen in der Datenbank das eigene Präfix der Installation.
| Tabelle | Rolle |
|---|---|
invoice, invoice_item | Kopf und Positionen (schreibt Dlbtinvoice::add()) |
invoice_retention | Einbehaltszeilen (saveRetentions()) |
| Belegblock-Tabellen | über das Modell masterdata/invoice_block, mit Nummernsperre |
allocation, label_link | Analytik und Labels (bei Änderung) |
Ablauf der Anlage
- Recht:
canSave(route, 0)— fehlt der Schlüsseladdim Funktionsstamm, entscheidetedit; der Eigentümer (company_client_id) muss im Bereich liegen (ownerInScope). - Kontingent:
dlbtquota->checkAction(user, route, 'add', 1); die Zuständeneed_credit/need_planführen zu einem Fehler (error_quota_*). - Feldvalidierung, Dublettensuche (
findDuplicateInvoice; eigene Meldung für eine Dublette im Papierkorb), bei Storno-/Korrekturrechnungen ist die referenzierte Rechnung Pflicht und muss existieren, Aufrechnungsprüfung (checkOffsetInvoice), Einbehaltsgrenze. - Bei eigener nummerierter Ausgangsrechnung: Sperre des Nummernkreises (
lockSeries), Nummernbildung, Prüfung der Datumsreihenfolge. addInvoice($post), danach Rücklesen (getInvoice); fehlt die Rechnung:error_not_created, die Nummer wird nicht verbraucht.commitSeriesSeq, Rechnungstyp setzen (applyKind()), Kontingent verbrauchen (consumeAction()), Einbehalte speichern, Protokoll.- Die Antwort liefert die neue
invoice_id; es gibt keine Weiterleitung.
Änderung
Gleiche Validierung; ist die Rechnung nummeriert/abgeschlossen (getSeriesLock()['numbered']), folgt error_invoice_finalized. Sonst editInvoice($id, $post): vollständiger Austausch von Kopf und Positionen, Neuberechnung in der Bibliothek, applyKind(), Einbehalte, Protokoll. Auch das Öffnen des Formulars prüft canSave und ownerInScope: die Rechnung eines fremden Unternehmens lässt sich nicht öffnen.
Fehlerschlüssel
error_supplier, error_customer_required, error_currency, error_date, error_invoice_no_form, error_number_in_own_series, error_duplicate, error_duplicate_trashed, error_offset_*, error_retention_over, error_reference_*, error_number_client, error_number_busy, error_number_block, error_series_prefix_taken, error_number_date_order, error_quota_*.
Formularhilfen
getDueDate,getTaxData,getRate— Fälligkeit, MwSt.-Satz, MNB-Kurs; Recht:addoderedit.offsetinvoices— aufrechenbare Ausgangsrechnungen; Recht:edit+ Eigentümerbereich.docsearch,attachdocument,detachdocument,unlinkdocument— Dokument der Dokumentenzentrale suchen, mit der Rechnung verknüpfen oder lösen, alteinvoice_document-Verknüpfung auflösen; Recht:edit+ Bereich.- Die PDF-Felder (Vorlage, Klausel, Hinweis) hängen am Recht
pdf.
Berechtigungen
- Ebene 1: Grundzugriff und Änderungsrecht auf dem Rechnungspfad.
- Ebene 2:
add(im Funktionsstamm nicht eingestuft, nur in den Abhängigkeitstabellen),edit(BASE). - Ebene 3:
ownerInScopeundinvoiceInScope.