diff --git a/custom/Espo/Custom/Hooks/CDokumente/UpdateJunctionSyncStatus.php b/custom/Espo/Custom/Hooks/CDokumente/UpdateJunctionSyncStatus.php new file mode 100644 index 00000000..dd7daa89 --- /dev/null +++ b/custom/Espo/Custom/Hooks/CDokumente/UpdateJunctionSyncStatus.php @@ -0,0 +1,155 @@ +isNew()) { + return; + } + + // Überspringe, wenn keine relevanten Felder geändert wurden + if (!$this->hasRelevantChanges($entity)) { + return; + } + + try { + // Update AdvowareAkten Junction-Tables + $this->updateAdvowareAktenJunctions($entity); + + // Update AIKnowledge Junction-Tables + $this->updateAIKnowledgeJunctions($entity); + + } catch (\Exception $e) { + // Fehler loggen, aber nicht werfen (um Save nicht zu blockieren) + $GLOBALS['log']->error('CDokumente UpdateJunctionSyncStatus Hook Error: ' . $e->getMessage()); + } + } + + /** + * Prüft ob relevante Felder geändert wurden + */ + private function hasRelevantChanges(Entity $entity): bool + { + // Relevante Felder für Sync-Status + $relevantFields = [ + 'name', + 'description', + 'dokument', + 'dokumentId', + 'preview', + 'previewId', + 'fileStatus' + ]; + + foreach ($relevantFields as $field) { + if ($entity->isAttributeChanged($field)) { + return true; + } + } + + return false; + } + + /** + * Update AdvowareAkten Junction-Tables + */ + private function updateAdvowareAktenJunctions(Entity $entity): void + { + $updateQuery = $this->entityManager->getQueryBuilder() + ->update() + ->in('CAdvowareAktenDokumente') + ->set(['syncstatus' => 'unclean']) + ->where([ + 'cDokumenteId' => $entity->getId(), + 'deleted' => false + ]) + ->build(); + + $this->entityManager->getQueryExecutor()->execute($updateQuery); + + // Hole alle betroffenen AdvowareAkten IDs + $selectQuery = $this->entityManager->getQueryBuilder() + ->select(['cAdvowareAktenId']) + ->from('CAdvowareAktenDokumente') + ->where([ + 'cDokumenteId' => $entity->getId(), + 'deleted' => false + ]) + ->build(); + + $pdoStatement = $this->entityManager->getQueryExecutor()->execute($selectQuery); + $rows = $pdoStatement->fetchAll(\PDO::FETCH_ASSOC); + + // Trigger Update auf jeder AdvowareAkte (um CheckGlobalSyncStatus Hook auszulösen) + foreach ($rows as $row) { + $aktenId = $row['cAdvowareAktenId'] ?? null; + if ($aktenId) { + $akte = $this->entityManager->getEntity('CAdvowareAkten', $aktenId); + if ($akte) { + // Force Update ohne Hook-Loop + $akte->set('syncStatus', 'unclean'); + $this->entityManager->saveEntity($akte); + } + } + } + } + + /** + * Update AIKnowledge Junction-Tables + */ + private function updateAIKnowledgeJunctions(Entity $entity): void + { + $updateQuery = $this->entityManager->getQueryBuilder() + ->update() + ->in('CAIKnowledgeDokumente') + ->set(['syncstatus' => 'unclean']) + ->where([ + 'cDokumenteId' => $entity->getId(), + 'deleted' => false + ]) + ->build(); + + $this->entityManager->getQueryExecutor()->execute($updateQuery); + + // Hole alle betroffenen AIKnowledge IDs + $selectQuery = $this->entityManager->getQueryBuilder() + ->select(['cAIKnowledgeId']) + ->from('CAIKnowledgeDokumente') + ->where([ + 'cDokumenteId' => $entity->getId(), + 'deleted' => false + ]) + ->build(); + + $pdoStatement = $this->entityManager->getQueryExecutor()->execute($selectQuery); + $rows = $pdoStatement->fetchAll(\PDO::FETCH_ASSOC); + + // Trigger Update auf jeder AIKnowledge (um CheckGlobalSyncStatus Hook auszulösen) + foreach ($rows as $row) { + $knowledgeId = $row['cAIKnowledgeId'] ?? null; + if ($knowledgeId) { + $knowledge = $this->entityManager->getEntity('CAIKnowledge', $knowledgeId); + if ($knowledge) { + // Force Update ohne Hook-Loop + $knowledge->set('syncStatus', 'unclean'); + $this->entityManager->saveEntity($knowledge); + } + } + } + } +} diff --git a/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json b/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json index abbf6807..4ac7806f 100644 --- a/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json +++ b/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json @@ -5,12 +5,6 @@ "ydocumentuuid": "Y-Document-UUID", "md5sum": "MD5-Prüfsumme", "sha256": "SHA256-Prüfsumme", - "aktennr": "Advoware Identifikator", - "advowareLastSync": "Advoware letzte Synchronisation", - "syncStatus": "Sync-Status", - "xaiId": "x.AI ID", - "xaiCollections": "x.AI Collections", - "xaiSyncStatus": "Sync-Status", "fileStatus": "Datei-Status", "contactsvmhdokumente": "Freigegebene Nutzer", "vmhMietverhltnisesDokumente": "Mietverhältnisse", @@ -47,29 +41,9 @@ "Create CDokumente": "Dokument erstellen" }, "tooltips": { - "aktennr": "Eindeutige Dokument-Nummer aus Advoware", - "advowareLastSync": "Zeitpunkt der letzten Synchronisation mit Advoware", - "syncStatus": "Status der Advoware-Synchronisation: pending_sync = Warte auf Sync, clean = erfolgreich synchronisiert, unclean = Änderungen ausstehend, failed = Fehler, no_sync = Nicht synchronisiert", - "xaiId": "Eindeutige ID für x.AI Synchronisation", - "xaiCollections": "Liste der x.AI Collections für dieses Dokument", - "xaiSyncStatus": "Status der x.AI Synchronisation: pending_sync = Warte auf Sync, clean = erfolgreich synchronisiert, unclean = Änderungen ausstehend, failed = Fehler, no_sync = Nicht synchronisiert", "fileStatus": "Status der Datei: new = neu hochgeladen, changed = geändert, synced = synchronisiert" }, "options": { - "syncStatus": { - "pending_sync": "Warte auf Sync", - "clean": "Synchronisiert", - "unclean": "Änderungen ausstehend", - "failed": "Fehlgeschlagen", - "no_sync": "Kein Sync" - }, - "xaiSyncStatus": { - "pending_sync": "Warte auf Sync", - "clean": "Synchronisiert", - "unclean": "Abweichungen", - "failed": "Fehlgeschlagen", - "no_sync": "Kein Sync" - }, "fileStatus": { "new": "Neu", "changed": "Geändert", diff --git a/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json b/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json index 3a644eb8..3fb02c7b 100644 --- a/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json +++ b/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json @@ -14,14 +14,9 @@ "mietobjekt2dokumente": "Properties", "mietinkassosdokumente": "Rent Collection", "kndigungensdokumente": "Terminations", - "aktennr": "Advoware Identifier", - "advowareLastSync": "Advoware Last Sync", - "syncStatus": "Sync Status", - "xaiId": "x.AI ID", - "xaiCollections": "x.AI Collections", - "xaiSyncStatus": "Sync Status", "fileStatus": "File Status", "advowareAktens": "Advoware Akten", + "advowareAktens": "Advoware Akten", "aIKnowledges": "AI Knowledge", "advowareAktenHnr": "Advoware HNR", "advowareAktenSyncstatus": "Advoware Sync Status", @@ -52,29 +47,9 @@ "listForAIKnowledge": "List for AI Knowledge" }, "tooltips": { - "aktennr": "Unique document number from Advoware", - "advowareLastSync": "Time of last synchronization with Advoware", - "syncStatus": "Advoware synchronization status: pending_sync = Waiting for sync, clean = successfully synchronized, unclean = changes pending, failed = error, no_sync = Not synchronized", - "xaiId": "Unique ID for x.AI synchronization", - "xaiCollections": "List of x.AI collections for this document", - "xaiSyncStatus": "x.AI synchronization status: pending_sync = Waiting for sync, clean = successfully synchronized, unclean = changes pending, failed = error, no_sync = Not synchronized", "fileStatus": "File status: new = newly uploaded, changed = modified, synced = synchronized" }, "options": { - "syncStatus": { - "pending_sync": "Waiting for Sync", - "clean": "Synchronized", - "unclean": "Changes Pending", - "failed": "Failed", - "no_sync": "No Sync" - }, - "xaiSyncStatus": { - "pending_sync": "Waiting for Sync", - "clean": "Synchronized", - "unclean": "Changes Pending", - "failed": "Failed", - "no_sync": "No Sync" - }, "fileStatus": { "new": "New", "changed": "Changed", diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json b/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json index 777bec6a..f358f3ba 100644 --- a/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json +++ b/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json @@ -75,75 +75,11 @@ "isCustom": true, "copyToClipboard": true }, - "aktennr": { - "type": "int", - "required": false, - "tooltip": true, - "isCustom": true - }, - "advowareLastSync": { - "type": "datetime", - "required": false, - "readOnly": true, - "tooltip": true, - "isCustom": true - }, - "syncStatus": { - "type": "enum", - "required": false, - "options": [ - "pending_sync", - "clean", - "unclean", - "failed", - "no_sync" - ], - "style": { - "pending_sync": "default", - "clean": "success", - "unclean": "warning", - "failed": "danger", - "no_sync": null - }, - "default": "no_sync", - "tooltip": true, - "isCustom": true - }, "puls": { "type": "link", "entity": "CPuls", "isCustom": true }, - "xaiId": { - "type": "varchar", - "maxLength": 255, - "isCustom": true - }, - "xaiCollections": { - "type": "array", - "isCustom": true - }, - "xaiSyncStatus": { - "type": "enum", - "required": false, - "options": [ - "pending_sync", - "clean", - "unclean", - "failed", - "no_sync" - ], - "style": { - "pending_sync": "default", - "clean": "success", - "unclean": "warning", - "failed": "danger", - "no_sync": null - }, - "default": "no_sync", - "tooltip": true, - "isCustom": true - }, "fileStatus": { "type": "enum", "required": false, @@ -362,11 +298,6 @@ "id" ] }, - "aktennr": { - "columns": [ - "aktennr" - ] - }, "md5sum": { "columns": [ "md5sum" diff --git a/data/config.php b/data/config.php index 438a1268..e543a46b 100644 --- a/data/config.php +++ b/data/config.php @@ -360,7 +360,7 @@ return [ 0 => 'youtube.com', 1 => 'google.com' ], - 'microtime' => 1773253602.105787, + 'microtime' => 1773255038.319449, '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 2ea8a0e2..d4d116f5 100644 --- a/data/state.php +++ b/data/state.php @@ -1,7 +1,7 @@ 1773253761, - 'microtimeState' => 1773253761.495155, + 'cacheTimestamp' => 1773255038, + 'microtimeState' => 1773255038.505417, 'currencyRates' => [ 'EUR' => 1.0 ],