From 4a302542b78fe45c67684362eb03422fffee61a8 Mon Sep 17 00:00:00 2001 From: bsiggel Date: Wed, 25 Mar 2026 22:01:58 +0100 Subject: [PATCH] Refactor CAdvowareAkten and CDokumente hooks; update localization and metadata; adjust microtime values in config and state files --- .../CAdvowareAkten/CheckGlobalSyncStatus.php | 75 ------------------- .../Custom/Hooks/CDokumente/CDokumente.php | 31 +++++--- .../Resources/i18n/de_DE/CAdvowareAkten.json | 4 +- .../Resources/i18n/de_DE/CDokumente.json | 8 +- .../Resources/i18n/en_US/CAdvowareAkten.json | 4 +- .../Resources/i18n/en_US/CDokumente.json | 8 +- .../layouts/CAdvowareAkten/detail.json | 10 +-- .../Resources/layouts/CDokumente/detail.json | 18 ++++- .../Resources/layouts/CDokumente/list.json | 22 ++++-- .../CDokumente/listForAdvowareAkten.json | 6 +- .../metadata/entityDefs/CAdvowareAkten.json | 13 ++-- .../metadata/entityDefs/CDokumente.json | 18 +++++ data/config.php | 2 +- data/state.php | 4 +- 14 files changed, 99 insertions(+), 124 deletions(-) delete mode 100644 custom/Espo/Custom/Hooks/CAdvowareAkten/CheckGlobalSyncStatus.php diff --git a/custom/Espo/Custom/Hooks/CAdvowareAkten/CheckGlobalSyncStatus.php b/custom/Espo/Custom/Hooks/CAdvowareAkten/CheckGlobalSyncStatus.php deleted file mode 100644 index 91643a1f..00000000 --- a/custom/Espo/Custom/Hooks/CAdvowareAkten/CheckGlobalSyncStatus.php +++ /dev/null @@ -1,75 +0,0 @@ -get('skipHooks')) { - return; - } - - // Nur wenn Entity bereits existiert (nicht bei Create) - if ($entity->isNew()) { - return; - } - - try { - // Hole alle verknüpften Dokumente mit ihren syncstatus-Werten aus der Junction-Tabelle - $query = $this->entityManager->getQueryBuilder() - ->select(['syncstatus']) - ->from('CAdvowareAktenDokumente') - ->where([ - 'cAdvowareAktenId' => $entity->getId(), - 'deleted' => false - ]) - ->build(); - - $pdoStatement = $this->entityManager->getQueryExecutor()->execute($query); - $rows = $pdoStatement->fetchAll(\PDO::FETCH_ASSOC); - - // Wenn keine Dokumente verknüpft, setze auf "unclean" - if (empty($rows)) { - $entity->set('syncStatus', 'unclean'); - return; - } - - // Prüfe, ob irgendein Dokument "new" oder "unclean" ist - $hasUnsynced = false; - foreach ($rows as $row) { - $status = $row['syncstatus'] ?? null; - if ($status === 'new' || $status === 'unclean' || $status === null || $status === '') { - $hasUnsynced = true; - break; - } - } - - // Setze globalen Status - if ($hasUnsynced) { - $entity->set('syncStatus', 'unclean'); - } else { - // Alle Dokumente sind "synced" - $entity->set('syncStatus', 'synced'); - $entity->set('lastSync', date('Y-m-d H:i:s')); - } - - } catch (\Exception $e) { - // Bei Fehler loggen und Status auf "unclean" setzen - $GLOBALS['log']->error('CAdvowareAkten CheckGlobalSyncStatus Hook Error: ' . $e->getMessage()); - $entity->set('syncStatus', 'unclean'); - } - } -} diff --git a/custom/Espo/Custom/Hooks/CDokumente/CDokumente.php b/custom/Espo/Custom/Hooks/CDokumente/CDokumente.php index 4c2b5578..9d534148 100644 --- a/custom/Espo/Custom/Hooks/CDokumente/CDokumente.php +++ b/custom/Espo/Custom/Hooks/CDokumente/CDokumente.php @@ -3,10 +3,21 @@ namespace Espo\Custom\Hooks\CDokumente; use Espo\ORM\Entity; +use Espo\ORM\Repository\Option\SaveOptions; +use Espo\Core\Hook\Hook\BeforeSave; -class CDokumente extends \Espo\Core\Hooks\Base +/** + * Hook: Berechnet Dokumenten-Hashes und setzt fileStatus + * + * Verwendet Blake3 als Hash-Algorithmus für optimale Performance + */ +class CDokumente implements BeforeSave { - public function beforeSave(Entity $entity, array $options = []) + public function __construct( + private \Espo\ORM\EntityManager $entityManager + ) {} + + public function beforeSave(Entity $entity, SaveOptions $options): void { // Problem: isAttributeChanged('dokument') erkennt Datei-Änderungen nicht, // da EspoCRM Datei-Uploads nicht als Feld-Änderung markiert. @@ -14,23 +25,20 @@ class CDokumente extends \Espo\Core\Hooks\Base // um sicherzustellen, dass Hashes bei Datei-Änderungen berechnet werden. // Optimierung wäre wünschenswert, aber nicht möglich mit aktueller API. - $dokument = $entity->get('dokument'); + $dokumentId = $entity->get('dokumentId'); - if (!$dokument) { + if (!$dokumentId) { return; } - if (is_object($dokument)) { - $attachment = $dokument; - } else { - $attachment = $this->getEntityManager()->getEntity('Attachment', $dokument); - } + // Verwende EntityManager zur korrekten Relation-Verwaltung + $attachment = $this->entityManager->getEntityById('Attachment', $dokumentId); if (!$attachment) { return; } - $filePath = 'data/upload/' . $attachment->get('id'); + $filePath = 'data/upload/' . $attachment->getId(); if (!file_exists($filePath)) { return; } @@ -41,7 +49,8 @@ class CDokumente extends \Espo\Core\Hooks\Base return; } - $newBlake3 = \blake3($fileContent); + // Blake3 Hashing - schneller als SHA3 und kryptographisch sicher + $newBlake3 = blake3($fileContent); // Setze Hash $entity->set('blake3hash', $newBlake3); diff --git a/custom/Espo/Custom/Resources/i18n/de_DE/CAdvowareAkten.json b/custom/Espo/Custom/Resources/i18n/de_DE/CAdvowareAkten.json index 762cb56d..0d51b9b9 100644 --- a/custom/Espo/Custom/Resources/i18n/de_DE/CAdvowareAkten.json +++ b/custom/Espo/Custom/Resources/i18n/de_DE/CAdvowareAkten.json @@ -15,7 +15,6 @@ "mietinkasso": "Mietinkasso", "aktenzeichen": "Aktenzeichen", "aktennummer": "Aktennummer", - "aktenpfad": "Aktenpfad (Windows)", "syncStatus": "Sync-Status", "lastSync": "Letzte Synchronisation", "aktivierungsstatus": "Aktivierungsstatus", @@ -43,7 +42,6 @@ "tooltips": { "syncStatus": "Globaler Synchronisationsstatus: synced = Alle Dokumente synchronisiert, unclean = Mindestens ein Dokument ist neu oder hat Änderungen, pending_sync = Synchronisierung wurde gestartet aber noch nicht abgeschlossen, failed = Synchronisierung fehlgeschlagen. Wird automatisch basierend auf den Dokumenten-Status aktualisiert.", "lastSync": "Zeitpunkt der letzten erfolgreichen Synchronisation aller Dokumente", - "aktivierungsstatus": "Aktivierungsstatus der Akte: new = Neu angelegt, import = Aus Advoware importiert, active = Aktiv synchronisiert, paused = Synchronisation pausiert, deactivated = Synchronisation deaktiviert", - "aktenpfad": "Windows-Dateipfad zur Akte in Advoware" + "aktivierungsstatus": "Aktivierungsstatus der Akte: new = Neu angelegt, import = Aus Advoware importiert, active = Aktiv synchronisiert, paused = Synchronisation pausiert, deactivated = Synchronisation deaktiviert" } } \ No newline at end of file diff --git a/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json b/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json index 1d60a9cb..b40aa4a3 100644 --- a/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json +++ b/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json @@ -11,6 +11,9 @@ "syncedHash": "Sync-Hash", "usn": "USN", "dateipfad": "Dateipfad", + "lastSyncTimestamp": "Letzter Sync", + "advowareArt": "Advoware Art", + "advowareBemerkung": "Advoware Bemerkung", "contactsvmhdokumente": "Freigegebene Nutzer", "vmhMietverhltnisesDokumente": "Mietverhältnisse", "vmhErstgespraechsdokumente": "Erstgespräche", @@ -47,7 +50,10 @@ "syncStatus": "Status der Synchronisation mit Advoware: new=neu, unclean=geändert, synced=synchronisiert, failed=Fehler, unsupported=nicht unterstützt", "syncedHash": "Hash-Wert bei letzter erfolgreicher Synchronisation", "usn": "Update Sequence Number - Versionsnummer für Synchronisation", - "dateipfad": "Windows-Dateipfad des Dokuments in Advoware" + "dateipfad": "Windows-Dateipfad des Dokuments in Advoware", + "lastSyncTimestamp": "Zeitstempel der letzten erfolgreichen Synchronisation mit Advoware", + "advowareArt": "Dokumententyp/Art wie in Advoware klassifiziert", + "advowareBemerkung": "Bemerkungsfeld aus Advoware - wird bei Sync übernommen" }, "options": { "syncStatus": { diff --git a/custom/Espo/Custom/Resources/i18n/en_US/CAdvowareAkten.json b/custom/Espo/Custom/Resources/i18n/en_US/CAdvowareAkten.json index 8cee3f74..d1ceeed2 100644 --- a/custom/Espo/Custom/Resources/i18n/en_US/CAdvowareAkten.json +++ b/custom/Espo/Custom/Resources/i18n/en_US/CAdvowareAkten.json @@ -4,7 +4,6 @@ "mietinkasso": "Mietinkasso", "aktenzeichen": "Aktenzeichen", "aktennummer": "Aktennummer", - "aktenpfad": "File Path (Windows)", "syncStatus": "Sync Status", "lastSync": "Last Synchronization", "aktivierungsstatus": "Activation Status", @@ -44,7 +43,6 @@ "tooltips": { "syncStatus": "Global synchronization status: synced = All documents synchronized, unclean = At least one document is new or has changes, pending_sync = Synchronization started but not yet completed, failed = Synchronization failed. Updated automatically based on document status.", "lastSync": "Timestamp of the last successful synchronization of all documents", - "aktivierungsstatus": "Activation status of the file: new = Newly created, import = Imported from Advoware, active = Actively synchronized, paused = Synchronization paused, deactivated = Synchronization deactivated", - "aktenpfad": "Windows file path to the file in Advoware" + "aktivierungsstatus": "Activation status of the file: new = Newly created, import = Imported from Advoware, active = Actively synchronized, paused = Synchronization paused, deactivated = Synchronization deactivated" } } \ No newline at end of file diff --git a/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json b/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json index 70474954..41d5919f 100644 --- a/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json +++ b/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json @@ -10,6 +10,9 @@ "syncedHash": "Sync Hash", "usn": "USN", "dateipfad": "File Path", + "lastSyncTimestamp": "Last Sync", + "advowareArt": "Advoware Type", + "advowareBemerkung": "Advoware Remarks", "contactsvmhdokumente": "Portal Users", "vmhMietverhltnisesDokumente": "Tenancies", "vmhErstgespraechsdokumente": "Initial Consultations", @@ -52,7 +55,10 @@ "syncStatus": "Sync status with Advoware: new=new, unclean=changed, synced=synchronized, failed=error, unsupported=not supported", "syncedHash": "Hash value at last successful synchronization", "usn": "Update Sequence Number - Version number for synchronization", - "dateipfad": "Windows file path of the document in Advoware" + "dateipfad": "Windows file path of the document in Advoware", + "lastSyncTimestamp": "Timestamp of last successful synchronization with Advoware", + "advowareArt": "Document type/kind as classified in Advoware", + "advowareBemerkung": "Remarks field from Advoware - synced automatically" }, "options": { "syncStatus": { diff --git a/custom/Espo/Custom/Resources/layouts/CAdvowareAkten/detail.json b/custom/Espo/Custom/Resources/layouts/CAdvowareAkten/detail.json index fa1e6e23..caadda62 100644 --- a/custom/Espo/Custom/Resources/layouts/CAdvowareAkten/detail.json +++ b/custom/Espo/Custom/Resources/layouts/CAdvowareAkten/detail.json @@ -6,7 +6,7 @@ "name": "name" }, { - "name": "aktenzeichen" + "name": "aktivierungsstatus" } ], [ @@ -14,7 +14,7 @@ "name": "aktennummer" }, { - "name": "aktenpfad" + "name": "aktenzeichen" } ], [ @@ -24,12 +24,6 @@ { "name": "lastSync" } - ], - [ - { - "name": "aktivierungsstatus" - }, - false ] ], "style": "default", diff --git a/custom/Espo/Custom/Resources/layouts/CDokumente/detail.json b/custom/Espo/Custom/Resources/layouts/CDokumente/detail.json index 6388f5a2..ce12cd56 100644 --- a/custom/Espo/Custom/Resources/layouts/CDokumente/detail.json +++ b/custom/Espo/Custom/Resources/layouts/CDokumente/detail.json @@ -5,7 +5,9 @@ { "name": "name" }, - {} + { + "name": "preview" + } ] ], "dynamicLogicVisible": null, @@ -20,8 +22,13 @@ "rows": [ [ { - "name": "preview" + "name": "advowareArt" }, + { + "name": "advowareBemerkung" + } + ], + [ { "name": "description" } @@ -60,7 +67,7 @@ "name": "cAdvowareAkten" }, { - "name": "syncStatus" + "name": "dateipfad" } ], [ @@ -73,7 +80,10 @@ ], [ { - "name": "dateipfad" + "name": "syncStatus" + }, + { + "name": "lastSyncTimestamp" } ], [ diff --git a/custom/Espo/Custom/Resources/layouts/CDokumente/list.json b/custom/Espo/Custom/Resources/layouts/CDokumente/list.json index 8e62929f..1159f4b8 100644 --- a/custom/Espo/Custom/Resources/layouts/CDokumente/list.json +++ b/custom/Espo/Custom/Resources/layouts/CDokumente/list.json @@ -2,26 +2,34 @@ { "name": "name", "link": true, - "width": 25 - }, - { - "name": "dokument", "width": 20 }, + { + "name": "dokument", + "width": 15 + }, + { + "name": "advowareArt", + "width": 10 + }, { "name": "syncStatus", + "width": 10 + }, + { + "name": "lastSyncTimestamp", "width": 12 }, { "name": "assignedUser", - "width": 15 + "width": 12 }, { "name": "createdAt", - "width": 14 + "width": 11 }, { "name": "modifiedAt", - "width": 14 + "width": 10 } ] \ No newline at end of file diff --git a/custom/Espo/Custom/Resources/layouts/CDokumente/listForAdvowareAkten.json b/custom/Espo/Custom/Resources/layouts/CDokumente/listForAdvowareAkten.json index 5f93816d..a376ee77 100644 --- a/custom/Espo/Custom/Resources/layouts/CDokumente/listForAdvowareAkten.json +++ b/custom/Espo/Custom/Resources/layouts/CDokumente/listForAdvowareAkten.json @@ -3,6 +3,10 @@ "name": "name", "link": true }, + { + "name": "advowareArt", + "align": "left" + }, { "name": "advowareAktenHnr", "align": "left" @@ -12,7 +16,7 @@ "align": "left" }, { - "name": "advowareAktenLastSync", + "name": "lastSyncTimestamp", "align": "left" }, { diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/CAdvowareAkten.json b/custom/Espo/Custom/Resources/metadata/entityDefs/CAdvowareAkten.json index 33107132..7a1a6b70 100644 --- a/custom/Espo/Custom/Resources/metadata/entityDefs/CAdvowareAkten.json +++ b/custom/Espo/Custom/Resources/metadata/entityDefs/CAdvowareAkten.json @@ -57,12 +57,6 @@ "disableFormatting": true, "isCustom": true }, - "aktenpfad": { - "type": "varchar", - "maxLength": 500, - "tooltip": true, - "isCustom": true - }, "syncStatus": { "type": "enum", "required": false, @@ -118,7 +112,12 @@ }, "dokumenteSyncstatus": { "type": "enum", - "options": ["new", "unclean", "synced", "failed"], + "options": [ + "new", + "unclean", + "synced", + "failed" + ], "notStorable": true, "utility": true, "disabled": true diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json b/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json index 764c0d43..d81907c1 100644 --- a/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json +++ b/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json @@ -118,6 +118,24 @@ "tooltip": true, "isCustom": true }, + "lastSyncTimestamp": { + "type": "datetime", + "tooltip": true, + "readOnly": true, + "isCustom": true + }, + "advowareArt": { + "type": "varchar", + "maxLength": 100, + "tooltip": true, + "isCustom": true + }, + "advowareBemerkung": { + "type": "text", + "rows": 4, + "tooltip": true, + "isCustom": true + }, "puls": { "type": "link", "entity": "CPuls", diff --git a/data/config.php b/data/config.php index e2b52133..e6b200c6 100644 --- a/data/config.php +++ b/data/config.php @@ -360,7 +360,7 @@ return [ 0 => 'youtube.com', 1 => 'google.com' ], - 'microtime' => 1774447406.848339, + 'microtime' => 1774472414.650919, 'siteUrl' => 'https://crm.bitbylaw.com', 'fullTextSearchMinLength' => 4, 'webSocketUrl' => 'ws://api.bitbylaw.com:5000/espocrm/ws', diff --git a/data/state.php b/data/state.php index 2266c492..2d187f58 100644 --- a/data/state.php +++ b/data/state.php @@ -1,7 +1,7 @@ 1774447407, - 'microtimeState' => 1774447407.027399, + 'cacheTimestamp' => 1774472414, + 'microtimeState' => 1774472414.878455, 'currencyRates' => [ 'EUR' => 1.0 ],