From 35d165a4b61e5bfd08176c4215af27cd6e8f1698 Mon Sep 17 00:00:00 2001 From: bsiggel Date: Wed, 25 Mar 2026 22:26:49 +0100 Subject: [PATCH] Implement UpdateLastSyncFromDocuments hook; adjust syncStatus logic; update layout and metadata for dokumentes relationship --- .../UpdateLastSyncFromDocuments.php | 111 ++++++++++++++++++ .../CDokumente/UpdateJunctionSyncStatus.php | 8 +- .../CAdvowareAkten/bottomPanelsDetail.json | 4 +- .../relationships/dokumentes.json | 39 ++++++ .../metadata/entityDefs/CAdvowareAkten.json | 31 ----- .../metadata/entityDefs/CDokumente.json | 3 + data/config.php | 2 +- data/state.php | 4 +- 8 files changed, 163 insertions(+), 39 deletions(-) create mode 100644 custom/Espo/Custom/Hooks/CAdvowareAkten/UpdateLastSyncFromDocuments.php create mode 100644 custom/Espo/Custom/Resources/layouts/CAdvowareAkten/relationships/dokumentes.json diff --git a/custom/Espo/Custom/Hooks/CAdvowareAkten/UpdateLastSyncFromDocuments.php b/custom/Espo/Custom/Hooks/CAdvowareAkten/UpdateLastSyncFromDocuments.php new file mode 100644 index 00000000..4de26ac6 --- /dev/null +++ b/custom/Espo/Custom/Hooks/CAdvowareAkten/UpdateLastSyncFromDocuments.php @@ -0,0 +1,111 @@ +get('skipHooks')) { + return; + } + + // Nur wenn Entity bereits existiert (nicht bei Create) + if ($entity->isNew()) { + return; + } + + try { + // Hole das neueste lastSyncTimestamp aller verknüpften Dokumente + $query = $this->entityManager->getQueryBuilder() + ->select([ + 'MAX:lastSyncTimestamp' => 'maxLastSync', + 'COUNT:id' => 'dokumentCount' + ]) + ->from('CDokumente') + ->where([ + 'cAdvowareAktenId' => $entity->getId(), + 'deleted' => false, + 'lastSyncTimestamp!=' => null + ]) + ->build(); + + $pdoStatement = $this->entityManager->getQueryExecutor()->execute($query); + $result = $pdoStatement->fetch(\PDO::FETCH_ASSOC); + + if ($result && $result['maxLastSync']) { + // Setze lastSync auf den neuesten Sync-Timestamp + $entity->set('lastSync', $result['maxLastSync']); + } + + // Berechne auch syncStatus basierend auf verknüpften Dokumenten + $this->updateSyncStatus($entity); + + } catch (\Exception $e) { + // Fehler loggen, aber nicht werfen (um Save nicht zu blockieren) + $GLOBALS['log']->error('CAdvowareAkten UpdateLastSyncFromDocuments Hook Error: ' . $e->getMessage()); + } + } + + /** + * Aktualisiert syncStatus basierend auf den Status der verknüpften Dokumente + */ + private function updateSyncStatus(Entity $entity): void + { + $query = $this->entityManager->getQueryBuilder() + ->select(['syncStatus']) + ->from('CDokumente') + ->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; + $hasFailed = false; + + foreach ($rows as $row) { + $status = $row['syncStatus'] ?? null; + + if ($status === 'failed') { + $hasFailed = true; + } + + if ($status === 'new' || $status === 'unclean' || $status === null || $status === '') { + $hasUnsynced = true; + } + } + + // Setze globalen Status + if ($hasFailed) { + $entity->set('syncStatus', 'failed'); + } elseif ($hasUnsynced) { + $entity->set('syncStatus', 'unclean'); + } else { + // Alle Dokumente sind "synced" + $entity->set('syncStatus', 'synced'); + } + } +} diff --git a/custom/Espo/Custom/Hooks/CDokumente/UpdateJunctionSyncStatus.php b/custom/Espo/Custom/Hooks/CDokumente/UpdateJunctionSyncStatus.php index 1dbe2406..6777d1d1 100644 --- a/custom/Espo/Custom/Hooks/CDokumente/UpdateJunctionSyncStatus.php +++ b/custom/Espo/Custom/Hooks/CDokumente/UpdateJunctionSyncStatus.php @@ -34,11 +34,11 @@ class UpdateJunctionSyncStatus implements AfterSave $entity->set('syncStatus', 'unclean'); $this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]); - // Also update the parent AdvowareAkte - $akte = $this->entityManager->getEntity('CAdvowareAkten', $entity->get('cAdvowareAktenId')); + // Trigger parent AdvowareAkte update (will update syncStatus and lastSync via its own hook) + $akte = $this->entityManager->getEntityById('CAdvowareAkten', $entity->get('cAdvowareAktenId')); if ($akte) { - $akte->set('syncStatus', 'unclean'); - $this->entityManager->saveEntity($akte, ['silent' => true, 'skipHooks' => true]); + // Just touch the entity to trigger beforeSave hook + $this->entityManager->saveEntity($akte, ['silent' => true]); } } diff --git a/custom/Espo/Custom/Resources/layouts/CAdvowareAkten/bottomPanelsDetail.json b/custom/Espo/Custom/Resources/layouts/CAdvowareAkten/bottomPanelsDetail.json index 494101cc..556cf664 100644 --- a/custom/Espo/Custom/Resources/layouts/CAdvowareAkten/bottomPanelsDetail.json +++ b/custom/Espo/Custom/Resources/layouts/CAdvowareAkten/bottomPanelsDetail.json @@ -14,7 +14,9 @@ "tabLabel": "Dokumente" }, "dokumentes": { - "index": 1 + "index": 1, + "view": "views/record/panels/relationship", + "layout": "listForAdvowareAkten" }, "_tabBreak_1": { "index": 2, diff --git a/custom/Espo/Custom/Resources/layouts/CAdvowareAkten/relationships/dokumentes.json b/custom/Espo/Custom/Resources/layouts/CAdvowareAkten/relationships/dokumentes.json new file mode 100644 index 00000000..2309fcb1 --- /dev/null +++ b/custom/Espo/Custom/Resources/layouts/CAdvowareAkten/relationships/dokumentes.json @@ -0,0 +1,39 @@ +[ + { + "name": "name", + "link": true, + "width": 20 + }, + { + "name": "advowareArt", + "align": "left", + "width": 12 + }, + { + "name": "advowareBemerkung", + "align": "left", + "notSortable": true, + "width": 18 + }, + { + "name": "syncStatus", + "align": "left", + "width": 12 + }, + { + "name": "lastSyncTimestamp", + "align": "left", + "width": 13 + }, + { + "name": "dokument", + "notSortable": true, + "align": "left", + "width": 12 + }, + { + "name": "createdAt", + "align": "left", + "width": 13 + } +] \ No newline at end of file diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/CAdvowareAkten.json b/custom/Espo/Custom/Resources/metadata/entityDefs/CAdvowareAkten.json index 7a1a6b70..f510a173 100644 --- a/custom/Espo/Custom/Resources/metadata/entityDefs/CAdvowareAkten.json +++ b/custom/Espo/Custom/Resources/metadata/entityDefs/CAdvowareAkten.json @@ -104,36 +104,6 @@ "tooltip": true, "isCustom": true }, - "dokumenteHnr": { - "type": "int", - "notStorable": true, - "utility": true, - "disabled": true - }, - "dokumenteSyncstatus": { - "type": "enum", - "options": [ - "new", - "unclean", - "synced", - "failed" - ], - "notStorable": true, - "utility": true, - "disabled": true - }, - "dokumenteLastSync": { - "type": "datetime", - "notStorable": true, - "utility": true, - "disabled": true - }, - "dokumenteSyncedHash": { - "type": "varchar", - "notStorable": true, - "utility": true, - "disabled": true - }, "dokumentes": { "type": "linkMultiple", "layoutDetailDisabled": false, @@ -143,7 +113,6 @@ "importDisabled": false, "exportDisabled": false, "customizationDisabled": false, - "disabled": true, "isCustom": true } }, diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json b/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json index d81907c1..cba8e270 100644 --- a/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json +++ b/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json @@ -78,6 +78,7 @@ "hnr": { "type": "int", "tooltip": true, + "disableFormatting": true, "isCustom": true }, "syncStatus": { @@ -108,8 +109,10 @@ }, "usn": { "type": "int", + "dbType": "bigint", "min": 0, "tooltip": true, + "disableFormatting": true, "isCustom": true }, "dateipfad": { diff --git a/data/config.php b/data/config.php index e6b200c6..44dd7663 100644 --- a/data/config.php +++ b/data/config.php @@ -360,7 +360,7 @@ return [ 0 => 'youtube.com', 1 => 'google.com' ], - 'microtime' => 1774472414.650919, + 'microtime' => 1774473866.020977, '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 2d187f58..f2121648 100644 --- a/data/state.php +++ b/data/state.php @@ -1,7 +1,7 @@ 1774472414, - 'microtimeState' => 1774472414.878455, + 'cacheTimestamp' => 1774473866, + 'microtimeState' => 1774473866.194744, 'currencyRates' => [ 'EUR' => 1.0 ],