Zum Inhalt

Billing Run - Konzept & Planung

Übersicht

Der Billing Run ist ein automatisierter Prozess zur Erstellung von Rechnungen für fällige Services. Er ermöglicht die Massenabrechnung von Kundenservices basierend auf deren Abrechnungszyklus.

Status: ✅ IMPLEMENTIERT (MVP v1)

Implementierte Features

1. Datenmodell

  • InvoiceItem Model mit Parent-Child-Hierarchie
  • Invoice-InvoiceItem Beziehung
  • ✅ Settings für Rechnungsnummern (invoice_prefix, invoice_number_current)

2. Services & Helpers

  • InvoiceNumberGenerator - Durchlaufende Nummern mit Prefix
  • BillingRunProgress - Cache-basiertes Progress-Tracking

3. Jobs

  • CreateBillingRunJob - Master-Job, koordiniert den gesamten Run
  • CreateInvoiceForCustomerJob - Erstellt Rechnung pro Kunde
  • Sammelt fällige Services (nur status = 'active')
  • Erstellt Invoice mit hierarchischen InvoiceItems
  • Generiert PDF (DomPDF)
  • Speichert auf S3 (produktiv) oder lokal (Test)
  • Aktualisiert next_billing_date der Services
  • Erstellt Email (wenn customer->invoice_send_email = true)

4. UI (Filament Admin Panel)

  • BillingRun Page mit 3 Phasen:
  • Phase 1: Konfiguration & Vorschau
    • Datum-Filter
    • Testlauf-Option
    • E-Mail-Erstellung Option
    • Preview-Tabelle mit Validierung
    • Statistiken (Kunden, Services, Summe, Fehler, Warnungen)
  • Phase 2: Fortschritt (Livewire Polling)
    • Echtzeit-Fortschrittsbalken
    • Aktueller Kunde
    • Erfolg/Fehler-Zähler
    • Gesamtsumme
    • Fehlerprotokoll (aufklappbar)
  • Phase 3: Ergebnis
    • Zusammenfassung
    • Fehlerprotokoll
    • Warnungen
    • Link zu Rechnungen

5. PDF-Generierung

  • ✅ Invoice PDF Template (resources/views/invoices/pdf.blade.php)
  • Hierarchische Darstellung (Parent-Child)
  • Leistungszeitraum pro Position
  • MwSt.-Berechnung
  • Firmendaten aus Settings

Workflow

Billing Date Handling

  • Strikt: Nur Services mit next_billing_date <= ausgewähltes_datum
  • Keine Vorlauf-Optionen

Service Status Filter

  • Nur status = 'active' wird abgerechnet
  • Services mit gesetztem stopped_at (Vergangenheit) werden übersprungen
  • Billing Cycle NONE (0) wird übersprungen

Parent-Child-Services Abrechnung

  • Gruppierte Darstellung mit Hierarchie
  • Alle Beträge werden summiert (Parent + Children)
  • Sortierung:
  • Hosting-Services mit ihren Children (eingerückt)
  • Standalone Services ohne Parent am Ende

Rechnungsnummer

  • Durchlaufende Nummer mit konfigurierbarem Prefix
  • Settings: invoice_prefix (z.B. "RE-"), invoice_number_current
  • Format: RE-1001, RE-1002, ...

Dry Run / Testmodus

  • Simulation MIT PDF-Preview
  • Keine DB-Änderungen (Draft-Invoices)
  • PDFs werden temporär gespeichert: storage/app/billing-preview/{run_id}/
  • Cleanup: Manuell oder via Scheduled Job

Email-Versand

  • Abhängig von customer->invoice_send_email
  • Wenn true und billing_email vorhanden: Email in Queue
  • Wenn false: Nur PDF generieren
  • Validierung: Fehler wenn invoice_send_email = true aber billing_email leer

Queue Handling

  • Default Queue (keine separate billing Queue)
  • Jobs werden sequenziell pro Kunde abgearbeitet

Technische Details

Billing Cycles (InvoiceCycle Enum)

ONCE = -1;      // einmalig → next_billing_date = null nach Abrechnung
NONE = 0;       // ohne → wird nie abgerechnet
MONTHLY = 1;    // monatlich
BIMONTHLY = 2;  // zweimonatlich
QUARTERLY = 3;  // vierteljährlich
SEMIANNUALLY = 6; // halbjährlich
ANNUALLY = 12;  // jährlich
BIANNUALLY = 24; // zweijährlich

