Eddy-Feedback: Die Differenz-zur-Faelligkeit (z.B. -13.5 T) war unintuitiv
(Kopfrechnen noetig) und "(spaeter als ueblich)" hat die Widget-Spalte
gesprengt.
- Prognosedatum jetzt am RECHNUNGSDATUM verankert: datef + Oe Tage nach
Rechnungseingang (avg_pay). Das ist die klassische Days-to-Pay-Kennzahl,
vermeidet Prognosen vor dem Rechnungsdatum und ist direkt lesbar.
- Sichtbare Zahl = "Oe X T nach Rechnung" (positiv) statt Differenz zur
Faelligkeit. Ampel-Icon bleibt auf der Faelligkeits-Skala (diff) -> weiter
Paritaet zur Zahlungsverhalten-Box der Kundenkarte.
- "(spaeter als ueblich)" als Text entfernt: bei verstrichener Prognose
wird stattdessen nur das DATUM rot gefaerbt (Zeile bleibt schmal),
Erklaerung steckt im Tooltip.
- getZahlprognose liefert zusaetzlich avg_pay; buildPrognoseCell bekommt
das Rechnungsdatum durchgereicht. Neuer Lang-Key MahnungProgNachRechnung,
Tooltip umformuliert.
Lokal gegen die Test-DB verifiziert (Datum aus datef+avg_pay, Rot nur bei
verstrichener Prognose, Zukunfts-Rechnung ohne Rot, php -l sauber).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fix nach Eddys Beobachtung: Kunde mit Historie auf der Kundenkarte
(BuchhaltungsWidget bewertet ab n>=1) erschien im Widget als "keine
Historie", weil MAHNUNG_PROGNOSE_MIN_N auf 3 stand.
- MIN_N Default 3 -> 1: Paritaet zur Zahlungsverhalten-Box, die ebenfalls
ab der 1. bezahlten Rechnung bewertet. Weiter per Konstante erhoehbar.
- "(ueberfaellig)" -> "(spaeter als ueblich)": Das Flag greift wenn das
Prognosedatum verstrichen und die Rechnung noch offen ist - das kann
schon VOR der formellen Faelligkeit passieren (Fruehzahler). "ueberfaellig"
war dafuer das falsche Wort. Neuer Lang-Key MahnungProgSpaeterAlsUeblich.
- Prognosedatum + OE-Verzug jetzt aus dem EXAKTEN Mittelwert (Timestamp
statt gerundeter Tage), Anzeige mit einer Nachkommastelle -> deckt sich
1:1 mit "Differenz" auf der Kundenkarte (z.B. -3.1 T -> Faelligkeit-3.1).
Lokal gegen die Test-DB verifiziert (n=1/n=2 werden gezeigt, Flag nur bei
verstrichener Prognose, Zukunfts-Faelligkeit ohne Flag, php -l sauber).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Neue Spalte "Vsl. Zahlung" in box_mahnung_offen: je offener Rechnung
Prognose (Faelligkeit + round(Oe-Verzug)) aus dem bisherigen Zahlungs-
verhalten des Kunden, mit Ampel-Icon + Bewertungsstufe + Tooltip.
- Skala 1:1 aus BuchhaltungsWidget uebernommen (KB #886), damit die
Ampel zur "Zahlungsverhalten"-Box auf der Kundenkarte passt: 5 Stufen
Vorbildlich/Puenktlich/Spaetzahler/Verspaetet/Problematisch anhand
Oe-Tage nach Faelligkeit, gleiche Schwellen + Farben.
- Berechnung als self-contained Kopie (getZahlprognose, 1 Query je
Kunde/Request gecacht) - keine Laufzeit-Abhaengigkeit auf das
BuchhaltungsWidget.
- Prognose ueberschritten + Rechnung noch offen -> "(ueberfaellig)"
als zusaetzliches Mahnsignal.
- Mindest-Stichprobe MAHNUNG_PROGNOSE_MIN_N (Default 3), sonst
"keine Historie". Neue Lang-Keys MahnungProg* (de_DE + en_US).
- $langs->transnoentities() statt trans() genutzt (sonst leere %s
durch doppeltes sprintf bzw. doppeltes &-Encoding, siehe KB #897).
End-to-end via CLI-Harness gegen die lokale Test-DB verifiziert
(alle 5 Stufen, Overdue-Zweig, Empty-State, php -l sauber).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summenzeile zeigt jetzt Netto und Brutto (aus f.total_ttc der Rechnung,
nicht aus Netto hochgerechnet - damit bleiben Reverse-Charge, Steuer-
befreiung und Kleinunternehmerregelung korrekt). Neue Lang-Keys
MahnungBoxNetto/MahnungBoxBrutto in de_DE + en_US.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wenn alle Rechnungen bezahlt sind, blieb info_box_contents leer und
ModeleBoxes::showBox renderte keinen Widget-Rahmen mehr. Widget kam
auch nach neuen Rechnungen nicht zurück. Fix: bei 0 Treffern eine
Platzhalter-Zeile "Keine offenen Kundenrechnungen" einfügen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tms war als reines TIMESTAMP angelegt -> unter explicit_defaults_for_timestamp
NULL DEFAULT NULL, blieb daher bei jedem UPDATE leer. Jetzt Dolibarr-Standard
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP fuer mahnung/stufe/
trackingpattern. Neue idempotente Migration migrateTimestampSpalten() im init()
befuellt Alt-NULLs aus datec und stellt die Spalte per ALTER TABLE um.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Umlaute in allen lang-Dateien korrigiert. Alle hardcodierten deutschen Strings
in 22 PHP-Dateien durch $langs->trans('Key') ersetzt. Neue Schlüssel für
Cron-Meldungen, Dokument-Aktionen, Bonität, Vorschlag-Status, Template-Vars u.a.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bonitaets-Anzeige:
- Hook tabContentViewThirdparty rendert prominente rote Warnbox auf der
Kundenkarte wenn fk_statut=3 + close_code=badcustomer existiert. Zeigt
Anzahl, Gesamtsumme, Datum letzter Abschreibung + Link zur Detail-Liste.
- Hook formObjectOptions zeigt kompakte Warn-Zeile auf ordercard und
invoicecard wenn der Kunde Forderungsausfaelle hat.
- ordercard zum module_parts.hooks.data ergaenzt.
Uneinbringlich-Button:
- Auf Mahnung-Karten der Stufe 3, Status >= ERSTELLT, nicht storniert,
Rechnung noch nicht abandoned.
- Bestaetigungs-Dialog mit Begruendungs-Textfeld (Default-Text setzt
das aktuelle Datum ein).
- Ruft Facture::setCanceled mit CommonInvoice::CLOSECODE_BADDEBT.
- Mahnung wird storniert + Begruendung in note_private festgehalten.
Steuer-Modul kompatibel: EÜR liest nur llx_paiement (keine Zahlung =
keine Einnahme), UStVA filtert fk_statut IN (1,2) — abandoned Rechnungen
werden automatisch korrekt ausgeschlossen. Bei Ist-Versteuerung damit
buchhalterisch sauber, kein manueller Eingriff noetig.
Lang-Keys: 16 neu (de_DE + en_US) fuer Bonitaets-Box + Uneinbringlich-Workflow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Neuer Cron-Job MahnungCronVersandReminder (taeglich):
- Sucht in llx_mahnung_mahnung Status=ERSTELLT (1) + date_versand IS NULL
+ datec < NOW() - INTERVAL N DAY.
- N steht in der Konstante MAHNUNG_VERSAND_REMINDER_DAYS (Default 2).
- Bei Treffern: Ntfy-Push (Topic MAHNUNG_NTFY_TOPIC) mit Titel + Liste
der bis zu 8 Mahnungen ("MAHN2026-0042 (Stufe 2, 3 Tage alt) — Kunde").
- Optional GlobalNotify-Badge "mahnung_versand" wenn GlobalNotify aktiv.
Modul-Descriptor:
- Cronjobs-Array um Reminder ergaenzt (frequency 1d, priority 55, status 1).
Lang-Keys: 2x (de_DE + en_US) fuer Cron-Label + Description.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Rechnungen ohne Mahnung: "—" als Zeichen
- Rechnungen mit Mahnung: farbiger Badge verlinkt auf card.php der Mahnung
- Mahnung-ID per Subquery geholt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Widget basiert jetzt 1:1 auf box_factures_imp.php:
- Alle offenen Rechnungen (nicht nur ueberfaellige)
- Status-Icon wie Original (LibStatut)
- Summenzeile ueber alle offenen (separate Query)
- Link zur Rechnungsliste im Header
Plus: Extra-Spalte Mahnstufe mit farbigem Badge (wenn vorhanden)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- box_mahnung_offen.php: require_once mahnung.class.php nach oben verschoben,
da Mahnung::STATUS_STORNIERT in der SQL-Query vor dem bisherigen Include benutzt wurde
- setup.php: actions_setmoduleoptions.inc.php vor llxHeader() verschoben
(sonst scheitert der ODT-Upload wegen "headers already sent"), Duplikat entfernt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>