Commit graph

13 commits

Author SHA1 Message Date
0244a5b07e feat(mahnung): Mailversand ueber FormMail, Versandprotokoll, HTML-Mails
Phase 13/14 abgeschlossen. Der Mailversand war zuvor KAPUTT: ajax/sendmail.php
war bereits zur Funktionsbibliothek umgebaut, card.php postete aber weiterhin
per JS dagegen.

Mailformular (FormMail)
- card.php nutzt jetzt Dolibarrs Standard-Mailformular (action=presend/send):
  Empfaenger (Firma + alle Ansprechpartner), Betreff, Text und Anhang sichtbar
  und aenderbar. Gesendet wird ausschliesslich ueber mahnungSendeErinnerungsMail().
- Anhang = unveraenderte Original-Rechnungs-PDF, wird bei Bedarf nacherzeugt.
  Eigener Parameter mailinit statt mode=init, weil get_form() bei mode=init die
  Anhangsliste selbst leert.
- HTML-Mails: DolEditor im Setup + withfckeditor=-1 im Formular (folgt
  FCKEDITOR_ENABLE_MAIL wie Dolibarrs eigene Mailvorlagen).
- Klartext bleibt Klartext: GETPOST('restricthtml') jagt jeden Nicht-HTML-Text
  durch dol_nl2br() — mahnungBodyEntkleiden() nimmt nur dieses Artefakt zurueck
  und laesst echte Formatierung unangetastet.
- Platzhalter jetzt auch in Dolibarr-Schreibweise (__REF__, __DATE_YMD__,
  __AMOUNT_FORMATED__, __DATE_DUE_YMD__, __FRIST_TAGE__ ...), Liste sichtbar im Setup.
- Absender-Adresse und -Name konfigurierbar (MAHNUNG_EMAIL_SENDER[_NAME]).
- Erneuter Versand moeglich (force aus dem Status abgeleitet, nicht aus dem
  Request — Doppelversand-Schutz bleibt wirksam).

Versandprotokoll (neue Tabelle llx_mahnung_mailprotokoll)
- Jede versendete Erinnerung wird mit Empfaenger, Kopie, Betreff, Text und
  Anhangsnamen festgehalten, einsehbar unter Versandstatus. Historie statt
  Spalten am Vorgang, weil erneut gesendet werden kann.
- Lazy-Migration legt die Tabelle an (DB_VERSION 0.4.0), kein Reaktivieren noetig.

Haertung nach Code-Review (21 bestaetigte Funde)
- Anhang liess sich nicht abwaehlen (wurde sofort wieder eingehaengt)
- Upload/Entfernen ohne Rechtepruefung; Temp-Verzeichnis pro Vorgang getrennt
- Teilzahlung zwischen Oeffnen und Senden fuehrt zurueck ins Formular
- Empfaenger: Semikolon-Trenner, keine stillen Verwerfungen, Dubletten, CR/LF
- CSRF: presend + Core-Dateiaktionen (confirm_deletefile, renamefile, sendit,
  linkit) token-pflichtig
- Externe Benutzer sehen nur eigene Vorgaenge; Abschreiben verlangt facture.creer

UI
- Mahnstufe nur noch EINE Darstellung (Badge), Farbskala zentral in
  lib/mahnung_ui.lib.php statt doppelt gepflegt
- Zahnrad oben rechts in die Einstellungen (nur mit Recht mahnung.setup)
- Original-Rechnung unter Verknuepfte Dokumente mit Vorschau, Groesse in KB
- PDF-Einleitungstext nur noch, wo ueberhaupt ein PDF entsteht

Sprachdateien de_DE/en_US deckungsgleich, 9 tote Keys entfernt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 21:31:25 +02:00
fdd2b17ab4 Widget-Prognose: intuitive "Ø X T nach Rechnung" + rotes Datum statt Text [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
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>
2026-07-19 11:48:08 +02:00
4997a78599 Widget-Prognose: Paritaet zur Kundenkarten-Box + Frueh-Signal statt "ueberfaellig" [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
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>
2026-07-19 11:39:25 +02:00
adfeafa09b Widget: Zahlungsprognose-Spalte (Skala aus BuchhaltungsWidget/KB #886) [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
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>
2026-07-19 11:30:09 +02:00
7532770599 Widget offene Rechnungen: Brutto-Summe zusaetzlich zur Netto-Summe [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
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>
2026-07-10 08:38:17 +02:00
84e9692ffe Widget offene Rechnungen: Zaehler im Kopf + konfigurierbare Zeilenanzahl [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
- Kopf-Badge zeigt jetzt die tatsaechliche Anzahl offener Rechnungen statt "..."
- Neues Setup-Select MAHNUNG_BOX_MAXLINES (Alle/5/10/20/30/50)
- Widget laedt alle offenen Rechnungen (korrekter Zaehler), rendert nur die
  eingestellte Anzahl + "..."-Ueberlaufzeile; Default 0 = alle anzeigen
- Lang-Keys de_DE/en_US ergaenzt, (%s) aus Widget-Titel entfernt

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 12:56:03 +02:00
73e377dc01 fix(box): Widget bleibt sichtbar wenn keine offenen Rechnungen vorhanden [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 12s
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>
2026-05-24 07:38:09 +02:00
10cf41a687 i18n: Alle Texte über $langs->trans() — ~100 neue Sprachschlüssel de_DE + en_US [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
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>
2026-05-13 16:25:50 +02:00
d1cec1b46a Widget: Mahnstufe-Badge verlinkt auf Mahnung, Strich bei keiner Mahnung [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
- 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>
2026-05-10 18:48:16 +02:00
b68ef498ee Fix: Widget Spaltenreihenfolge — Mahnstufe vor Status, Status schmal rechts [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-10 18:46:16 +02:00
ec0c843492 Fix: Widget zeigt alle offenen Rechnungen wie Original + Mahnstufe [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
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>
2026-05-10 18:44:45 +02:00
7387d3ac1e Fix: Widget Fatal Error + Setup Upload-Include verschoben [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
- 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>
2026-05-10 18:40:30 +02:00
993ac50c0c Feature: ODT-Template-System, Widget, Dokumentenliste, Templatevariablen-Referenz [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
- ODT-Template-System: Pro Mahnstufe eigenes Template (mahnung_stufe1/2/3.odt),
  Fallback auf generisches Template; Basis-Klasse ModelePDFMahnung,
  pdf_standard_mahnung (TCPDF refactored), doc_generic_mahnung_odt (ODTPHP)
- Widget box_mahnung_offen: Überfällige Rechnungen mit Mahnstufe-Badge (blau/orange/rot)
- card.php: Dokumentenliste mit Lupe (PDF-Vorschau), Download, Modellauswahl
- admin/templatevars.php: Referenzseite aller verfügbaren ODT-Variablen
- admin/setup.php: Dokumentenmodell-Verwaltung, Upload-Bereich mit Benennungskonvention
- mahnung.class.php: generateDocument() + socid-Alias für commonGenerateDocument()
- modMahnung.class.php: models=1, MAHNUNG_ADDON_PDF/ODT_PATH-Konstanten,
  document_model-Registrierung in init(), Widget registriert
- mahnungpdf.class.php entfernt, Logik in pdf_standard_mahnung.modules.php

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-10 18:28:24 +02:00