next_billing_date Berechnung

  • Nach Rechnungserstellung: next_billing_date += billing_cycle Monate
  • Einmalig (ONCE): next_billing_date = null
  • Ohne (NONE): Wird nicht aktualisiert

Leistungszeitraum auf Rechnung

  • period_start = next_billing_date des Services
  • period_end = period_start + billing_cycle Monate - 1 Tag
  • Beispiel: Service fällig 01.11.2025, monatlich → Zeitraum: 01.11.2025 - 30.11.2025

Fehlerbehandlung

  • Fehler pro Kunde werden gecatcht → Log + Progress
  • Transaction Rollback pro Kunde
  • Andere Kunden werden weiter abgerechnet
  • Fehlerprotokoll in BillingRunProgress (Cache)

Dateien

Models & Migrations

  • app/Models/InvoiceItem.php
  • database/migrations/2025_10_17_120549_create_invoice_items_table.php
  • app/Enums/InvoiceCycle.php (korrigiert)

Services

  • app/Services/InvoiceNumberGenerator.php
  • app/Services/BillingRunProgress.php

Jobs

  • app/Jobs/CreateBillingRunJob.php
  • app/Jobs/CreateInvoiceForCustomerJob.php

Filament UI

  • Modules/Admin/Filament/Pages/BillingRun.php
  • resources/views/modules/admin/filament/pages/billing-run.blade.php

Views

  • resources/views/invoices/pdf.blade.php

Settings (Seeder)

  • invoice_prefix - Rechnungs-Prefix (default: "RE-")
  • invoice_number_start - Startnummer (default: 1000)
  • invoice_number_current - Aktuelle Nummer (wird hochgezählt)
  • invoice_due_days - Zahlungsziel in Tagen (default: 14)
  • invoice_tax_rate - Standard-MwSt.-Satz (default: 19)
  • invoice_terms - Zahlungsbedingungen
  • invoice_footer - Fußzeile
  • email_invoice_subject - E-Mail Betreff Template
  • email_invoice_body - E-Mail Body Template

Verwendung

Via UI (Admin Panel)

  1. Navigation → "Abrechnung" → "Abrechnungslauf"
  2. Datum wählen, Optionen setzen (Testlauf, E-Mails)
  3. Vorschau prüfen (Validierung, Warnungen, Fehler)
  4. "Abrechnungslauf starten" klicken
  5. Fortschritt beobachten (Auto-Refresh alle 2 Sekunden)
  6. Ergebnis anschauen (Statistiken, Fehlerprotokoll)

Programmatisch

use App\Jobs\CreateBillingRunJob;
use Illuminate\Support\Str;

$runId = Str::uuid()->toString();
$customerIds = [1, 2, 3, 4, 5]; // Array von Customer IDs
$billingDate = '2025-11-01'; // Y-m-d
$isTestRun = false;
$createEmails = true;

CreateBillingRunJob::dispatch(
    $customerIds,
    $billingDate,
    $isTestRun,
    $createEmails,
    $runId
);

// Fortschritt abrufen
$progress = new BillingRunProgress($runId);
$data = $progress->getData();

Testing

# Docker Container
cd hostadmin
docker-compose exec app php artisan test

# Manueller Test
1. Testdaten erstellen (Customers, Services mit next_billing_date in Vergangenheit)
2. Admin Panel  Billing Run
3. Testlauf aktivieren
4. Run starten
5. Preview-PDFs prüfen in storage/app/billing-preview/

Bekannte Einschränkungen (MVP v1)

  1. Kein BillingRun Model - Keine Historie in DB, nur Logging
  2. Keine Pro-Rata Berechnung - Volle Monatsabrechnung
  3. Keine automatische Wiederholung bei Fehlern
  4. Kein geplanter Billing Run (Cron) - Nur manuell
  5. Keine Rechnungsarten (Teil-Rechnung, Gutschrift, Storno)
  6. Kein Mahnwesen
  7. Template-System nicht integriert - Verwendet Basis-PDF-View

Nächste Schritte (Future)

