fix(mahnung): tms-Spalten auf ON UPDATE CURRENT_TIMESTAMP umstellen [deploy]
All checks were successful
Deploy mahnung / deploy (push) Successful in 14s
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>
This commit is contained in:
parent
d49e178554
commit
bfc89917b1
5 changed files with 74 additions and 6 deletions
25
CHANGELOG.md
25
CHANGELOG.md
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Schema-Fix (tms-Spalten)
|
||||
- Die `tms`-Spalten von `llx_mahnung_mahnung`, `llx_mahnung_stufe` und `llx_mahnung_trackingpattern` wurden als reines `TIMESTAMP` angelegt — unter `explicit_defaults_for_timestamp` entstand daraus `NULL DEFAULT NULL`, sodass `tms` bei jedem UPDATE leer blieb. Jetzt Dolibarr-Standard `DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`, damit der Änderungszeitpunkt (z.B. einer per Zahlungstrigger erledigten Mahnung) wieder nachvollziehbar ist.
|
||||
- Neue idempotente Migration `migrateTimestampSpalten()` (läuft im Modul-`init()`): befüllt bestehende `NULL`-Werte aus `datec` und stellt die Spalte per `ALTER TABLE` um. Greift auf Bestands-Installs beim Re-Aktivieren des Moduls.
|
||||
|
||||
### Bonitaet / Forderungsausfall-Workflow
|
||||
- Neuer Hook `tabContentViewThirdparty` rendert auf der Kundenkarte eine **prominente rote Warnbox**, wenn der Kunde abgeschriebene Rechnungen (`fk_statut=3` + `close_code='badcustomer'`) hat. Zeigt Anzahl, Gesamtsumme, Datum der letzten Abschreibung + Link zur Detail-Liste.
|
||||
- Neuer Hook `formObjectOptions` zeigt eine kompakte Warn-Zeile bei Auftrags-/Rechnungs-Karten ("ordercard", "invoicecard"), wenn der Kunde Forderungsausfaelle hat — Bonitaets-Pruefung vor neuem Geschaeft.
|
||||
|
|
@ -26,10 +30,11 @@
|
|||
### Beleg-Scan mit Sendungsnummer-Erkennung
|
||||
- Neuer Button "Belege scannen" im Versand-Block der Mahnungs-Karte.
|
||||
- Beim Klick werden alle hochgeladenen Belege (PDF via `pdftotext`, sonst txt/html) durchsucht und gegen die konfigurierten Tracking-Patterns gematcht.
|
||||
- **OCR-Fallback**: wenn `pdftotext` nur Form-Feed-Zeichen liefert (Bild-PDF), wird automatisch `ocrmypdf --skip-text -l deu+eng` aufgerufen und das OCR-PDF erneut mit `pdftotext` gelesen. Temporaeres OCR-PDF wird nach Extraktion geloescht.
|
||||
- Erkannte Sendungsnummern werden als Vorschlag ueber dem Beleg-Bereich angezeigt (mit Dateiname, Provider-Label, Sendungsnummer + Deep-Link).
|
||||
- Per "Uebernehmen"-Button werden `tracking_nr` + `tracking_provider` in einem Klick gespeichert. "Verwerfen" entfernt den Vorschlag aus der Session.
|
||||
- Fallback: wenn `pdftotext` im Container fehlt, wird das im UI klar gemeldet — txt/html werden trotzdem durchsucht.
|
||||
- OCR (Tesseract fuer Bilder) bewusst noch nicht enthalten — kommt separat falls gewuenscht, ist Container-Aufwand.
|
||||
- Per "Uebernehmen"-Button werden `tracking_nr` + `tracking_provider` gespeichert; **zusaetzlich werden `date_versand` und `versandweg` automatisch gesetzt** (falls noch leer), sodass kein separates Speichern noetig ist.
|
||||
- "Verwerfen" entfernt den Vorschlag aus der Session.
|
||||
- DPAG-Einschreiben-Regex erlaubt OCR-typische Leerzeichen zwischen Zifferngruppen (`R[A-Z]\s?\d{4}\s?\d{4}\s?\d\s?DE`).
|
||||
|
||||
### Konfigurierbare Tracking-Patterns (Setup-Seite)
|
||||
- Neue Tabelle `llx_mahnung_trackingpattern` (Pro Eintrag: provider, label, regex, url_template, priority, active). Auto-Migration + Default-Seed beim Setup-Aufruf.
|
||||
|
|
@ -56,7 +61,21 @@
|
|||
- Neuer Filter "Kundentyp" (B2B / B2C).
|
||||
- Neue Spalte "Kontakt" mit Telefon- und Mail-Direktlink-Icons.
|
||||
|
||||
### Verzugszinsen-Neuberechnung
|
||||
- Mahnungen im Status "Erstellt" (noch nicht versandt) werden beim Aufruf der card.php **automatisch mit der aktuellen Stufen-Konfiguration neu berechnet**. Aenderungen am Zinssatz-Override in den Einstellungen wirken sofort auf alle offenen Mahnungen.
|
||||
- Toleranz 0,001 EUR um unnoetige DB-Writes zu vermeiden.
|
||||
- `basiszins_snapshot` wird ebenfalls aktualisiert.
|
||||
|
||||
### Zinssatz-Override UX (Setup-Seite)
|
||||
- Zinssatz-Override-Felder zeigen jetzt einen **Placeholder** mit dem Standard-Zinssatz (z.B. "6,27").
|
||||
- **Grauer Hilfetext** neben dem Feld: "Leer = Standard (1,27 + 5,0 % = 6,27 %), 0 = keine Zinsen" — macht die Unterscheidung zwischen leer (Standard) und 0 (keine Zinsen) klar.
|
||||
- Effektiver Zinssatz wird live aus den globalen Basiszins-/Aufschlag-Einstellungen berechnet.
|
||||
|
||||
### Fixes
|
||||
- Deutsche Post Tracking-URL korrigiert: `?piececode={nr}` statt `?form.sendungsnummer={nr}`.
|
||||
- `showdocuments()` Return-Wert wurde nicht geprinted — Sendebelege waren nach Upload unsichtbar.
|
||||
- `$upload_dir` war im `scan_belege`-Handler undefiniert (Variable wurde erst 90 Zeilen spaeter gesetzt) — eigene Pfadberechnung im Action-Block.
|
||||
- `pdftotext` Form-Feed-Zeichen (`\x0C`) bei Bild-PDFs: `trim()` entfernt `\x0C` nicht — explizite Zeichenliste noetig.
|
||||
- Kundenkarte: Tab "Mahnwesen" erschien doppelt, weil `complete_head_from_modules()` pro Karte mehrfach (core + external + remove) feuert. Hook filtert jetzt auf `mode=add` + `filterorigmodule=external`.
|
||||
|
||||
## [0.2.0] — 2026-05-10 — ODT-Template-System, Widget, Dokumentenmodelle
|
||||
|
|
|
|||
|
|
@ -334,6 +334,9 @@ class modMahnung extends DolibarrModules
|
|||
// Migration: Versand-Felder ergänzen, falls Tabelle aus alter Version stammt
|
||||
$this->migrateVersandFelder();
|
||||
|
||||
// Migration: tms-Spalten auf "ON UPDATE CURRENT_TIMESTAMP" umstellen
|
||||
$this->migrateTimestampSpalten();
|
||||
|
||||
// Default-Tracking-Patterns seeden (idempotent — nur beim ersten Mal)
|
||||
require_once DOL_DOCUMENT_ROOT.'/custom/mahnung/class/mahnungtrackingpattern.class.php';
|
||||
MahnungTrackingPattern::seedDefaults($this->db);
|
||||
|
|
@ -395,4 +398,50 @@ class modMahnung extends DolibarrModules
|
|||
$db->query("ALTER TABLE ".MAIN_DB_PREFIX."mahnung_mahnung ".implode(', ', $alter));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stellt die tms-Spalten der Modul-Tabellen auf das Dolibarr-Standardverhalten
|
||||
* "DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" um. Ältere Installs
|
||||
* hatten tms als reines "TIMESTAMP", was unter explicit_defaults_for_timestamp
|
||||
* als "NULL DEFAULT NULL" angelegt wurde — tms blieb dadurch bei jedem UPDATE leer.
|
||||
*
|
||||
* Idempotent: Tabellen, deren tms bereits ON UPDATE trägt, werden übersprungen.
|
||||
* Bestehende NULL-Werte werden vor der NOT-NULL-Umstellung aus datec befüllt.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function migrateTimestampSpalten()
|
||||
{
|
||||
global $db;
|
||||
|
||||
$tables = array('mahnung_mahnung', 'mahnung_stufe', 'mahnung_trackingpattern');
|
||||
foreach ($tables as $table) {
|
||||
$full = MAIN_DB_PREFIX.$table;
|
||||
|
||||
// Aktuelle tms-Definition prüfen — Tabelle/Spalte fehlt -> überspringen
|
||||
$res = $db->query("SHOW COLUMNS FROM ".$full." LIKE 'tms'");
|
||||
if (!$res || $db->num_rows($res) == 0) {
|
||||
if ($res) {
|
||||
$db->free($res);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
$col = $db->fetch_object($res);
|
||||
$db->free($res);
|
||||
|
||||
// Bereits migriert (Extra enthält "on update ...") -> nichts zu tun
|
||||
if (stripos((string) $col->Extra, 'on update') !== false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Alt-Zeilen ohne tms aus dem Erstelldatum befüllen, damit die
|
||||
// anschließende NOT-NULL-Umstellung keine 0000-Werte erzeugt.
|
||||
$db->query("UPDATE ".$full." SET tms = COALESCE(datec, NOW()) WHERE tms IS NULL");
|
||||
|
||||
$db->query(
|
||||
"ALTER TABLE ".$full." MODIFY COLUMN tms TIMESTAMP NOT NULL"
|
||||
." DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ CREATE TABLE llx_mahnung_mahnung (
|
|||
tracking_nr VARCHAR(50),
|
||||
tracking_provider VARCHAR(20),
|
||||
datec DATETIME,
|
||||
tms TIMESTAMP,
|
||||
tms TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
fk_user_creat INTEGER,
|
||||
fk_user_modif INTEGER
|
||||
) ENGINE=InnoDB;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ CREATE TABLE llx_mahnung_stufe (
|
|||
pdf_intro TEXT,
|
||||
active TINYINT DEFAULT 1 NOT NULL,
|
||||
datec DATETIME,
|
||||
tms TIMESTAMP
|
||||
tms TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- Default-Stufen (idempotent: INSERT IGNORE wegen UNIQUE entity+stufe)
|
||||
|
|
|
|||
|
|
@ -17,5 +17,5 @@ CREATE TABLE llx_mahnung_trackingpattern (
|
|||
priority INTEGER DEFAULT 100,
|
||||
active TINYINT DEFAULT 1,
|
||||
datec DATETIME,
|
||||
tms TIMESTAMP
|
||||
tms TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB;
|
||||
|
|
|
|||
Loading…
Reference in a new issue