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_dateder 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
trueundbilling_emailvorhanden: Email in Queue - Wenn
false: Nur PDF generieren - Validierung: Fehler wenn
invoice_send_email = trueaberbilling_emailleer
Queue Handling¶
- Default Queue (keine separate
billingQueue) - 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_datedes Servicesperiod_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.phpdatabase/migrations/2025_10_17_120549_create_invoice_items_table.phpapp/Enums/InvoiceCycle.php(korrigiert)
Services¶
app/Services/InvoiceNumberGenerator.phpapp/Services/BillingRunProgress.php
Jobs¶
app/Jobs/CreateBillingRunJob.phpapp/Jobs/CreateInvoiceForCustomerJob.php
Filament UI¶
Modules/Admin/Filament/Pages/BillingRun.phpresources/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- Zahlungsbedingungeninvoice_footer- Fußzeileemail_invoice_subject- E-Mail Betreff Templateemail_invoice_body- E-Mail Body Template
Verwendung¶
Via UI (Admin Panel)¶
- Navigation → "Abrechnung" → "Abrechnungslauf"
- Datum wählen, Optionen setzen (Testlauf, E-Mails)
- Vorschau prüfen (Validierung, Warnungen, Fehler)
- "Abrechnungslauf starten" klicken
- Fortschritt beobachten (Auto-Refresh alle 2 Sekunden)
- 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)¶
- Kein BillingRun Model - Keine Historie in DB, nur Logging
- Keine Pro-Rata Berechnung - Volle Monatsabrechnung
- Keine automatische Wiederholung bei Fehlern
- Kein geplanter Billing Run (Cron) - Nur manuell
- Keine Rechnungsarten (Teil-Rechnung, Gutschrift, Storno)
- Kein Mahnwesen
- 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
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_cycleergibt 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:¶
- Preview-Phase:
- ✅ Datum-Filter
- ✅ Tabelle mit Kunden und fälligen Services
- ✅ Validierung (Fehler anzeigen)
- ✅ Manuelle Auswahl (Checkboxen)
-
✅ Statistiken
-
Erstellung:
- ✅ Eine Rechnung pro Kunde
- ✅ Alle fälligen Services als Positionen
- ✅ PDF-Generierung
- ✅ S3-Upload
- ✅ Background-Job (Queue)
-
✅ Fortschrittsanzeige
-
Nachbearbeitung:
- ✅ Zusammenfassung
- ✅ Fehlerprotokoll
- ✅ 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:¶
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¶
- ✅ Konzept dokumentieren
- 🔲 Entscheidungen treffen (offene Fragen klären)
- 🔲 Datenbank-Schema finalisieren
- 🔲 Mockups/Wireframes erstellen
- 🔲 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