v2 Features

  • Pro-Rata Berechnung (tagesgenau)
  • BillingRun Model für Historie
  • Automatische Wiederholung bei Fehlern
  • Export des Fehlerprotokolls (CSV/PDF)
  • DocumentTemplate Integration für Rechnung-PDFs
  • Geplanter Billing Run (Scheduler)

v3 Features

  • Mahnwesen-Integration
  • Automatische Zahlungserinnerungen
  • SEPA-Lastschrift-Export
  • Dunning-Prozess (Mahnstufen)
  • Statistiken & Reports
  • Unterschiedliche Rechnungsarten (Gutschrift, Storno, Teil-Rechnung)

Troubleshooting

Problem: Jobs werden nicht abgearbeitet

Lösung: Queue Worker läuft nicht

docker-compose exec app php artisan queue:work
# oder Queue-Container neustarten
docker-compose restart queue

Problem: PDFs werden nicht generiert

Lösung: DomPDF-Fehler, View prüfen

docker-compose exec app php artisan view:clear
# Log prüfen
docker-compose logs app

Problem: Next Billing Date wird nicht aktualisiert

Lösung: Transaktion Rollback wegen Fehler - Fehlerprotokoll im Billing Run Result prüfen - Log prüfen: docker-compose logs app | grep "billing"

Problem: E-Mails werden nicht versendet

Lösung: Email-Settings prüfen - customer->invoice_send_email aktiviert? - customer->billing_email gesetzt? - Email-Queue läuft? docker-compose logs queue


Letztes Update: 2025-10-17
Status: ✅ Implementiert (MVP v1)
Version: 1.0.0

Datenmodell: - CustomerService: Hat next_billing_date, service_billing_cycle, start_date, status, service_price - Invoice: Verknüpft mit Customer (und optional Contract), hat invoice_number, invoice_date, due_date, status, pdf_path - InvoiceItem: Einzelne Rechnungspositionen (zu prüfen/erstellen)

Billing Cycles

Anzahl Monate, Ausnahme -1 für einmalig und 0 für keine Abrechnung

-1 = "einmalig"; 0 = "ohne"; 1 = 'monatlich'; 2 = 'zweimonatlich'; 3 = 'vierteljährlich'; 6 = 'halbjährlich'; 12 = 'jährlich'; 24 = 'zweijährlich';

  • Der Billingcylce einzelner Services kann unterschiedlich werden. Bsp: Webhosting: monatlich = 1 und Domain: jährlich = 12
  • next_billing_date + service_billing_cycle ergibt den "Leistungszeitraum" der auf der Rechnung angezeigt wird.

Bestehende Features: - Services haben konfigurierbare Billing-Cycles - next_billing_date wird im CustomerService gespeichert - PDF-Generierung existiert bereits (DomPDF) - S3-Storage für Rechnungs-PDFs (customer/{customer_id}/invoices/{year}/)

Workflow-Konzept

Phase 1: Vorbereitungsphase (Preview)

Ziel: Dem Benutzer eine Übersicht geben, welche Services abgerechnet werden.

Funktionen: - Datum auswählen: "Alle Services fällig bis [Datum]" - Vorschau-Tabelle zeigt: - Kunde (Name, Kundennummer) - Anzahl fälliger Services - Geschätzter Rechnungsbetrag (Summe aller Service-Preise) - Status (OK, Warnung, Fehler) - Checkbox zur manuellen Auswahl - Filter-Optionen: - Nach Kunde - Nach Service-Typ - Nach Billing-Cycle - Nach Status (active, suspended, etc.)

Validierung & Warnungen: - ❌ Kunde ohne E-Mail-Adresse - ❌ Service ohne Preis - ❌ Kein aktives Rechnungstemplate - ⚠️ Kunde hat Status "suspended" oder "cancelled" - ⚠️ Service hat Preis 0.00

Statistiken: - Anzahl Kunden - Anzahl Services - Gesamtsumme (geschätzt) - Anzahl Warnungen/Fehler

Phase 2: Konfiguration & Optionen

Abrechnungsoptionen: - [ ] Testlauf (Dry Run): Keine Änderungen in Datenbank, nur Simulation - [ ] Rechnungen erstellen: Invoices in DB anlegen, PDFs generieren - [ ] E-Mails in Queue stellen: Automatisch nach Erstellung versandbereit machen - [ ] Services aktualisieren: next_billing_date direkt aktualisieren

