# Modul Mahnung — 3-stufiges Mahnwesen für Dolibarr Mahnwesen-Modul für Dolibarr ERP: tägliche Vorschlagsliste überfälliger Rechnungen, 3-stufiger Workflow (Erinnerung → Mahnung → Letzte Mahnung), Mahngebühren + tagesgenaue Verzugszinsen nach **BGB §288**, PDF- und ODT-Mahnschreiben, E-Mail-Versand, Sammelbrief, Trigger auf Zahlungseingang. ## Status Version **0.2.0 + Phasen 1-6 (Unreleased)** — UX-Vorschlagsliste, Versand-Erfassung, Sendebeleg-Upload, konfigurierbare Tracking-Patterns mit Live-Vorschau, Beleg-Scan via pdftotext, Versand-Reminder, Bonitäts-Workflow + Uneinbringlich-Klassifikation. ## Features | Feature | Implementierung | |---|---| | Tägliche Vorschlagsliste überfälliger Rechnungen | Cron `MahnungCronBuildVorschlag` | | Push-Benachrichtigung mit Anzahl je Stufe | Ntfy + GlobalNotify | | 3 Stufen pflegbar (Frist, neue Frist, Gebühr B2C/B2B, Versandart, E-Mail-Template, PDF-Intro) | `admin/setup.php` | | B2C / B2B-Erkennung | über `llx_societe.tva_intra` | | Verzugszinsen | tagesgenau, B2C: Basiszins +5 %, B2B: +9 %; Override pro Stufe möglich; **auto-Neuberechnung** bei noch nicht versandten Mahnungen | | §288 Abs. 5 Pauschale 40 € | nur bei B2B, einmalig pro Rechnung | | PDF-Mahnschreiben (DIN 5008) | Standard-TCPDF-Generator `pdf_standard_mahnung` | | ODT-Mahnschreiben (je Stufe) | ODT-Template-Generator `doc_generic_mahnung_odt` mit Stufen-Auswahl | | Dokumentenmodell-Verwaltung | Setup-Seite: Modelle aktivieren, Default wählen, ODT-Templates hochladen | | Template-Variablen-Referenz | `admin/templatevars.php` — alle verfügbaren ODT-Variablen | | Dokumentenliste auf Mahnungs-Karte | Vorschau (Lupe), Download, Modellauswahl | | Bulk-Erstellung + Sammelbrief | TCPDI-basiert | | E-Mail-Versand mit PDF-Anhang | `CMailFile`, Subject/Body mit Platzhaltern | | Auto-Erledigung bei Zahlungseingang | Trigger `BILL_PAYED` + `PAYMENT_CUSTOMER_CREATE` | | Tab "Mahnungen (n)" auf Rechnungs- + Kundenkarte | Hook `completeTabsHead` (filtert auf add/external) | | Widget: Offene Rechnungen mit Mahnstufe | `box_mahnung_offen` | | **Vorschlagsliste-Filter** (Mahnstufe, Tage Verzug, Mindestbetrag, Kundentyp B2B/B2C, Kunden-Select2 mit Ajax) | `list.php` — Kundentyp-Wechsel filtert das Kunden-Dropdown sofort per Auto-Submit | | **Kontakt-Spalte** in Vorschlagsliste (Telefon-/Mail-Icons mit Direktlink) | tel:/mailto: aus `llx_societe.phone/email` | | **Versand-Erfassung** pro Mahnung (Datum, Versandweg, Sendungsnummer, Tracking-Provider) | `card.php` Versand-Block; setzt automatisch Status auf VERSENDET | | **Tracking-Deep-Links** für DHL, DPAG, DPD, Hermes, UPS | konfigurierbar via Tracking-Pattern-Tabelle | | **Sendebeleg-Upload** pro Mahnung | Dolibarrs `formfile->showdocuments('mahnung', ...)` → `DOL_DATA_ROOT/mahnung//` | | **Konfigurierbare Tracking-Patterns** (Regex + URL-Template, Priorität, Aktivierung) | `admin/tracking_patterns.php` CRUD + Live-Vorschau | | **Live-Regex-Vorschau** (Treffer + URL-Preview während Eingabe) | `ajax/regex_preview.php` (debounced 300ms, ReDoS-Schutz) | | **Beleg-Scan** (pdftotext + ocrmypdf-Fallback + Pattern-Matching → Sendungsnummer-Vorschlag) | Button "Belege scannen" auf `card.php`; "Übernehmen" setzt automatisch Tracking + Versanddatum + Versandweg | | **Versand-Reminder** (Mahnung > N Tage unversendet → Ntfy-Push) | Cron `MahnungCronVersandReminder`, Schwellenwert via `MAHNUNG_VERSAND_REMINDER_DAYS` | | **Bonitäts-Box auf Kundenkarte** (Anzahl + Summe + letztes Datum der `badcustomer` abandoned Rechnungen) | Hook `tabContentViewThirdparty` | | **Bonitäts-Warning** bei Auftrag-/Rechnungs-Karte | Hook `formObjectOptions` (invoicecard + ordercard) | | **"Als uneinbringlich klassifizieren"-Button** auf Mahnung Stufe 3 | Bestätigungs-Dialog mit Begründung → `Facture::setCanceled($user, CommonInvoice::CLOSECODE_BADDEBT, $note)` | ## Voraussetzungen - Dolibarr ≥ 19 - PHP ≥ 7.4 - TCPDF (Dolibarr-Standard) für PDF - Optional: ODTPHP (Dolibarr-Standard) für ODT-Templates - Optional: TCPDI (Dolibarr `includes/tcpdf/tcpdi.php`) für Sammelbrief-Konkatenation - Optional: `pdftotext` + `ocrmypdf` + `tesseract` im Container für OCR-Beleg-Scan - Optional: `GlobalNotify` für In-App-Notification-Badges - Empfohlen: `BankImport` (automatischer Zahlungseingang via FinTS triggert die Mahnungs-Erledigung sauber) ## Installation ```bash git clone https://git.data-it-solution.de/data/mahnung.git \ /pfad/zu/dolibarr/htdocs/custom/mahnung ``` Dann **Startseite → Setup → Module → Finanzwesen → Mahnung** aktivieren. Bei Aktivierung werden `llx_mahnung_mahnung` und `llx_mahnung_stufe` angelegt; drei Default-Stufen werden idempotent eingefügt. Dokumentenmodelle (`standard_mahnung`, `generic_mahnung_odt`) werden in `llx_document_model` registriert. Nach Aktivierung in **Setup → Mahnwesen Einstellungen**: 1. Basiszins prüfen 2. Stufen-Texte (PDF-Intro, E-Mail-Body) anpassen 3. Dokumentenmodell wählen und ggf. ODT-Templates hochladen 4. Cron-Job `MahnungCronBuildVorschlag` aktivieren ## ODT-Templates Templates werden unter **Setup → Mahnwesen Einstellungen → Dokumentenmodelle** hochgeladen. ### Dateinamen-Konvention | Dateiname | Verwendung | |---|---| | `mahnung_stufe1.odt` | Zahlungserinnerung (Stufe 1) | | `mahnung_stufe2.odt` | 1. Mahnung (Stufe 2) | | `mahnung_stufe3.odt` | Letzte Mahnung (Stufe 3) | | `mahnung.odt` | Fallback für alle Stufen | ### Verfügbare Template-Variablen (Auswahl) | Variable | Beispiel | |---|---| | `{mahnung_ref}` | MAHN2026-0001 | | `{mahnung_stufe}` | 1 | | `{mahnung_stufe_label}` | Zahlungserinnerung | | `{mahnung_date}` | 10.05.2026 | | `{mahnung_betrag_offen}` | 131,34 | | `{mahnung_mahngebuehr}` | 5,00 | | `{mahnung_verzugszinsen}` | 1,23 | | `{mahnung_summe}` | 137,57 | | `{mahnung_kundentyp}` | B2C | | `{facture_ref}` | IN2604-0036 | | `{facture_total_ttc}` | 131,34 | | `{company_name}` | Kundenname | | `{mycompany_name}` | Eigene Firma | | `{mahnung_bank_iban}` | DE89... | Vollständige Liste: **Setup → Mahnwesen → Verfügbare Template-Variablen** ## Rechte | Recht | Standard | Bedeutung | |---|---|---| | `mahnung.read` | aktiv | Mahnungen einsehen | | `mahnung.write` | inaktiv | Mahnungen erstellen / bearbeiten | | `mahnung.send` | inaktiv | Mahnungen versenden (E-Mail / Druck) | | `mahnung.delete` | inaktiv | Mahnungen stornieren | | `mahnung.setup` | inaktiv | Stufen, Basiszins, Versand konfigurieren | ## Modul-Konstanten | Name | Default | Bedeutung | |---|---|---| | `MAHNUNG_BASISZINS` | `1.27` | BGB-Basiszins (%) — halbjährlich pflegen (1.1./1.7.) | | `MAHNUNG_AUFSCHLAG_B2C` | `5.0` | Verzugszins-Aufschlag B2C (BGB §288 Abs. 1) | | `MAHNUNG_AUFSCHLAG_B2B` | `9.0` | Verzugszins-Aufschlag B2B (BGB §288 Abs. 2) | | `MAHNUNG_PAUSCHALE_B2B` | `40.00` | Pauschale B2B (EUR, BGB §288 Abs. 5, einmalig) | | `MAHNUNG_ADDON_PDF` | `standard_mahnung` | Standard-Dokumentenmodell | | `MAHNUNG_ADDON_PDF_ODT_PATH` | `DOL_DATA_ROOT/doctemplates/mahnung` | ODT-Template-Verzeichnis | | `MAHNUNG_NTFY_TOPIC` | `vk-builds` | Ntfy-Topic für Vorschlags-Push | | `MAHNUNG_VERSAND_REMINDER_DAYS` | `2` | Schwelle (Tage) für Versand-Reminder Ntfy-Push | ## Datenbank | Tabelle | Zweck | |---|---| | `llx_mahnung_mahnung` | Mahnvorgänge — inkl. Versand-Felder `date_versand`, `versandweg`, `tracking_nr`, `tracking_provider` (idempotente Migration via `migrateVersandFelder()` beim Setup-Aufruf) | | `llx_mahnung_stufe` | Stufen-Konfiguration (Stufe 1/2/3 mit Fristen, Gebühren, Templates) | | `llx_mahnung_trackingpattern` | Konfigurierbare Tracking-Regex + URL-Template pro Provider, Default-Seed mit DHL/DPAG/DPD/Hermes/UPS | ## AJAX-Endpoints | Endpoint | Zweck | Parameter | Auth | |---|---|---|---| | `ajax/createmahnung.php` | Bulk-Mahnung-Erzeugung | `facture_ids[]`, `stufe`, `token` | `mahnung.write` | | `ajax/sammelbrief.php` | Sammelbrief-PDF | `facture_ids[]`, `token` | `mahnung.send` | | `ajax/sendmail.php` | E-Mail-Versand | `mahnung_id`, `token` | `mahnung.send` | | `ajax/regex_preview.php` | Live-Vorschau für Tracking-Patterns | `regex`, `sample`, `url_template` (POST) | `mahnung.setup` oder Admin | ## Hooks & Trigger **Hook-Klasse:** `class/actions_mahnung.class.php` — registriert für `invoicecard`, `thirdpartycard`, `ordercard`. | Hook | Zweck | |---|---| | `addMoreActionsButtons` | "Mahnung erstellen"-Button auf Rechnungs-Karte | | `completeTabsHead` | Tab "Mahnungen (n)" — filtert auf `mode=add` + `filterorigmodule=external` (sonst doppelter Tab, siehe KB #601) | | `tabContentViewThirdparty` | Bonitäts-Warnbox auf Kundenkarte wenn `badcustomer` abandoned Rechnungen existieren | | `formObjectOptions` | Bonitäts-Warning bei Auftrag-/Rechnungs-Karten | **Trigger:** `core/triggers/interface_99_modMahnung_MahnungTriggers.class.php` - `BILL_PAYED` + `BILL_VALIDATE` + `PAYMENT_CUSTOMER_CREATE` → setzt offene Mahnungen auf `STATUS_ERLEDIGT` **Cron-Jobs:** - `MahnungCronBuildVorschlag` — täglich, Vorschlagsliste aufbauen + Ntfy-Push - `MahnungCronVersandReminder` — täglich, Reminder für unversendete Mahnungen ## Workflow ``` Cron 06:00 (MahnungCronBuildVorschlag) | |--> ueberfaellige Rechnungen einsammeln |--> Stufe ermitteln (Stufe 1 ab frist_tage Verzug, | Folgestufen nach neue_frist_tage seit Vor-Mahnung) |--> Ntfy-Push mit Anzahl je Stufe + Gesamt-EUR |--> GlobalNotify "actionRequired" (wenn Modul aktiv) | v list.php (Vorschlagsliste) | Filter: Mahnstufe, min. Verzug, min. Betrag, Kundentyp (B2B/B2C), Kunde (Select2) | Spalten: Rechnung, Kunde, Kontakt (tel/mail), Typ, Faelligkeit, Verzug, | Betrag, letzte Mahnung, vorgeschlagene Stufe | |--> User waehlt aus + klickt "Mahnungen erzeugen" | -> ajax/createmahnung.php berechnet Gebuehr + Verzugszinsen, | persistiert llx_mahnung_mahnung, generiert PDF/ODT | |--> Alternativ "Sammelbrief erzeugen" | -> ajax/sammelbrief.php generiert + konkateniert PDFs | v card.php (Mahnung-Detailansicht) | Documents: generierte PDFs + Modellauswahl + Regenerate | Versand: Datum, Versandweg, Sendungsnummer, Tracking-Provider -> Deep-Link | Sendebelege: Upload (formfile->showdocuments), Scan-Button | Aktionen: Stornieren | Als uneinbringlich klassifizieren (nur Stufe 3) | Cron 06:00 (MahnungCronVersandReminder) |--> Mahnungen mit Status=ERSTELLT > N Tage unversendet -> Ntfy-Push | Zahlungseingang (BankImport / Manual) | v Trigger BILL_PAYED / PAYMENT_CUSTOMER_CREATE |--> alle offenen Mahnvorgaenge zur Rechnung -> status=erledigt | Endgueltig uneinbringlich (Mahnbescheid + Vollstreckung erfolglos) | v Stufe-3-Mahnung -> Button "Als uneinbringlich klassifizieren" |--> Facture::setCanceled($user, CLOSECODE_BADDEBT, $note) | -> fk_statut=3 (ABANDONED), close_code='badcustomer' | -> Mahnung wird storniert, Begruendung in note_private |--> Auf Kundenkarte erscheint rote Bonitaets-Warnbox |--> Beim Anlegen neuer Auftraege/Rechnungen: Warning-Banner | Steuerlich (Steuer-Modul): |--> EÜR ignoriert (liest llx_paiement, keine Zahlung = keine Einnahme) |--> UStVA filtert fk_statut IN (1,2) -> abandoned automatisch ausgeschlossen ``` ## Dateibaum ``` mahnung/ ├── core/modules/modMahnung.class.php Descriptor, Rechte, Cron, Hooks, Models │ (migrateVersandFelder + Pattern-Seed) ├── core/modules/mahnung/ │ ├── modules_mahnung.php Abstrakte Basis ModelePDFMahnung │ └── doc/ │ ├── pdf_standard_mahnung.modules.php TCPDF-Generator (DIN 5008) │ └── doc_generic_mahnung_odt.modules.php ODT-Template-Generator ├── core/triggers/interface_99_modMahnung_MahnungTriggers.class.php ├── core/boxes/box_mahnung_offen.php Widget: Offene Rechnungen + Mahnstufe ├── class/mahnung.class.php CRUD Mahnvorgang + generateDocument() │ + setVersand + trackingUrl + defaultProviderForWeg ├── class/mahnungstufe.class.php CRUD Stufen-Konfig ├── class/mahnungvorschlag.class.php Vorschlags-Service (Stufenermittlung, │ kundentyp/min_betrag-Filter, soc_phone/email) ├── class/mahnungtrackingpattern.class.php CRUD Tracking-Patterns + detectFromText ├── class/mahnungcron.class.php buildVorschlagsliste + versandReminder ├── class/mahnungntfy.class.php Ntfy-Wrapper ├── class/actions_mahnung.class.php Hook-Klasse: │ - addMoreActionsButtons (invoicecard) │ - completeTabsHead (invoice+thirdparty) │ - tabContentViewThirdparty (Bonitaets-Box) │ - formObjectOptions (invoice+ordercard Warning) ├── admin/setup.php Setup + Dokumentenmodell + Auto-Migration ├── admin/templatevars.php Template-Variablen-Referenz ├── admin/tracking_patterns.php CRUD + Live-Vorschau fuer Tracking-Patterns ├── ajax/createmahnung.php Bulk-Mahnung-Erzeugung ├── ajax/sammelbrief.php Sammelbrief-PDF-Konkatenation ├── ajax/sendmail.php E-Mail-Versand ├── ajax/regex_preview.php Live-Vorschau-Endpoint fuer Pattern-Setup ├── list.php Vorschlagsliste / Archiv (Select2-Filter) ├── card.php Detailansicht: Versand, Belege, Tracking, │ Uneinbringlich-Workflow ├── sql/llx_mahnung_*.sql Schema + Seed └── langs/{de_DE,en_US}/mahnung.lang ``` ## Lizenz GPL-3.0