Docs: README + CLAUDE.md auf Stand nach Phasen 1-6 bringen
All checks were successful
Deploy mahnung / deploy (push) Has been skipped
All checks were successful
Deploy mahnung / deploy (push) Has been skipped
README:
- Feature-Tabelle um Phase 1-6 erweitert: Select2-Filter, Versand-Erfassung,
Sendebeleg-Upload, Tracking-Patterns + Live-Vorschau, Beleg-Scan,
Versand-Reminder Cron, Bonitaets-Workflow.
- Neue Sektionen Datenbank, AJAX-Endpoints, Hooks & Trigger.
- MAHNUNG_VERSAND_REMINDER_DAYS zu Konstanten ergaenzt.
- Workflow-ASCII-Diagramm aktualisiert: Filter + Versand-Block + Belege-Scan
+ Uneinbringlich-Pfad + Steuer-Modul-Kompatibilitaet.
- Dateibaum: neue Files (mahnungtrackingpattern, tracking_patterns admin,
regex_preview ajax) + Methoden in actions_mahnung dokumentiert.
CLAUDE.md:
- Schema-Migration-Sektion (migrateVersandFelder beim Setup-Aufruf).
- Hooks-Stolperfallen: completeTabsHead mehrfach-Trigger.
- Filter-Syntax-Stolperfallen: USC-Syntax bei select_company,
search_socid=-1 als "nichts ausgewaehlt".
- Pipeline-Stolperfallen: ${{ commit_message }} via env: durchreichen.
- Versand & Bonitaet Sektion mit Kreuzverweisen auf KB #601-#609.
- Dolibarr-Versionshinweise um formconfirm-Textarea ergaenzt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3a49c67fbd
commit
5e91c87c99
2 changed files with 125 additions and 12 deletions
30
CLAUDE.md
30
CLAUDE.md
|
|
@ -1,7 +1,7 @@
|
|||
# CLAUDE.md — Mahnung-Modul
|
||||
|
||||
## Projekt
|
||||
Dolibarr Custom-Modul: 3-stufiges Mahnwesen nach BGB §288.
|
||||
Dolibarr Custom-Modul: 3-stufiges Mahnwesen nach BGB §288 + Versand-Tracking + Forderungsausfall-Workflow.
|
||||
|
||||
## Technisches
|
||||
- **numero**: 500038 (NICHT ändern — 500037 ist Eplan)
|
||||
|
|
@ -9,6 +9,13 @@ Dolibarr Custom-Modul: 3-stufiges Mahnwesen nach BGB §288.
|
|||
- **Prod-Pfad**: /mnt/appdata/firma/dolibarr-202509/modules/mahnung/
|
||||
- **Lokal**: Symlink /var/www/dolibarr/custom/mahnung → repo/
|
||||
- **Test-DB**: dolibarr_test auf 192.168.155.11
|
||||
- **Forgejo-Repo**: data/mahnung (NICHT data-it/ — historisch, soll bleiben)
|
||||
|
||||
## Schema-Migration
|
||||
- `modMahnung::migrateVersandFelder()` läuft automatisch beim Setup-Page-Aufruf
|
||||
- Idempotent via `SHOW COLUMNS LIKE` → fehlende Spalten via `ALTER TABLE ADD COLUMN`
|
||||
- Default-Tracking-Patterns werden via `MahnungTrackingPattern::seedDefaults()` geseedet (Check: `COUNT(*) > 0` → skip)
|
||||
- **Nach Deploy: User muss Setup-Page einmal aufrufen**, sonst fehlen die neuen Spalten
|
||||
|
||||
## Dokumentenmodell-System
|
||||
- `commonGenerateDocument()` fügt automatisch `doc_`/`pdf_` Prefix hinzu
|
||||
|
|
@ -21,8 +28,29 @@ Dolibarr Custom-Modul: 3-stufiges Mahnwesen nach BGB §288.
|
|||
- Zeigt ALLE offenen Rechnungen, nicht nur überfällige
|
||||
- Mahnstufe-Badge nur wenn Mahnung existiert, sonst Strich
|
||||
|
||||
## Hooks-Stolperfallen
|
||||
- **`completeTabsHead`** wird bei jedem Aufruf von `complete_head_from_modules()` getriggert — pro Karte mehrfach (core + external + remove). Filter auf `mode=add` + `filterorigmodule=external`, sonst doppelter Tab. (KB #601)
|
||||
- Hook-Kontexte: `invoicecard`, `thirdpartycard`, `ordercard` — letztere für Bonitäts-Warnings.
|
||||
|
||||
## Filter-Syntax-Stolperfallen
|
||||
- **`$form->select_company($selected, $htmlname, $filter, ...)`**: der `$filter`-Parameter erwartet **USC-Syntax** `(feld:operator:wert)`, NICHT plain SQL. Beispiel B2C: `(s.tva_intra:is:NULL) OR (s.tva_intra:=:'')`. Sonst SQL-Syntax-Error + 500. (KB #602)
|
||||
- **`search_socid=-1`** wird von `select_company` als "nichts ausgewählt" geliefert → im Filter-Check `> 0` statt `!empty()` nutzen.
|
||||
|
||||
## Pipeline-Stolperfallen
|
||||
- **`${{ github.event.head_commit.message }}` NIE direkt in `run:`-Skript interpolieren** — bei Sonderzeichen (Klammern, Backticks) bricht Bash. Immer via `env:` durchreichen. (KB #603)
|
||||
- `[deploy]`-Tag im Commit nötig, sonst kein Auto-Deploy.
|
||||
|
||||
## Versand & Bonität (Phase 6)
|
||||
- Versand-Felder: `date_versand`, `versandweg`, `tracking_nr`, `tracking_provider` an `llx_mahnung_mahnung`
|
||||
- Tracking-URLs aus DB (`llx_mahnung_trackingpattern`) via `MahnungTrackingPattern::urlFor()`, Fallback: `Mahnung::trackingUrl()` (hardcoded)
|
||||
- Beleg-Upload: `formfile->showdocuments('mahnung', $ref, $filedir, ...)` — `$conf->mahnung->dir_output` wird von Dolibarr automatisch gesetzt (KB #605), kein Custom-Setup nötig
|
||||
- Beleg-Scan: `pdftotext` ist im `90-Dolibarr-Prod-Custom`-Container drin (`/usr/bin/pdftotext`); Pattern-Match via `MahnungTrackingPattern::detectFromText()`
|
||||
- Uneinbringlich-Klassifikation: `Facture::setCanceled($user, CommonInvoice::CLOSECODE_BADDEBT, $note)` → setzt `fk_statut=3` + `close_code='badcustomer'` (KB #606)
|
||||
- Steuer-Modul kompatibel: EÜR ignoriert (liest nur `llx_paiement`), UStVA filtert `fk_statut IN (1,2)` automatisch (KB #607)
|
||||
|
||||
## Dolibarr-Versionshinweise
|
||||
- `f.fk_statut` statt `f.statut` (seit Dolibarr 22.x)
|
||||
- `verifCsrf()` existiert nicht — CSRF via `newToken()` + GETPOST('token')
|
||||
- `dol_mkdir()` gibt 0 zurück wenn Verzeichnis bereits existiert (nicht false)
|
||||
- `dol_dir_list()` gibt `fullname` zurück (nicht `fullpath`)
|
||||
- `$form->formconfirm()` unterstützt textarea-Feld via `$formquestion`-Array (KB #609)
|
||||
|
|
|
|||
107
README.md
107
README.md
|
|
@ -4,13 +4,13 @@ Mahnwesen-Modul für Dolibarr ERP: tägliche Vorschlagsliste überfälliger Rech
|
|||
|
||||
## Status
|
||||
|
||||
Version **0.2.0** — ODT-Template-System, Widget, Dokumentenmodell-Verwaltung.
|
||||
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` (default deaktiviert) |
|
||||
| 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` |
|
||||
|
|
@ -24,8 +24,20 @@ Version **0.2.0** — ODT-Template-System, Widget, Dokumentenmodell-Verwaltung.
|
|||
| 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` |
|
||||
| Widget: Offene Rechnungen mit Mahnstufe | `box_mahnung_offen` — wie Standard-Widget, plus Mahnstufe-Badge mit Link |
|
||||
| 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/<MAHN-Ref>/` |
|
||||
| **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 + Pattern-Matching → Sendungsnummer-Vorschlag) | Button "Belege scannen" auf `card.php` |
|
||||
| **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
|
||||
|
||||
|
|
@ -109,11 +121,47 @@ Vollständige Liste: **Setup → Mahnwesen → Verfügbare Template-Variablen**
|
|||
| `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
|
||||
Cron 06:00 (MahnungCronBuildVorschlag)
|
||||
|
|
||||
|--> ueberfaellige Rechnungen einsammeln
|
||||
|--> Stufe ermitteln (Stufe 1 ab frist_tage Verzug,
|
||||
|
|
@ -123,6 +171,9 @@ Cron 06:00
|
|||
|
|
||||
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,
|
||||
|
|
@ -131,10 +182,33 @@ list.php (Vorschlagsliste)
|
|||
|--> 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
|
||||
|
|
@ -142,6 +216,7 @@ Zahlungseingang (BankImport / Manual)
|
|||
```
|
||||
mahnung/
|
||||
├── core/modules/modMahnung.class.php Descriptor, Rechte, Cron, Hooks, Models
|
||||
│ (migrateVersandFelder + Pattern-Seed)
|
||||
├── core/modules/mahnung/
|
||||
│ ├── modules_mahnung.php Abstrakte Basis ModelePDFMahnung
|
||||
│ └── doc/
|
||||
|
|
@ -150,18 +225,28 @@ mahnung/
|
|||
├── 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)
|
||||
├── class/mahnungcron.class.php Cron-Job
|
||||
├── 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 (invoicecard + thirdpartycard)
|
||||
├── admin/setup.php Setup + Dokumentenmodell-Verwaltung
|
||||
├── 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
|
||||
├── list.php Vorschlagsliste / Archiv
|
||||
├── card.php Detailansicht + Dokumentenliste
|
||||
├── 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
|
||||
```
|
||||
|
|
|
|||
Loading…
Reference in a new issue