Rechnungskonfiguration: - Rechnungsdatum: Standard = Heute, änderbar - Fälligkeitsdatum: Standard = Rechnungsdatum + X Tage (aus Settings) - Template auswählen: Standard-Template oder spezifisches wählen - Rechnungsnummer-Format: Aus Settings

Phase 3: Erstellungsprozess

Technische Umsetzung:

Job: CreateBillingRunInvoices
├─ Input: Array von Customer IDs + Konfiguration
├─ Process:
│  └─ Für jeden Kunde:
│     ├─ Alle fälligen Services laden
│     ├─ Invoice erstellen
│     │  ├─ invoice_number generieren
│     │  ├─ invoice_date, due_date setzen
│     │  ├─ customer_id zuordnen
│     │  └─ status = 'draft'
│     ├─ InvoiceItems erstellen
│     │  └─ Pro Service:
│     │     ├─ description (service_name + domain)
│     │     ├─ quantity
│     │     ├─ unit_price (service_price)
│     │     ├─ tax_rate (aus Settings)
│     │     └─ total
│     ├─ Invoice Summen berechnen
│     │  ├─ subtotal (Summe aller Items)
│     │  ├─ tax_amount (subtotal * tax_rate)
│     │  └─ total_amount (subtotal + tax_amount)
│     ├─ PDF generieren
│     │  ├─ Template rendern mit Daten
│     │  ├─ PDF mit DomPDF erzeugen
│     │  └─ Auf S3 speichern: customer/{id}/invoices/{year}/{filename}.pdf
│     ├─ Invoice aktualisieren
│     │  ├─ pdf_path setzen
│     │  ├─ pdf_generated_at setzen
│     │  └─ status = 'open' (wenn alles OK)
│     └─ Services aktualisieren
│        └─ next_billing_date = calculateNextBillingDate()
└─ Output: BillingRunResult (Statistiken, Fehler)

Fortschrittsanzeige: - Livewire-Component mit Polling - Zeigt: X von Y Kunden abgerechnet - Geschätzte verbleibende Zeit - Möglichkeit zum Abbrechen

Fehlerbehandlung: - Fehler pro Kunde/Service loggen - Bei Fehler: Transaktion zurückrollen für diesen Kunden - Weitermachen mit nächstem Kunden - Am Ende: Fehlerprotokoll anzeigen

Phase 4: Ergebnis & Nachbearbeitung

Zusammenfassung anzeigen:

Abrechnungslauf abgeschlossen
├─ ✅ 45 Rechnungen erfolgreich erstellt
├─ ❌ 3 Fehler
├─ 📊 Statistiken:
│  ├─ Gesamtsumme: 12.450,00 €
│  ├─ Durchschnitt: 276,67 € pro Rechnung
│  └─ Laufzeit: 2 Min 34 Sek
└─ 📄 Protokoll herunterladen

Fehlerprotokoll: - Kunde, Service, Fehlermeldung - Möglichkeit zum Export (CSV) - Filter: Nur Fehler, Nur Warnungen

Nächste Schritte: - Button: "Rechnungen per E-Mail versenden" - Leitet zu E-Mail-Massenversand - Filtert automatisch auf neu erstellte Rechnungen - Button: "Rechnungen ansehen" - Öffnet Invoice-Liste gefiltert auf heute erstellte

Offene Fragen & Entscheidungen

A. Rechnungserstellung

Frage 1: Eine oder mehrere Rechnungen pro Kunde? - Option A: Eine Sammelrechnung pro Kunde mit allen fälligen Services - ✅ Übersichtlicher für Kunde - ✅ Weniger Rechnungen = weniger E-Mails - ❌ Komplexer wenn Services unterschiedliche Fälligkeiten haben - Option B: Separate Rechnung pro Service - ✅ Einfacher zu implementieren - ✅ Services können individuell abgerechnet werden - ❌ Viele Rechnungen bei Kunden mit vielen Services

→ Empfehlung: Option A (Sammelrechnung), ABER mit der Möglichkeit Services manuell auszuschließen

Frage 2: Rechnungsnummer-Format? - Format aus Settings: invoice_number_format (z.B. "INV-{year}-{number}") - Fortlaufende Nummer aus Settings: invoice_number_start, invoice_number_current - Jahr-basierte Nummerierung? (Jedes Jahr bei 1 anfangen?)

