Skip to content

10 – Rechnungen & E-Rechnung

Reifegrad: 🟢 produktiv · Schicht: invoices & Co., @work7/domain (Invoice-Funktionen), packages/domain/src/einvoice/*, src/app/invoices, src/app/api/invoices/*, src/templates/invoice-template.html

Zweck

Rechnungen erstellen (manuell, aus Angebot, aus Rapporten), Zahlungen verwalten, als PDF/E-Mail versenden und gesetzeskonforme E-Rechnungen für DE (ZUGFeRD/CII) und AT (ebInterface) exportieren.

Datenmodell (Migration 006 + 031)

  • invoices: invoice_number (UNIQUE(company_id, invoice_number)), type ∈ {anzahlung, teilrechnung, schlussrechnung, standard}, status ∈ {draft, sent, paid, partial_paid, overdue, cancelled}, Finanzfelder als NUMERIC (subtotal, discount_*, tax_rate, tax_amount, total), already_paid und generiertesremaining = total - already_paid. Bezüge: customer_id, project_id, offer_id. E-Rechnungsfelder (031): service_date, service_period_start/_end, buyer_reference, reverse_charge, currency, original_invoice_number, sent_at, paid_at.
  • invoice_items: position, source_type ∈ {offer_item, rapport_entry, rapport_material, manual} + source_id (Herkunftsverfolgung), quantity, unit, unit_price, generiertes total_price, zeilenweise Steuer tax_rate/tax_category (Default S).
  • invoice_rapport_links: m:n Rechnung ↔ Rapport mit billing_percentage.
  • invoice_counters: fortlaufende Nummer pro (company_id, year); DB-Funktion generate_invoice_number() → Format RE-2026-0001.
  • invoice_exports: Export-Historie (format ∈ {zugferd, ebinterface}, status ∈ {pending, valid, invalid, failed}, validation_result JSONB, file_xml, file_pdf, file_primary).
  • labor_rates: Stundensätze je job_category (für Abrechnung aus Rapporten).
  • DB-Trigger recalculate_invoice_totals() summiert Beträge bei jeder Item-Änderung neu.

Status- & Zahlungslogik (@work7/domain)

  • Statusübergänge (INVOICE_STATUS_TRANSITIONS / assertInvoiceStatusTransition): draft→{sent,cancelled}, sent→{paid,partial_paid,overdue,cancelled}, partial_paid→{paid,overdue}, overdue→{paid,partial_paid,cancelled}; paid/cancelled terminal.
  • Teilzahlungen (calculateInvoicePaymentState / recordInvoicePayment): validiert Betrag > 0 und ≤ Restbetrag, setzt partial_paid bzw. paid. markInvoicePaid für Komplettzahlung.

Erzeugung aus Vorprozessen

  • createInvoiceFromOfferPOST /api/invoices/from-offer: übernimmt Angebotspositionen.
  • createInvoiceFromRapportsPOST /api/invoices/from-rapports: bündelt Rapportzeilen; Arbeitsstunden werden über labor_rates(job_category) bepreist, Material als eigene Posten; setzt invoice_rapport_links und rapports.billing_status.

E-Rechnung (packages/domain/src/einvoice/*)

Eigenständige, getestete E-Invoicing-Pipeline:

  1. Kanonisches Modell (canonical-invoice.ts, types.ts): lädt Rechnung + Verkäufer/Käufer in ein CanonicalInvoice und validiert Pflichtfelder (EN 16931).
  2. Formatwahl (resolveEinvoiceFormat): DE → zugferd (CII-XML in PDF/A-3 eingebettet, zugferd-generator.ts), sonst ebinterface (AT, ebinterface-generator.ts).
  3. Human-PDF (human-pdf.ts, invoice-html.ts): lesbares Rechnungs-PDF als Träger.
  4. Validierung: Feld- und XML-Validierung (validateCiiXml / validateEbInterfaceXml); Ergebnis (valid/invalid) + Fehlerliste landen in invoice_exports.

Domain-Funktionen: validateInvoiceExport, exportInvoiceEinvoice, getInvoiceExportLink, getLatestExport.

API-Endpunkte

EndpointFunktion
GET/POST /api/invoicesListe / anlegen
GET/PUT/DELETE /api/invoices/[id]Detail / ändern / löschen
GET/POST /api/invoices/[id]/itemsPositionen
POST /api/invoices/[id]/payZahlung erfassen
POST /api/invoices/[id]/sendRechnung versenden (E-Mail)
POST /api/invoices/[id]/exportE-Rechnung erzeugen (ZUGFeRD/ebInterface)
POST /api/invoices/[id]/export/validateExport vorab validieren
POST /api/invoices/from-offer · from-rapportsaus Angebot / Rapporten erzeugen
GET/POST /api/invoices/labor-ratesStundensätze verwalten
GET /api/pdf/invoices/[id]Rechnungs-PDF

UI

/invoices (Liste mit Status/Restbetrag), /invoices/[id] (Detail, Positionen, Zahlungen, Export, Versand). Komponenten: src/components/invoices/*. Mandanten-Defaults (Nummernformat, E-Rechnungsformat, Steuer) aus companies (siehe 02-mandanten-company-settings).

Compliance-Hintergrund

Siehe ../compliance/compliance-e-rechnung-de-at.md und adr-0006-e-rechnung-zugferd-ebinterface.

Bekannte Befunde / offene Punkte

  • Mahnwesen/Skonto sind in companies konfigurierbar (dunning_*, cash_discount_*), aber ein automatischer Mahnlauf ist (noch) nicht als Job implementiert.
  • overdue-Status muss aktiv gesetzt werden (kein Auto-Job, der fällige Rechnungen umstuft).
  • Default-tax_rate 20 % (AT) – via Mandanten-Default überschreibbar.

Verwandte Notes

Work7 · Software für Handwerksbetriebe