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:
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user