→ Zu klären: Gewünschtes Format definieren

Frage 3: Umgang mit unterschiedlichen Billing-Dates? Beispiel: Kunde hat 5 Services - Service A: fällig am 01.11.2025 - Service B: fällig am 15.11.2025 - Service C: fällig am 01.12.2025

Optionen: - Alle in eine Rechnung (frühestes Fälligkeitsdatum verwenden) - Nur Services bis zum ausgewählten Datum - Separate Rechnungen nach Fälligkeitsdatum gruppiert

→ Empfehlung: Nur Services bis zum ausgewählten Datum, eine Rechnung

B. Service-Aktualisierung

Frage 1: Wann next_billing_date aktualisieren? - Sofort bei Rechnungserstellung ✅ (Empfehlung) - Verhindert doppelte Abrechnung - Service ist direkt "abgerechnet" - Bei Rechnungsversand - Was wenn Rechnung gelöscht wird? - Bei Zahlungseingang - Service bleibt "fällig" bis bezahlt - Komplexer zu handhaben

Frage 2: Gestoppte Services? Services mit stopped_at: - Automatisch überspringen - ODER: Letzte Teilabrechnung bis stopped_at - ODER: Warnung anzeigen, manuell entscheiden

→ Empfehlung: Automatisch überspringen, in Vorschau anzeigen

C. Teilabrechnung & Pro-Rata

Szenario 1: Service startet mitten im Monat - Service startet am 15.01.2025 - Billing Cycle: monthly - Erste Rechnung: Nur halber Monat?

Szenario 2: Service wird mitten im Monat gestoppt - Service läuft bis 15.01.2025 - Billing Cycle: monthly - Letzte Rechnung: Nur halber Monat?

Optionen: - Volle Abrechnung (einfach, keine Berechnung nötig) - Pro-Rata Berechnung (komplexer, aber fairer) - Tagesgenau: preis / tage_im_monat * tage_genutzt - Nur bei erstem/letztem Monat

→ Empfehlung für MVP: Volle Abrechnung, Pro-Rata später als Feature

D. Fehlerbehandlung & Edge Cases

Fehlerfall 1: Kunde ohne E-Mail - Rechnung erstellen, aber nicht in E-Mail-Queue - Warnung im Protokoll - Status: "created_no_email"

Fehlerfall 2: Service ohne Preis - ❌ Überspringen - Fehler loggen - Admin muss Preis nachtragen

Fehlerfall 3: Template-Rendering schlägt fehl - Transaktion zurückrollen - Fehler loggen mit Details - Weiter mit nächstem Kunden

Fehlerfall 4: S3-Upload schlägt fehl - Invoice in DB bleibt als "draft" - Retry-Mechanismus? - Fehler loggen

→ Zu implementieren: Robuste Fehlerbehandlung mit Logging

E. UI/UX Überlegungen

Wizard vs. Single Page? - Wizard (Step-by-Step): ✅ Empfehlung - Step 1: Preview & Auswahl - Step 2: Konfiguration - Step 3: Erstellung (Progress) - Step 4: Ergebnis - Single Page: - Alles auf einer Seite - Schneller für erfahrene Nutzer

Fortschrittsanzeige: - Livewire-Component - Polling alle 2 Sekunden - Zeigt: Fortschritt, aktuelle Aktion, Fehler - Button: "Abbrechen" (stoppt Job)

Abbrechen während Erstellung: - Job kann gestoppt werden - Bereits erstellte Rechnungen bleiben bestehen - Nicht erstellte werden übersprungen - Protokoll zeigt "Abgebrochen" Status

MVP (Minimum Viable Product)

Must-Have Features für v1:

  1. Preview-Phase:
  2. ✅ Datum-Filter
  3. ✅ Tabelle mit Kunden und fälligen Services
  4. ✅ Validierung (Fehler anzeigen)
  5. ✅ Manuelle Auswahl (Checkboxen)
  6. ✅ Statistiken

  7. Erstellung:

  8. ✅ Eine Rechnung pro Kunde
  9. ✅ Alle fälligen Services als Positionen
  10. ✅ PDF-Generierung
  11. ✅ S3-Upload
  12. ✅ Background-Job (Queue)
  13. ✅ Fortschrittsanzeige

  14. Nachbearbeitung:

  15. ✅ Zusammenfassung
  16. ✅ Fehlerprotokoll
  17. ✅ Link zu E-Mail-Versand

