Refactor UpdateLastSyncFromDocuments hook to use PDO for database queries; add AI Sync fields to CDokumente layout; update microtime values in config and state files; create check_role_permissions script for role validation

This commit is contained in:
2026-03-26 14:04:05 +01:00
parent cca6d288eb
commit 0841543d8e
5 changed files with 186 additions and 55 deletions

View File

@@ -14,97 +14,78 @@ class UpdateLastSyncFromDocuments implements BeforeSave
public function __construct(
private \Espo\ORM\EntityManager $entityManager
) {}
public function beforeSave(Entity $entity, SaveOptions $options): void
{
// Überspringe, wenn skipHooks gesetzt ist (verhindert Loops)
if ($options->get('skipHooks')) {
return;
}
// Nur wenn Entity bereits existiert (nicht bei Create)
if ($entity->isNew()) {
return;
}
try {
$pdo = $this->entityManager->getPDO();
$aktenId = $entity->getId();
// Hole das neueste lastSyncTimestamp aller verknüpften Dokumente
$query = $this->entityManager->getQueryBuilder()
->select([
'MAX:lastSyncTimestamp' => 'maxLastSync',
'COUNT:id' => 'dokumentCount'
])
->from('CDokumente')
->where([
'cAktenId' => $entity->getId(),
'deleted' => false,
'lastSyncTimestamp!=' => null
])
->build();
$pdoStatement = $this->entityManager->getQueryExecutor()->execute($query);
$result = $pdoStatement->fetch(\PDO::FETCH_ASSOC);
$stmt = $pdo->prepare(
"SELECT MAX(last_sync_timestamp) AS maxLastSync
FROM c_dokumente
WHERE c_akten_id = :aktenId AND deleted = 0 AND last_sync_timestamp IS NOT NULL"
);
$stmt->execute([':aktenId' => $aktenId]);
$result = $stmt->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);
// Berechne syncStatus basierend auf verknüpften Dokumenten
$this->updateSyncStatus($entity, $pdo, $aktenId);
} catch (\Exception $e) {
// Fehler loggen, aber nicht werfen (um Save nicht zu blockieren)
$GLOBALS['log']->error('CAkten UpdateLastSyncFromDocuments Hook Error: ' . $e->getMessage());
}
}
/**
* Aktualisiert syncStatus basierend auf den Status der verknüpften Dokumente
*/
private function updateSyncStatus(Entity $entity): void
private function updateSyncStatus(Entity $entity, \PDO $pdo, string $aktenId): void
{
$query = $this->entityManager->getQueryBuilder()
->select(['syncStatus'])
->from('CDokumente')
->where([
'cAktenId' => $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"
$stmt = $pdo->prepare(
"SELECT sync_status FROM c_dokumente
WHERE c_akten_id = :aktenId AND deleted = 0"
);
$stmt->execute([':aktenId' => $aktenId]);
$rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);
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;
$status = $row['sync_status'] ?? 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');
}
}