feat: GlobalNotify Integration für Import-Benachrichtigungen

- 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 <noreply@anthropic.com>
This commit is contained in:
Eduard Wisch 2026-02-23 11:29:13 +01:00
parent 59ce17b7b5
commit 8b0d1830a3
3 changed files with 157 additions and 1 deletions

View file

@ -2,6 +2,19 @@
Alle wesentlichen Änderungen an diesem Projekt werden in dieser Datei dokumentiert. 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 ## [3.6] - 2026-02-23
### Behoben ### Behoben

View file

@ -71,6 +71,57 @@ class CronImportZugferd
*/ */
private $startTime = 0; 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 * 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("Completed: imported={$this->imported_count}, skipped={$this->skipped_count}, errors={$this->error_count}, duration={$duration}s");
$this->cronLog("========== CRON END (success) =========="); $this->cronLog("========== CRON END (success) ==========");
// Send GlobalNotify notifications
$this->sendImportNotifications();
return ($this->error_count > 0) ? -1 : 0; return ($this->error_count > 0) ? -1 : 0;
} catch (Exception $e) { } catch (Exception $e) {
$this->error = 'Exception: '.$e->getMessage(); $this->error = 'Exception: '.$e->getMessage();
$this->cronLog("EXCEPTION: ".$e->getMessage()."\n".$e->getTraceAsString(), 'ERROR'); $this->cronLog("EXCEPTION: ".$e->getMessage()."\n".$e->getTraceAsString(), 'ERROR');
$this->cronLog("========== CRON END (exception) =========="); $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; return -1;
} catch (Throwable $t) { } catch (Throwable $t) {
$this->error = 'Fatal: '.$t->getMessage(); $this->error = 'Fatal: '.$t->getMessage();
$this->cronLog("FATAL: ".$t->getMessage()."\n".$t->getTraceAsString(), 'ERROR'); $this->cronLog("FATAL: ".$t->getMessage()."\n".$t->getTraceAsString(), 'ERROR');
$this->cronLog("========== CRON END (fatal) =========="); $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; return -1;
} }
} }
@ -645,4 +713,79 @@ class CronImportZugferd
dol_syslog("CronImportZugferd: Keeping error file in watch folder: " . $file, LOG_INFO); dol_syslog("CronImportZugferd: Keeping error file in watch folder: " . $file, LOG_INFO);
return true; 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;
}
} }

View file

@ -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' $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' // 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 // Url to the file with your last numberversion of this module
//$this->url_last_version = 'http://www.example.com/versionmodule.txt'; //$this->url_last_version = 'http://www.example.com/versionmodule.txt';