Nice-to-Have für v2:

  • 🔲 Pro-Rata Berechnung
  • 🔲 Automatische Wiederholung bei Fehlern
  • 🔲 Geplanter Billing Run (Cron)
  • 🔲 E-Mail-Vorschau vor Versand
  • 🔲 Export des Protokolls
  • 🔲 Billing-Run Historie
  • 🔲 Unterschiedliche Rechnungsarten (Teil-Rechnung, Gutschrift)

Nice-to-Have für v3:

  • 🔲 Mahnwesen-Integration
  • 🔲 Automatische Zahlungserinnerungen
  • 🔲 SEPA-Lastschrift-Export
  • 🔲 Dunning-Prozess (Mahnstufen)
  • 🔲 Statistiken & Reports

Technische Implementierung

Neue Modelle/Migrations:

// Eventuell: BillingRun Model (Historie)
BillingRun:
  - id
  - user_id (wer hat gestartet)
  - run_date
  - billing_until_date
  - status (running, completed, failed, cancelled)
  - invoices_created
  - errors_count
  - total_amount
  - started_at
  - completed_at
  - log_data (JSON)

// InvoiceItem (falls noch nicht vorhanden)
InvoiceItem:
  - id
  - invoice_id
  - customer_service_id (optional, für Zuordnung)
  - description
  - quantity
  - unit_price
  - tax_rate
  - tax_amount
  - total
  - sort_order

Jobs:

// Job für gesamten Billing Run
App\Jobs\CreateBillingRun
  - Input: BillingRunConfiguration
  - Erstellt BillingRun Record
  - Dispatcht CreateInvoiceForCustomer Jobs

// Job pro Kunde
App\Jobs\CreateInvoiceForCustomer
  - Input: Customer ID, Services, Configuration
  - Erstellt Invoice + Items
  - Generiert PDF
  - Updated Services

Events:

BillingRunStarted
BillingRunCompleted
BillingRunFailed
InvoiceCreatedFromBillingRun

Notifications:

// Admin Benachrichtigung nach Abschluss
BillingRunCompletedNotification
  - Zeigt Statistiken
  - Link zu Ergebnissen

Zeitplan (Vorschlag)

Phase 1: Grundlagen (2-3 Tage) - InvoiceItem Model + Migration - BillingRun Model + Migration - Basis-Jobs erstellen

Phase 2: UI - Preview (2 Tage) - Wizard-Component - Preview-Tabelle - Validierung - Filter

Phase 3: Erstellung (3-4 Tage) - Job-Logic - PDF-Generierung - S3-Upload - Service-Updates - Fehlerbehandlung

Phase 4: UI - Fortschritt & Ergebnis (2 Tage) - Livewire Progress-Component - Ergebnis-Seite - Fehlerprotokoll

Phase 5: Testing & Refinement (2-3 Tage) - Unit Tests - Integration Tests - Bug Fixes - Performance-Optimierung

Gesamt: ~2-3 Wochen

Sicherheitsüberlegungen

  • ✅ Nur Admin-Benutzer dürfen Billing Run starten
  • ✅ Dry-Run Option für Tests
  • ✅ Keine automatische Löschung von Rechnungen
  • ✅ Alle Aktionen werden geloggt
  • ✅ Backup vor großem Billing Run empfohlen
  • ✅ Rate Limiting für E-Mail-Versand

Nächste Schritte

  1. ✅ Konzept dokumentieren
  2. 🔲 Entscheidungen treffen (offene Fragen klären)
  3. 🔲 Datenbank-Schema finalisieren
  4. 🔲 Mockups/Wireframes erstellen
  5. 🔲 Implementierung starten

Notizen

  • E-Mail-Versand ist separate Funktionalität (bereits vorhanden)
  • PDF-Generierung funktioniert bereits (DomPDF)
  • Settings für Rechnungsnummern müssen definiert werden
  • Template-System ist vorhanden

Letztes Update: 2025-10-16
Status: Konzeptphase
Verantwortlich: Team