Refactor document propagation and sync status hooks; deprecate CAkten hooks and implement new logic in CDokumente; update microtime values in config and state files
This commit is contained in:
@@ -5,79 +5,15 @@ use Espo\ORM\Entity;
|
|||||||
use Espo\Core\Hook\Hook\AfterSave;
|
use Espo\Core\Hook\Hook\AfterSave;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook: Propagiert Dokumenten-Änderungen von Akten nach oben zu Räumungsklage/Mietinkasso
|
* DEPRECATED / DEAD CODE — dieser Hook war in der falschen Namespace.
|
||||||
*
|
*
|
||||||
* Wenn ein Dokument einer Akte zugewiesen wird (via cAktenId):
|
* CAkten-Hooks feuern bei CAkten-Saves, nicht bei CDokumente-Saves.
|
||||||
* → verknüpfe mit verbundener Räumungsklage/Mietinkasso
|
* Die Logik wurde in Hooks/CDokumente/PropagateDocumentsUp.php verschoben.
|
||||||
*/
|
*/
|
||||||
class PropagateDocumentsUp implements AfterSave
|
class PropagateDocumentsUp implements AfterSave
|
||||||
{
|
{
|
||||||
private static array $processing = [];
|
|
||||||
|
|
||||||
public function __construct(
|
|
||||||
private \Espo\ORM\EntityManager $entityManager
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public function afterSave(Entity $entity, \Espo\ORM\Repository\Option\SaveOptions $options): void
|
public function afterSave(Entity $entity, \Espo\ORM\Repository\Option\SaveOptions $options): void
|
||||||
{
|
{
|
||||||
// Only process when cAktenId changed
|
// intentionally empty — see Hooks/CDokumente/PropagateDocumentsUp.php
|
||||||
if (!$entity->isAttributeChanged('cAktenId')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$akteId = $entity->get('cAktenId');
|
|
||||||
if (!$akteId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$key = $akteId . '-' . $entity->getId() . '-propagate';
|
|
||||||
if (isset(self::$processing[$key])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self::$processing[$key] = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
$akte = $this->entityManager->getEntity('CAkten', $akteId);
|
|
||||||
if (!$akte) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$raumungsklage = $this->entityManager
|
|
||||||
->getRDBRepository('CAkten')
|
|
||||||
->getRelation($akte, 'vmhRumungsklage')
|
|
||||||
->findOne();
|
|
||||||
|
|
||||||
if ($raumungsklage) {
|
|
||||||
$this->relateDocument($raumungsklage, 'dokumentesvmhraumungsklage', $entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
$mietinkasso = $this->entityManager
|
|
||||||
->getRDBRepository('CAkten')
|
|
||||||
->getRelation($akte, 'mietinkasso')
|
|
||||||
->findOne();
|
|
||||||
|
|
||||||
if ($mietinkasso) {
|
|
||||||
$this->relateDocument($mietinkasso, 'dokumentesmietinkasso', $entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$GLOBALS['log']->error('CAkten PropagateDocumentsUp Error: ' . $e->getMessage());
|
|
||||||
} finally {
|
|
||||||
unset(self::$processing[$key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function relateDocument(Entity $parentEntity, string $relationName, Entity $document): void
|
|
||||||
{
|
|
||||||
$repository = $this->entityManager->getRDBRepository($parentEntity->getEntityType());
|
|
||||||
$relation = $repository->getRelation($parentEntity, $relationName);
|
|
||||||
|
|
||||||
$isRelated = $relation
|
|
||||||
->where(['id' => $document->getId()])
|
|
||||||
->findOne();
|
|
||||||
|
|
||||||
if (!$isRelated) {
|
|
||||||
$relation->relate($document);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,89 +29,61 @@ class UpdateLastSyncFromDocuments implements BeforeSave
|
|||||||
$pdo = $this->entityManager->getPDO();
|
$pdo = $this->entityManager->getPDO();
|
||||||
$aktenId = $entity->getId();
|
$aktenId = $entity->getId();
|
||||||
|
|
||||||
|
// Einzelne Zeile mit aggregierten Worst-Case-Werten über alle Dokumente.
|
||||||
|
// CASE-Ausdrücke in MAX() vermeiden das GROUP-BY-Problem bei gemischten
|
||||||
|
// Aggregat- und Nicht-Aggregat-Spalten.
|
||||||
$stmt = $pdo->prepare(
|
$stmt = $pdo->prepare(
|
||||||
"SELECT
|
"SELECT
|
||||||
MAX(last_sync_timestamp) AS maxAdvLastSync,
|
MAX(last_sync_timestamp) AS maxAdvLastSync,
|
||||||
MAX(ai_last_sync) AS maxAiLastSync,
|
MAX(ai_last_sync) AS maxAiLastSync,
|
||||||
sync_status,
|
MAX(CASE
|
||||||
ai_sync_status
|
WHEN sync_status = 'failed' THEN 2
|
||||||
|
WHEN sync_status IN ('new','unclean')
|
||||||
|
OR sync_status IS NULL OR sync_status = '' THEN 1
|
||||||
|
ELSE 0
|
||||||
|
END) AS advWorstLevel,
|
||||||
|
MAX(CASE
|
||||||
|
WHEN ai_sync_status = 'failed' THEN 2
|
||||||
|
WHEN ai_sync_status IN ('new','unclean')
|
||||||
|
OR ai_sync_status IS NULL OR ai_sync_status = '' THEN 1
|
||||||
|
ELSE 0
|
||||||
|
END) AS aiWorstLevel,
|
||||||
|
COUNT(*) AS docCount
|
||||||
FROM c_dokumente
|
FROM c_dokumente
|
||||||
WHERE c_akten_id = :aktenId AND deleted = 0"
|
WHERE c_akten_id = :aktenId AND deleted = 0"
|
||||||
);
|
);
|
||||||
$stmt->execute([':aktenId' => $aktenId]);
|
$stmt->execute([':aktenId' => $aktenId]);
|
||||||
$rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if (empty($rows)) {
|
if (!$row || (int)$row['docCount'] === 0) {
|
||||||
$entity->set('syncStatus', 'unclean');
|
$entity->set('syncStatus', 'unclean');
|
||||||
$entity->set('aiSyncStatus', 'unclean');
|
$entity->set('aiSyncStatus', 'unclean');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timestamps
|
// Timestamps setzen
|
||||||
$maxAdvLastSync = null;
|
if (!empty($row['maxAdvLastSync'])) {
|
||||||
$maxAiLastSync = null;
|
$entity->set('lastSync', $row['maxAdvLastSync']);
|
||||||
|
}
|
||||||
// Status-Tracker
|
if (!empty($row['maxAiLastSync'])) {
|
||||||
$advHasFailed = false;
|
$entity->set('aiLastSync', $row['maxAiLastSync']);
|
||||||
$advHasUnsynced = false;
|
|
||||||
$aiHasFailed = false;
|
|
||||||
$aiHasUnsynced = false;
|
|
||||||
|
|
||||||
foreach ($rows as $row) {
|
|
||||||
// Advoware: neuester Timestamp
|
|
||||||
if (!empty($row['maxAdvLastSync'])) {
|
|
||||||
if ($maxAdvLastSync === null || $row['maxAdvLastSync'] > $maxAdvLastSync) {
|
|
||||||
$maxAdvLastSync = $row['maxAdvLastSync'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI: neuester Timestamp
|
|
||||||
if (!empty($row['maxAiLastSync'])) {
|
|
||||||
if ($maxAiLastSync === null || $row['maxAiLastSync'] > $maxAiLastSync) {
|
|
||||||
$maxAiLastSync = $row['maxAiLastSync'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advoware: schlechtester Status
|
|
||||||
$advStatus = $row['sync_status'] ?? null;
|
|
||||||
if ($advStatus === 'failed') {
|
|
||||||
$advHasFailed = true;
|
|
||||||
} elseif ($advStatus === 'new' || $advStatus === 'unclean' || $advStatus === null || $advStatus === '') {
|
|
||||||
$advHasUnsynced = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI: schlechtester Status
|
|
||||||
$aiStatus = $row['ai_sync_status'] ?? null;
|
|
||||||
if ($aiStatus === 'failed') {
|
|
||||||
$aiHasFailed = true;
|
|
||||||
} elseif ($aiStatus === 'new' || $aiStatus === 'unclean' || $aiStatus === null || $aiStatus === '') {
|
|
||||||
$aiHasUnsynced = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advoware Timestamp setzen
|
// Advoware Status setzen (worst-case über alle Dokumente)
|
||||||
if ($maxAdvLastSync !== null) {
|
$advLevel = (int)($row['advWorstLevel'] ?? 0);
|
||||||
$entity->set('lastSync', $maxAdvLastSync);
|
if ($advLevel >= 2) {
|
||||||
}
|
|
||||||
|
|
||||||
// AI Timestamp setzen
|
|
||||||
if ($maxAiLastSync !== null) {
|
|
||||||
$entity->set('aiLastSync', $maxAiLastSync);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advoware Status setzen (worst-case)
|
|
||||||
if ($advHasFailed) {
|
|
||||||
$entity->set('syncStatus', 'failed');
|
$entity->set('syncStatus', 'failed');
|
||||||
} elseif ($advHasUnsynced) {
|
} elseif ($advLevel === 1) {
|
||||||
$entity->set('syncStatus', 'unclean');
|
$entity->set('syncStatus', 'unclean');
|
||||||
} else {
|
} else {
|
||||||
$entity->set('syncStatus', 'synced');
|
$entity->set('syncStatus', 'synced');
|
||||||
}
|
}
|
||||||
|
|
||||||
// AI Status setzen (worst-case)
|
// AI Status setzen (worst-case über alle Dokumente)
|
||||||
if ($aiHasFailed) {
|
$aiLevel = (int)($row['aiWorstLevel'] ?? 0);
|
||||||
|
if ($aiLevel >= 2) {
|
||||||
$entity->set('aiSyncStatus', 'failed');
|
$entity->set('aiSyncStatus', 'failed');
|
||||||
} elseif ($aiHasUnsynced) {
|
} elseif ($aiLevel === 1) {
|
||||||
$entity->set('aiSyncStatus', 'unclean');
|
$entity->set('aiSyncStatus', 'unclean');
|
||||||
} else {
|
} else {
|
||||||
$entity->set('aiSyncStatus', 'synced');
|
$entity->set('aiSyncStatus', 'synced');
|
||||||
|
|||||||
90
custom/Espo/Custom/Hooks/CDokumente/PropagateDocumentsUp.php
Normal file
90
custom/Espo/Custom/Hooks/CDokumente/PropagateDocumentsUp.php
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
namespace Espo\Custom\Hooks\CDokumente;
|
||||||
|
|
||||||
|
use Espo\ORM\Entity;
|
||||||
|
use Espo\Core\Hook\Hook\AfterSave;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook: Propagiert Dokumenten-Verlinkung von CDokumente nach oben zu Räumungsklage/Mietinkasso.
|
||||||
|
*
|
||||||
|
* Wenn ein Dokument direkt einer Akte zugewiesen wird (cAktenId gesetzt oder geändert):
|
||||||
|
* → verknüpfe das Dokument auch via M2M mit der verbundenen Räumungsklage / dem Mietinkasso.
|
||||||
|
*
|
||||||
|
* Damit ist sichergestellt, dass über alle Einstiegspunkte (direktes CAkten-Panel,
|
||||||
|
* cAktenId-Feld) die Beziehung vollständig ist.
|
||||||
|
*/
|
||||||
|
class PropagateDocumentsUp implements AfterSave
|
||||||
|
{
|
||||||
|
private static array $processing = [];
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private \Espo\ORM\EntityManager $entityManager
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function afterSave(Entity $entity, \Espo\ORM\Repository\Option\SaveOptions $options): void
|
||||||
|
{
|
||||||
|
if ($options->get('skipHooks')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$akteId = $entity->get('cAktenId');
|
||||||
|
if (!$akteId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nur wenn cAktenId neu gesetzt oder geändert wurde
|
||||||
|
if (!$entity->isNew() && !$entity->isAttributeChanged('cAktenId')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $akteId . '-' . $entity->getId() . '-propagate-up';
|
||||||
|
if (isset(self::$processing[$key])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self::$processing[$key] = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$akte = $this->entityManager->getEntity('CAkten', $akteId);
|
||||||
|
if (!$akte) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$raumungsklage = $this->entityManager
|
||||||
|
->getRDBRepository('CAkten')
|
||||||
|
->getRelation($akte, 'vmhRumungsklage')
|
||||||
|
->findOne();
|
||||||
|
|
||||||
|
if ($raumungsklage) {
|
||||||
|
$this->relateDocument($raumungsklage, 'dokumentesvmhraumungsklage', $entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
$mietinkasso = $this->entityManager
|
||||||
|
->getRDBRepository('CAkten')
|
||||||
|
->getRelation($akte, 'mietinkasso')
|
||||||
|
->findOne();
|
||||||
|
|
||||||
|
if ($mietinkasso) {
|
||||||
|
$this->relateDocument($mietinkasso, 'dokumentesmietinkasso', $entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$GLOBALS['log']->error('CDokumente PropagateDocumentsUp Error: ' . $e->getMessage());
|
||||||
|
} finally {
|
||||||
|
unset(self::$processing[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function relateDocument(Entity $parentEntity, string $relationName, Entity $document): void
|
||||||
|
{
|
||||||
|
$repository = $this->entityManager->getRDBRepository($parentEntity->getEntityType());
|
||||||
|
$relation = $repository->getRelation($parentEntity, $relationName);
|
||||||
|
|
||||||
|
$isRelated = $relation
|
||||||
|
->where(['id' => $document->getId()])
|
||||||
|
->findOne();
|
||||||
|
|
||||||
|
if (!$isRelated) {
|
||||||
|
$relation->relate($document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
191
custom/Espo/Custom/Hooks/CDokumente/SyncStatusOnRelate.php
Normal file
191
custom/Espo/Custom/Hooks/CDokumente/SyncStatusOnRelate.php
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
<?php
|
||||||
|
namespace Espo\Custom\Hooks\CDokumente;
|
||||||
|
|
||||||
|
use Espo\ORM\Entity;
|
||||||
|
use Espo\Core\Hook\Hook\AfterRelate;
|
||||||
|
use Espo\Core\Hook\Hook\AfterUnrelate;
|
||||||
|
use Espo\ORM\Repository\Option\RelateOptions;
|
||||||
|
use Espo\ORM\Repository\Option\UnrelateOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook: Sync-Status-Aktualisierung wenn ein Dokument über die CDokumente-Panels
|
||||||
|
* mit einer Räumungsklage oder einem Mietinkasso verknüpft oder entknüpft wird.
|
||||||
|
*
|
||||||
|
* Auslöser (von CDokumente-Seite aus):
|
||||||
|
* - afterRelate 'vmhRumungsklagesdokumente' → Räumungsklage verknüpft
|
||||||
|
* - afterRelate 'mietinkassosdokumente' → Mietinkasso verknüpft
|
||||||
|
* - afterUnrelate 'vmhRumungsklagesdokumente' → Räumungsklage entknüpft
|
||||||
|
* - afterUnrelate 'mietinkassosdokumente' → Mietinkasso entknüpft
|
||||||
|
*
|
||||||
|
* Wenn die Verknüpfung von der Räumungsklage/Mietinkasso-Seite kommt, feuern
|
||||||
|
* stattdessen CVmhRumungsklage/CMietinkasso::PropagateDocuments — dieses Hook
|
||||||
|
* feuert dann NICHT (EspoCRM feuert afterRelate nur auf der aufrufenden Seite).
|
||||||
|
*/
|
||||||
|
class SyncStatusOnRelate implements AfterRelate, AfterUnrelate
|
||||||
|
{
|
||||||
|
/** Relation → [parentEntityType, advowareAktenRelation, aiKnowledgeRelation] */
|
||||||
|
private const RELATION_MAP = [
|
||||||
|
'vmhRumungsklagesdokumente' => ['CVmhRumungsklage', 'advowareAkten', 'aIKnowledge'],
|
||||||
|
'mietinkassosdokumente' => ['CMietinkasso', 'advowareAkten', 'aIKnowledge'],
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var array<string, bool> */
|
||||||
|
private static array $processing = [];
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private \Espo\ORM\EntityManager $entityManager
|
||||||
|
) {}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public function afterRelate(
|
||||||
|
Entity $entity,
|
||||||
|
string $relationName,
|
||||||
|
Entity $foreignEntity,
|
||||||
|
array $columnData,
|
||||||
|
RelateOptions $options
|
||||||
|
): void {
|
||||||
|
if (!isset(self::RELATION_MAP[$relationName])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $entity->getId() . '-' . $foreignEntity->getId() . '-' . $relationName . '-relate';
|
||||||
|
if (isset(self::$processing[$key])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self::$processing[$key] = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
[, $aktenRelation, $aiKnowledgeRelation] = self::RELATION_MAP[$relationName];
|
||||||
|
|
||||||
|
// AdvowareAkten über die Parent-Entity ermitteln
|
||||||
|
$advowareAkten = $this->entityManager
|
||||||
|
->getRDBRepository($foreignEntity->getEntityType())
|
||||||
|
->getRelation($foreignEntity, $aktenRelation)
|
||||||
|
->findOne();
|
||||||
|
|
||||||
|
if ($advowareAkten) {
|
||||||
|
$entity->set('cAktenId', $advowareAkten->getId());
|
||||||
|
$entity->set('syncStatus', 'unclean');
|
||||||
|
$entity->set('aiSyncStatus', 'unclean');
|
||||||
|
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
||||||
|
|
||||||
|
$this->triggerAkteUpdate($advowareAkten->getId());
|
||||||
|
} else {
|
||||||
|
// Kein Akte-Link — trotzdem Sync-Status auf unclean setzen
|
||||||
|
$entity->set('syncStatus', 'unclean');
|
||||||
|
$entity->set('aiSyncStatus', 'unclean');
|
||||||
|
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AIKnowledge-Verknüpfung propagieren
|
||||||
|
$aiKnowledge = $this->entityManager
|
||||||
|
->getRDBRepository($foreignEntity->getEntityType())
|
||||||
|
->getRelation($foreignEntity, $aiKnowledgeRelation)
|
||||||
|
->findOne();
|
||||||
|
|
||||||
|
if ($aiKnowledge) {
|
||||||
|
$this->relateIfNotAlready($aiKnowledge, 'dokumentes', $entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$GLOBALS['log']->error(
|
||||||
|
'CDokumente SyncStatusOnRelate afterRelate (' . $relationName . ') Error: ' . $e->getMessage()
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
unset(self::$processing[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
public function afterUnrelate(
|
||||||
|
Entity $entity,
|
||||||
|
string $relationName,
|
||||||
|
Entity $foreignEntity,
|
||||||
|
UnrelateOptions $options
|
||||||
|
): void {
|
||||||
|
if (!isset(self::RELATION_MAP[$relationName])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$key = $entity->getId() . '-' . $foreignEntity->getId() . '-' . $relationName . '-unrelate';
|
||||||
|
if (isset(self::$processing[$key])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self::$processing[$key] = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
[, $aktenRelation, $aiKnowledgeRelation] = self::RELATION_MAP[$relationName];
|
||||||
|
|
||||||
|
// Alte Akte ermitteln
|
||||||
|
$advowareAkten = $this->entityManager
|
||||||
|
->getRDBRepository($foreignEntity->getEntityType())
|
||||||
|
->getRelation($foreignEntity, $aktenRelation)
|
||||||
|
->findOne();
|
||||||
|
|
||||||
|
$oldAkteId = null;
|
||||||
|
|
||||||
|
if ($advowareAkten && $entity->get('cAktenId') === $advowareAkten->getId()) {
|
||||||
|
$oldAkteId = $advowareAkten->getId();
|
||||||
|
$entity->set('cAktenId', null);
|
||||||
|
$entity->set('syncStatus', 'unclean');
|
||||||
|
$entity->set('aiSyncStatus', 'unclean');
|
||||||
|
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($oldAkteId) {
|
||||||
|
$this->triggerAkteUpdate($oldAkteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AIKnowledge-Verknüpfung entfernen
|
||||||
|
$aiKnowledge = $this->entityManager
|
||||||
|
->getRDBRepository($foreignEntity->getEntityType())
|
||||||
|
->getRelation($foreignEntity, $aiKnowledgeRelation)
|
||||||
|
->findOne();
|
||||||
|
|
||||||
|
if ($aiKnowledge) {
|
||||||
|
$this->unrelateIfExists($aiKnowledge, 'dokumentes', $entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$GLOBALS['log']->error(
|
||||||
|
'CDokumente SyncStatusOnRelate afterUnrelate (' . $relationName . ') Error: ' . $e->getMessage()
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
unset(self::$processing[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private function triggerAkteUpdate(string $akteId): void
|
||||||
|
{
|
||||||
|
$akte = $this->entityManager->getEntityById('CAkten', $akteId);
|
||||||
|
if ($akte) {
|
||||||
|
$this->entityManager->saveEntity($akte, ['silent' => true]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function relateIfNotAlready(Entity $parentEntity, string $relationName, Entity $document): void
|
||||||
|
{
|
||||||
|
$repository = $this->entityManager->getRDBRepository($parentEntity->getEntityType());
|
||||||
|
$relation = $repository->getRelation($parentEntity, $relationName);
|
||||||
|
|
||||||
|
$isRelated = $relation->where(['id' => $document->getId()])->findOne();
|
||||||
|
if (!$isRelated) {
|
||||||
|
$relation->relate($document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function unrelateIfExists(Entity $parentEntity, string $relationName, Entity $document): void
|
||||||
|
{
|
||||||
|
$repository = $this->entityManager->getRDBRepository($parentEntity->getEntityType());
|
||||||
|
$relation = $repository->getRelation($parentEntity, $relationName);
|
||||||
|
|
||||||
|
$isRelated = $relation->where(['id' => $document->getId()])->findOne();
|
||||||
|
if ($isRelated) {
|
||||||
|
$relation->unrelate($document);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,7 +48,8 @@ class PropagateDocuments implements AfterRelate, AfterUnrelate
|
|||||||
// Set direct belongsTo relationship on document
|
// Set direct belongsTo relationship on document
|
||||||
if ($advowareAkten) {
|
if ($advowareAkten) {
|
||||||
$foreignEntity->set('cAktenId', $advowareAkten->getId());
|
$foreignEntity->set('cAktenId', $advowareAkten->getId());
|
||||||
$foreignEntity->set('syncStatus', 'new'); // Mark as new for Advoware sync
|
$foreignEntity->set('syncStatus', 'unclean'); // Advoware-Sync ausstehend
|
||||||
|
$foreignEntity->set('aiSyncStatus', 'unclean'); // AI-Sync ausstehend
|
||||||
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
||||||
|
|
||||||
// Akte über neue Verlinkung informieren → syncStatus auf unclean
|
// Akte über neue Verlinkung informieren → syncStatus auf unclean
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ class PropagateDocuments implements AfterRelate, AfterUnrelate
|
|||||||
// Set direct belongsTo relationship on document
|
// Set direct belongsTo relationship on document
|
||||||
if ($advowareAkten) {
|
if ($advowareAkten) {
|
||||||
$foreignEntity->set('cAktenId', $advowareAkten->getId());
|
$foreignEntity->set('cAktenId', $advowareAkten->getId());
|
||||||
$foreignEntity->set('syncStatus', 'new'); // Mark as new for Advoware sync
|
$foreignEntity->set('syncStatus', 'unclean'); // Advoware-Sync ausstehend
|
||||||
|
$foreignEntity->set('aiSyncStatus', 'unclean'); // AI-Sync ausstehend
|
||||||
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
$this->entityManager->saveEntity($foreignEntity, ['silent' => true, 'skipHooks' => true]);
|
||||||
|
|
||||||
// Akte über neue Verlinkung informieren → syncStatus auf unclean
|
// Akte über neue Verlinkung informieren → syncStatus auf unclean
|
||||||
|
|||||||
@@ -359,7 +359,7 @@ return [
|
|||||||
0 => 'youtube.com',
|
0 => 'youtube.com',
|
||||||
1 => 'google.com'
|
1 => 'google.com'
|
||||||
],
|
],
|
||||||
'microtime' => 1774562639.614825,
|
'microtime' => 1774603769.791242,
|
||||||
'siteUrl' => 'https://crm.bitbylaw.com',
|
'siteUrl' => 'https://crm.bitbylaw.com',
|
||||||
'fullTextSearchMinLength' => 4,
|
'fullTextSearchMinLength' => 4,
|
||||||
'webSocketUrl' => 'ws://api.bitbylaw.com:5000/espocrm/ws',
|
'webSocketUrl' => 'ws://api.bitbylaw.com:5000/espocrm/ws',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
return [
|
return [
|
||||||
'cacheTimestamp' => 1774566125,
|
'cacheTimestamp' => 1774603769,
|
||||||
'microtimeState' => 1774566125.048162,
|
'microtimeState' => 1774603769.963245,
|
||||||
'currencyRates' => [
|
'currencyRates' => [
|
||||||
'EUR' => 1.0
|
'EUR' => 1.0
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user