From 8b0d1830a376ee3ccb3404b44b86f0d2fd3f1240 Mon Sep 17 00:00:00 2001 From: data Date: Mon, 23 Feb 2026 11:29:13 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20GlobalNotify=20Integration=20f=C3=BCr?= =?UTF-8?q?=20Import-Benachrichtigungen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Helper-Funktion notify() für sichere GlobalNotify-Nutzung - Benachrichtigung bei importierten Rechnungen (zur Prüfung) - Warnung bei Import-Fehlern - Fehler-Benachrichtigung bei IMAP-Verbindungsproblemen - Sofortige Benachrichtigung bei Exception/Fatal - countPendingInvoices() für Draft-Rechnungen-Zählung - Fallback auf dol_syslog wenn GlobalNotify nicht verfügbar - Version 3.7 Co-Authored-By: Claude Opus 4.5 --- CHANGELOG.md | 13 +++ class/cron_importzugferd.class.php | 143 ++++++++++++++++++++++++ core/modules/modImportZugferd.class.php | 2 +- 3 files changed, 157 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d577f2d..70ce32b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ Alle wesentlichen Änderungen an diesem Projekt werden in dieser Datei dokumentiert. +## [3.7] - 2026-02-23 + +### Hinzugefügt +- **GlobalNotify Integration**: Benachrichtigungen über das zentrale GlobalNotify-Modul + - Import-Fehler: Warnung bei fehlgeschlagenen Importen + - Rechnungen zur Prüfung: Aktion wenn neue Rechnungen warten + - IMAP-Fehler: Warnung wenn E-Mail Postfach nicht erreichbar + - Exception/Fatal: Sofortige Benachrichtigung bei Abstürzen +- **Helper-Funktion**: `notify()` für sichere GlobalNotify-Nutzung mit Fallback + +### Hinweis +GlobalNotify ist optional. Ohne das Modul werden Benachrichtigungen ins Dolibarr-Log geschrieben. + ## [3.6] - 2026-02-23 ### Behoben diff --git a/class/cron_importzugferd.class.php b/class/cron_importzugferd.class.php index 521acdb..0a4b90c 100755 --- a/class/cron_importzugferd.class.php +++ b/class/cron_importzugferd.class.php @@ -71,6 +71,57 @@ class CronImportZugferd */ private $startTime = 0; + /** + * Send notification via GlobalNotify (if available) + * + * @param string $type 'error', 'warning', 'info', 'action' + * @param string $title Title + * @param string $message Message + * @param string $actionUrl URL for action button + * @param string $actionLabel Label for action button + * @return bool True if sent via GlobalNotify + */ + protected function notify($type, $title, $message, $actionUrl = '', $actionLabel = '') + { + if (!isModEnabled('globalnotify')) { + dol_syslog("ImportZugferd [{$type}]: {$title} - {$message}", LOG_WARNING); + return false; + } + + $classFile = dol_buildpath('/globalnotify/class/globalnotify.class.php', 0); + if (!file_exists($classFile)) { + dol_syslog("ImportZugferd [{$type}]: {$title} - {$message}", LOG_WARNING); + return false; + } + + require_once $classFile; + + if (!class_exists('GlobalNotify')) { + dol_syslog("ImportZugferd [{$type}]: {$title} - {$message}", LOG_WARNING); + return false; + } + + try { + switch ($type) { + case 'error': + GlobalNotify::error('importzugferd', $title, $message, $actionUrl, $actionLabel); + break; + case 'warning': + GlobalNotify::warning('importzugferd', $title, $message, $actionUrl, $actionLabel); + break; + case 'action': + GlobalNotify::actionRequired('importzugferd', $title, $message, $actionUrl, $actionLabel ?: 'Aktion erforderlich'); + break; + default: + GlobalNotify::info('importzugferd', $title, $message, $actionUrl, $actionLabel); + } + return true; + } catch (Exception $e) { + dol_syslog("GlobalNotify error: ".$e->getMessage(), LOG_ERR); + return false; + } + } + /** * Constructor * @@ -226,17 +277,34 @@ class CronImportZugferd $this->cronLog("Completed: imported={$this->imported_count}, skipped={$this->skipped_count}, errors={$this->error_count}, duration={$duration}s"); $this->cronLog("========== CRON END (success) =========="); + // Send GlobalNotify notifications + $this->sendImportNotifications(); + return ($this->error_count > 0) ? -1 : 0; } catch (Exception $e) { $this->error = 'Exception: '.$e->getMessage(); $this->cronLog("EXCEPTION: ".$e->getMessage()."\n".$e->getTraceAsString(), 'ERROR'); $this->cronLog("========== CRON END (exception) =========="); + $this->notify( + 'error', + 'ZUGFeRD Import fehlgeschlagen', + 'Exception: '.$e->getMessage(), + dol_buildpath('/importzugferd/admin/setup.php', 1), + 'Einstellungen prüfen' + ); return -1; } catch (Throwable $t) { $this->error = 'Fatal: '.$t->getMessage(); $this->cronLog("FATAL: ".$t->getMessage()."\n".$t->getTraceAsString(), 'ERROR'); $this->cronLog("========== CRON END (fatal) =========="); + $this->notify( + 'error', + 'ZUGFeRD Import Absturz', + 'Fatal: '.$t->getMessage(), + dol_buildpath('/importzugferd/admin/setup.php', 1), + 'Einstellungen prüfen' + ); return -1; } } @@ -645,4 +713,79 @@ class CronImportZugferd dol_syslog("CronImportZugferd: Keeping error file in watch folder: " . $file, LOG_INFO); return true; } + + /** + * Send notifications based on import results + * + * @return void + */ + protected function sendImportNotifications() + { + // Check for errors + if ($this->error_count > 0) { + $errorSummary = count($this->errors) > 0 ? implode(', ', array_slice($this->errors, 0, 3)) : 'Siehe Log'; + $this->notify( + 'warning', + $this->error_count.' ZUGFeRD Import-Fehler', + $errorSummary, + dol_buildpath('/importzugferd/list.php?status=error', 1), + 'Fehler anzeigen' + ); + } + + // Check for imported invoices that need review + if ($this->imported_count > 0) { + // Count pending invoices (drafts needing approval) + $pendingCount = $this->countPendingInvoices(); + + if ($pendingCount > 0) { + $this->notify( + 'action', + $this->imported_count.' ZUGFeRD Rechnungen importiert', + "{$pendingCount} Lieferantenrechnungen warten auf Prüfung und Freigabe", + dol_buildpath('/fourn/facture/list.php?search_status=0', 1), + 'Rechnungen prüfen' + ); + } else { + // All auto-created and validated + $this->notify( + 'info', + $this->imported_count.' ZUGFeRD Rechnungen importiert', + 'Alle Rechnungen wurden erfolgreich verarbeitet', + dol_buildpath('/fourn/facture/list.php', 1), + 'Anzeigen' + ); + } + } + + // IMAP connection issues + if (strpos($this->error, 'IMAP connection failed') !== false) { + $this->notify( + 'error', + 'IMAP Verbindung fehlgeschlagen', + 'E-Mail Postfach für ZUGFeRD-Import nicht erreichbar', + dol_buildpath('/importzugferd/admin/setup.php', 1), + 'IMAP prüfen' + ); + } + } + + /** + * Count pending (draft) supplier invoices + * + * @return int Number of draft supplier invoices + */ + protected function countPendingInvoices() + { + $sql = "SELECT COUNT(*) as cnt FROM ".MAIN_DB_PREFIX."facture_fourn"; + $sql .= " WHERE fk_statut = 0"; // Draft status + $sql .= " AND entity IN (".getEntity('facture_fourn').")"; + + $resql = $this->db->query($sql); + if ($resql) { + $obj = $this->db->fetch_object($resql); + return (int) $obj->cnt; + } + return 0; + } } diff --git a/core/modules/modImportZugferd.class.php b/core/modules/modImportZugferd.class.php index 2900452..836585c 100755 --- a/core/modules/modImportZugferd.class.php +++ b/core/modules/modImportZugferd.class.php @@ -76,7 +76,7 @@ class modImportZugferd extends DolibarrModules $this->editor_squarred_logo = ''; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@importzugferd' // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z' - $this->version = '3.6'; + $this->version = '3.7'; // Url to the file with your last numberversion of this module //$this->url_last_version = 'http://www.example.com/versionmodule.txt';