Commit graph

41 commits

Author SHA1 Message Date
41765cc5df docs(claude): Widget-Empty-State-Pflicht in CLAUDE.md dokumentiert [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
Verweis auf KB #682: bei $num==0 muss Platzhalter-Zeile in
info_box_contents gesetzt werden, sonst verschwindet das Widget.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 07:44:13 +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
bfc89917b1 fix(mahnung): tms-Spalten auf ON UPDATE CURRENT_TIMESTAMP umstellen [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
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>
2026-05-16 18:13:25 +02:00
d49e178554 fix(mahnung): Button per JS ans Ende der Aktionsleiste schieben statt Flex-Spacer [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
Vorher: Flex-Spacer-Trick (flex-basis:100%) sollte den Button in zweite Zeile
zwingen — funktioniert aber nur wenn .tabsAction ein Flexbox-Container mit
flex-wrap ist. Im AwlDark-Theme ist das nicht der Fall → Button landete einfach
am Anfang der Aktionsleiste.

Jetzt: kurzes JS-Snippet verschiebt #btn-mahnung-create per insertBefore vor
den ersten .butActionRefused (= disabled "Löschen" / "Auf anderen Kunden
übertragen" — typisch sichtbar bei freigegebener Rechnung). Fallback: appendTo
ans Ende der .tabsAction.

So landet "Mahnung erstellen" optisch direkt bei den Verwaltungs-Buttons am
rechten/unteren Ende, wie Eddy es wollte.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 10:39:23 +02:00
7031bea118 fix(mahnung): Button via direktem print statt resprints — sonst kein Output [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
REGRESSION aus letztem Commit: $this->resprints wurde nicht gerendert.

addMoreActionsButtons-Hook in compta/facture/card.php wertet zwar $reshook aus
(empty → Default-Buttons), printet aber $hookmanager->resPrint an dieser Stelle
nicht — anders als bei formObjectOptions. Der Hook muss seinen HTML-Output
direkt selbst per print ausgeben.

Direkter print ist hier sicher: der Hook wird innerhalb des dafür vorgesehenen
<div class="tabsAction"> aufgerufen, kein HTML-Layoutbruch möglich.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 10:33:17 +02:00
e7375ac559 fix(mahnung): Button "Mahnung erstellen" nur bei freigegebener + offener Rechnung, in zweiter Zeile [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
Vorher: Button wurde immer gezeigt — auch bei Entwurf, bezahlt, storniert
(zwar disabled mit Tooltip, aber sichtbar).

Jetzt: Hook gibt nichts aus wenn:
- Entwurf (statut == 0)
- Bezahlt (paye != 0)
- Storniert / abandoned (statut == 2 / 3)

Nur bei statut >= 1 UND paye === 0 erscheint der Button. Überfällig-Logik
entscheidet danach nur noch ob aktiv (mit URL) oder disabled (mit Tooltip).

Zusätzlich: Flex-Spacer (flex-basis:100%) wird DIREKT vor den Button gestellt
→ Button landet in eigener zweiter Zeile unterhalb der primären Aktionen,
neben "Import Zeilen / Löschen / Auf anderen Kunden übertragen".

Output via \$this->resprints statt direktem print — verhindert HTML-Layoutbruch
bei Hook-Aufrufen mitten in Tabellen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 10:29:50 +02:00
c8c16f1f85 Verzugszinsen werden für nicht-versandte Mahnungen live neu berechnet [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
Mahnungen im Status "Erstellt" (noch nicht versandt) werden beim Aufruf
der card.php mit der aktuellen Stufen-Konfiguration neu berechnet.
Ändert sich der Zinssatz-Override in den Einstellungen, wirkt das
sofort auf alle offenen Mahnungen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 17:34:17 +02:00
48c1b06058 Fix: Zinssatz-Hilfetext zeigt immer Standard-Satz, nicht Override-Wert [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
$effB2c/$effB2b enthielt den Override-Wert statt den Standard.
Jetzt wird immer Basiszins + Aufschlag angezeigt (z.B. "1,27 + 5,0 % = 6,27 %").

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 17:31:11 +02:00
ce525cee18 Setup: Zinssatz-Override zeigt effektiven Satz + Hilfetext [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
- Eingabefelder zeigen Placeholder mit Standard-Zinssatz (Basiszins + Aufschlag)
- Grauer Hilfetext: "Leer = Standard (1,27 + 5,0 % = 6,27 %), 0 = keine Zinsen"
- Effektiver Zinssatz wird live aus globalen Einstellungen berechnet
- Prod-DB: Stufe 1 Override von 0.0000 auf NULL korrigiert (direkt in DB)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 17:28:11 +02:00
98f3f1a04b Übernehmen setzt Versanddatum + Versandweg automatisch [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
apply_tracking setzt jetzt auch date_versand (heute) und
versandweg (abgeleitet vom Provider) wenn noch leer.
Kein extra Speichern-Klick mehr nötig.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 17:03:21 +02:00
9e3776fef3 Fix: scan_belege nutzte undefiniertes $upload_dir [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
$upload_dir wird erst nach den Action-Handlern definiert.
scan_belege-Block berechnet den Pfad jetzt selbst.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 16:57:36 +02:00
7157f0d8c3 Fix: Form-Feed-Zeichen von pdftotext verhinderte OCR-Fallback [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
pdftotext gibt bei Bild-PDFs 0x0C (Form Feed) zurück — trim() entfernt
das nicht. Dadurch wurde der OCR-Fallback nie ausgelöst.
Jetzt trim() mit expliziter Zeichenliste inkl. \x0C.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 16:55:24 +02:00
f776d121c5 Fix: Layout volle Breite statt fichehalfleft [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
fichehalfleft entfernt — Stammdaten und Versand-Tabelle
nutzen jetzt die volle Seitenbreite statt nur 55%.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 16:53:04 +02:00
b588937956 Fix: Tabellen-Layout fichehalfleft + Einschreiben-Pattern für OCR [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
- fichehalfleft Container für korrekte Dolibarr-Rahmen bei Stammdaten + Versand
- Einschreiben-Regex in DB updated: optionale Leerzeichen (OCR-freundlich)
- detectFromText() entfernt Leerzeichen aus erkannten Nummern (OCR-Normalisierung)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 16:45:56 +02:00
7196f2594c OCR für Bild-PDFs beim Belege-Scannen + Feedback-Meldung [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
Wenn pdftotext keinen Text findet, wird ocrmypdf (Tesseract OCR)
auf das PDF angewendet bevor erneut nach Sendungsnummern gesucht wird.
Bei leerem Ergebnis erscheint jetzt eine Hinweismeldung statt
stummem Seiten-Reload.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 16:40:33 +02:00
e785e53d8c UI: Stammdaten-Tabelle mit fichecenter/underbanner gerahmt [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
Dolibarr-Standard-Klassen (fichecenter, underbanner, tableforfield)
für konsistentes Card-Layout wie bei Rechnungen/Bestellungen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 16:38:29 +02:00
b8c00daa55 Fix: Sendebelege-Liste nicht sichtbar (fehlendes print) + Styling Versand-Bereich [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 16s
showdocuments() gibt String zurück — fehlte print davor.
Versand & Belege Bereich mit fichecenter/underbanner gerahmt.
Sendebelege-Titel als load_fiche_titre statt h3.
hideifempty=0 damit Sektion immer sichtbar.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 16:35:42 +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
80d92042bc Fix: Menü-Navigation, GlobalNotify-URL, Dokument-Upload + -Löschen [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
- GlobalNotify-URL: relativer Pfad statt absoluter (DOL_MAIN_URL_ROOT ohne
  Protokoll führte zu kaputten Seiten-URLs im Browser); buildAbsoluteUrl()
  prüft jetzt auf fehlendes http(s)://
- Menü-Navigation: mainmenu=billing&leftmenu=mahnung in allen list.php-Links
  ergänzt (createmahnung.php Redirect, Filter-Form, Hook-Links, Cron-Pfade)
- card.php Dokumente: Lupe direkt neben Dateinamen, Löschen-Button pro Datei
- card.php Upload: actions_linkedfiles.inc.php eingebunden (vor llxHeader),
  upload_dir korrekt gesetzt — showdocuments() zeigt jetzt Upload-Formular
- Redundante Variablen-Definitionen (mahnungSafeRef, files.lib require) entfernt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 15:36:58 +02:00
5e91c87c99 Docs: README + CLAUDE.md auf Stand nach Phasen 1-6 bringen
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>
2026-05-11 13:28:36 +02:00
3a49c67fbd Bonitaets-Workflow: Warnbox Kundenkarte + Uneinbringlich-Button Stufe 3 [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
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>
2026-05-11 13:17:44 +02:00
e833891804 Hotfix: 500-Error beim Kundentyp-Filter — select_company-Filter muss USC-Syntax sein [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
Bug:
- Mein letzter Commit hat einen plain-SQL-Filter an select_company uebergeben.
  Dolibarrs select_thirdparty_list reicht den Filter durch
  forgeSQLFromUniversalSearchCriteria, das erwartet aber USC-Syntax
  feld:operator:wert in Klammern. Plain-SQL fuehrt zu SQL-Syntax-Error
  und 500-Antwort.

Fix:
- B2B-Filter: (s.tva_intra:isnot:NULL) AND (s.tva_intra:!=:'')
- B2C-Filter: (s.tva_intra:is:NULL) OR (s.tva_intra:=:'')

Zusatz-Fixes aus dem Log:
- search_socid=-1 (von select_company als "nichts ausgewaehlt" gerendert)
  wurde irrtuemlich als Filter auf fk_soc=-1 angewendet. Jetzt nur als
  Filter genutzt wenn > 0.
- Beim Auto-Submit des Kundentyp-Selects wird search_socid auf "" gesetzt,
  damit eine zuvor ausgewaehlte (jetzt evtl. ausgefilterte) Kunden-ID
  nicht stehen bleibt.

KB-Eintrag #602 zur USC-Syntax angelegt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:46:19 +02:00
3e67a876c1 Vorschlagsliste UX: B2B/B2C-Filter wirkt direkt auf Kunden-Dropdown, Skip-Grund-Zelle harmonisiert [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
Kundentyp filtert das Kunden-Dropdown:
- select_company bekommt SQL-Filter "s.tva_intra IS NOT NULL AND s.tva_intra <> ''"
  bzw. "s.tva_intra IS NULL OR s.tva_intra = ''" je nach B2B/B2C-Wahl.
- Das Kundentyp-Select hat onchange=this.form.submit, sodass das Dropdown
  ohne extra Klick auf "Suche" direkt neu geladen wird.

Skip-Grund-Zelle:
- opacitymedium-Klasse von td auf inneres span verschoben. Manche Themes
  rendern td.opacitymedium mit eigenem Border-Verhalten — das hatte zu
  sichtbarem Rahmen-Unterschied in der Uebersprungen-Tabelle gefuehrt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:34:57 +02:00
3a016ce999 Pipeline-Fix: Commit-Message als ENV-Variable durchreichen statt String-Interpolation [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
Bug: ${{ github.event.head_commit.message }} wurde direkt in den
Bash-Script-Text eingefuegt. Sobald die Commit-Message Klammern,
Backticks oder andere Shell-Sonderzeichen enthielt, kam Syntaxfehler
"line 9: syntax error near unexpected token" und der ganze Deploy
fiel um. Phase 2, 3 und 5 waren betroffen, Phase 4 ging durch
weil zufaellig keine Klammern in der Message waren.

Zusaetzlich Sicherheits-Aspekt: Shell-Injection war moeglich, wenn
jemand eine Commit-Message mit Befehlssubstitution committet.

Fix:
- COMMIT_MSG via env: an den Step uebergeben statt im Run-Block
  per Expression einzusetzen.
- RUN_NUMBER, NTFY_AUTH und GIT_TOKEN gleichzeitig via env: harten
  fuer Konsistenz und Sicherheit.
- printf %s statt echo fuer mehrzeilige Messages.
- Klammern-frei verifiziert in dieser Commit-Message.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:28:30 +02:00
660e91e65d Versand-Reminder Cron + Ntfy-Push fuer unversendete Mahnungen [deploy]
Some checks failed
Deploy mahnung / deploy (push) Failing after 4s
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>
2026-05-11 12:08:44 +02:00
216c185fb7 Beleg-Scan: Sendungsnummer aus hochgeladenen PDFs erkennen [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
Neuer Button "Belege scannen" im Versand-Block der Mahnungs-Karte:
- Action scan_belege durchlaeuft alle Files in DOL_DATA_ROOT/mahnung/<MAHN-Ref>/
- PDFs werden via pdftotext (CLI, mit Verfuegbarkeits-Check) extrahiert
- txt/html werden direkt eingelesen (HTML mit strip_tags)
- Pro Datei wird MahnungTrackingPattern::detectFromText() angewendet —
  matched gegen alle aktiven Patterns nach priority DESC
- Treffer landen in $_SESSION als Vorschlag (file, provider, nr, url, label)

UX:
- Vorschlags-Banner mit gruener Linke ueber dem Beleg-Bereich
- Pro Vorschlag: Datei-Icon, Pattern-Label, Sendungsnummer als <code>,
  externer Link zur Sendungsverfolgung, "Uebernehmen"-Button
- "Uebernehmen" (action=apply_tracking) speichert tracking_nr +
  tracking_provider an der Mahnung und leert Session
- "Verwerfen" (action=dismiss_tracking) entfernt nur Session-Eintrag

Fallback:
- Wenn pdftotext nicht im Container verfuegbar: Warnmeldung im UI,
  txt/html werden trotzdem verarbeitet.

OCR fuer Bilder (PNG/JPG) bewusst noch nicht enthalten — separater Schritt
mit Container-Anpassung (Tesseract) wenn gewuenscht.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:07:09 +02:00
56954d68f3 Konfigurierbare Tracking-Patterns mit Live-Vorschau [deploy]
Some checks failed
Deploy mahnung / deploy (push) Failing after 4s
Datenmodell:
- Neue Tabelle llx_mahnung_trackingpattern (provider, label, regex,
  url_template, priority, active). Auto-Anlage + Default-Seed im setup.php
  und in modMahnung::init() — idempotent.

Default-Patterns (priority hoeher = spezifischer, zuerst gepruef):
- DHL Paket 20-stellig (90), DPAG Einschreiben RR...DE (85), UPS 1Z... (80),
- DHL 11-stellig Online-Frankierung (30), Hermes 14-stellig (25), DPD (20).

Setup-Seite admin/tracking_patterns.php:
- CRUD (Anlegen/Bearbeiten/Aktivieren-Deaktivieren/Loeschen)
- Live-Vorschau: Regex + Beispieltext + URL-Template werden waehrend
  des Tippens (debounce 300ms) via ajax/regex_preview.php ausgewertet.
  UI zeigt: Regex-Syntax-Status, gefundene Sendungsnummer, vollstaendige
  Tracking-URL (anklickbar).
- Validierung: Delimiter / # ~ Whitelist, https://-Pflicht, {nr}-Platzhalter,
  max 255 Zeichen Regex.

AJAX-Endpoint ajax/regex_preview.php:
- ReDoS-Schutz: max 10 KB Sample, pcre.backtrack_limit=100k.
- POST-only (mit Setup-Recht), JSON-Response.

card.php:
- tracking-URL kommt jetzt aus MahnungTrackingPattern::urlFor() (DB-Lookup
  nach Provider) statt hardcoded Mahnung::trackingUrl() — letztere bleibt
  als Fallback.

Setup-Seite: neuer Button "Tracking-Muster (Regex)" oben rechts.

Lang-Keys: 23 neue (de_DE + en_US) fuer Pattern-CRUD + Live-Vorschau.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 12:04:42 +02:00
bb610a7594 Versand-Erfassung + Sendebeleg-Upload pro Mahnung [deploy]
Some checks failed
Deploy mahnung / deploy (push) Failing after 4s
Datenmodell (llx_mahnung_mahnung):
- Neue Spalten: date_versand, versandweg, tracking_nr, tracking_provider.
- Idempotente Migration via modMahnung::migrateVersandFelder() — laeuft
  automatisch beim ersten Setup-Aufruf nach dem Deploy (SHOW COLUMNS-Check,
  fehlende Spalten werden per ALTER TABLE ergaenzt).

Mahnung-Klasse:
- setVersand() — speichert Datum + Weg + optional Tracking + setzt Status
  automatisch auf VERSENDET wenn vorher <= ERSTELLT.
- defaultProviderForWeg() — Mapping versandweg → tracking_provider
  (dhl→dhl, einschreiben→dpag, dpd→dpd, hermes→hermes, ups→ups).
- trackingUrl() — Deep-Link-Helper fuer DHL, Deutsche Post, DPD, Hermes, UPS.
- getVersandwegLabel() — lokalisiertes Label aus versandweg-Slug.
- fetch/update um die neuen Felder erweitert.

card.php:
- Neuer Block "Versand & Belege" nach den generierten Dokumenten.
- Erfassungs-Formular: Datepicker + Versandweg-Dropdown (10 Optionen) +
  Sendungsnummer + Provider-Override.
- Anzeige nach Erfassung mit "Sendung verfolgen"-Button zum Provider.
- "Versand bearbeiten" und "Versand zuruecksetzen" Buttons.
- Beleg-Upload via formfile->showdocuments('mahnung', ...) — Dateien
  landen in DOL_DATA_ROOT/mahnung/<MAHN-Ref>/.
- Modulpart "mahnung" funktioniert ohne Custom-Setup: Dolibarr's
  conf.class.php:744 setzt $conf->mahnung->dir_output automatisch.

Lang-Keys: 22 neue (de_DE + en_US) fuer Versand-Block.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:59:08 +02:00
8e5e26c162 Vorschlagsliste: Kunden-Select2 + Mindestbetrag + Kundentyp-Filter + Kontakt-Spalte [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
Filter-Zeile:
- Kunden-Filter "rowid"-Input ersetzt durch $form->select_company()
  (Ajax-Suche falls COMPANY_USE_SEARCH_TO_SELECT gesetzt, sonst klassisches
  Dropdown). Direkt-Links ?search_socid=74 von der Kundenkarte bleiben
  weiterhin funktional (htmlname=search_socid, Backward-kompatibel).
- Neuer Filter "Mindestbetrag" (EUR, Komma zugelassen).
- Neuer Filter "Kundentyp" (alle / B2B / B2C).

Tabelle:
- Neue Spalte "Kontakt" mit Telefon- und Mail-Direktlink-Icons (tel: / mailto:).
- Spalte erscheint sowohl in der Vorschlags- als auch in der Uebersprungen-Tabelle.

MahnungVorschlag::getVorschlaege() + buildAlleVorschlaege():
- SELECT erweitert um s.phone + s.email; werden als soc_phone/soc_email
  pro Eintrag mitgegeben.
- Neue PHP-side Filter min_betrag und kundentyp.

Lang-Keys: MahnungKontakt (de_DE + en_US).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:49:31 +02:00
e4f2dd6fb2 Fix: Tab "Mahnwesen" auf Kundenkarte doppelt — completeTabsHead-Hook auf add/external filtern [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
Dolibarr ruft complete_head_from_modules() pro societe_prepare_head() mehrmals
auf (core/lib/company.lib.php:365 fuer 'core', 487 fuer 'external', 489 fuer
'remove'). Jeder Aufruf feuert completeTabsHead — der Hook haengte den Tab
entsprechend mehrfach an.

Fix: im Hook auf $parameters['mode']='add' UND filterorigmodule='external'
filtern, damit der Tab genau einmal pro Karte erscheint.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:26:24 +02:00
d49bd9ebda Docs: README, CHANGELOG, CLAUDE.md aktualisiert, Version 0.2.0
All checks were successful
Deploy mahnung / deploy (push) Has been skipped
- README.md: ODT-Template-System, Widget, Dokumentenmodelle, Template-Variablen, aktualisierter Dateibaum
- CHANGELOG.md: Neuer Block [0.2.0] mit allen Aenderungen seit Erstrelease
- CLAUDE.md: Projektanweisungen fuer zukuenftige Sessions
- modMahnung: Version 0.1.0 → 0.2.0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-10 21:37:44 +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
1af917d818 Fix: f.statut → f.fk_statut — Spaltenname in neueren Dolibarr-Versionen geaendert [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 16:33:40 +02:00
c5ec39a258 Fix: verifCsrf() entfernt — Funktion existiert nicht in Dolibarr, CSRF wird via newToken() gehandhabt [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 12s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-10 16:30:55 +02:00
f3b70788d2 Fix: Modul-Numero auf 500038 korrigiert — Kollision mit Eplan (500037) behoben [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 16:26:13 +02:00
d889fb25a5 Archiv zeigt Kundennamen, Vorschlagsliste mit Skip-Diagnose [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 13s
- list.php Archiv: Rechnungs-Ref + Kunden-Name per Bulk-Query (statt rowid).
  Mahnung-Ref klickt zur Detailansicht (card.php).
- MahnungVorschlag: neue buildAlleVorschlaege()/getUebersprungeneRechnungen()
  liefern auch ueberfaellige Rechnungen ohne aktuellen Vorschlag inkl. skip_reason
  (Wartefrist laeuft, Stufen ausgeschoepft, Frist Stufe 1 nicht erreicht, ...).
- list.php Vorschlagsliste: zweite Tabelle "Aktuell uebersprungen" mit Grund.
  Erklaert warum ueberfaellige Rechnungen nicht in der Vorschlagsliste auftauchen.
- Lang-Keys MahnungUebersprungen/Hint/SkipGrund (DE+EN).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 12:16:20 +02:00
d1db85322b Initiales Release: Mahnung-Modul v0.1.0 [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
Vollstaendiges 3-stufiges Mahnwesen nach BGB §288:
- SQL-Schema (llx_mahnung_mahnung, llx_mahnung_stufe)
- CRUD-Klassen (Mahnung, MahnungStufe, MahnungVorschlag)
- TCPDF DIN-5008 PDF-Generierung
- Verzugszinsberechnung B2C/B2B + §288 Abs.5 Pauschale
- Trigger: offene Mahnungen bei Zahlungseingang schliessen
- Hook: Tab + Button auf Rechnungs-/Kundenkarte
- Cron: taegl. Vorschlagsliste + Ntfy-Push
- Deploy-Pipeline (.forgejo/workflows/deploy.yml)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 12:09:37 +02:00