Files
espocrm/custom/Espo/Custom/Hooks/CDokumente/SyncStatusOnRelate.php

194 lines
7.2 KiB
PHP

<?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');
$entity->set('aiParsingStatus', 'unknown');
$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');
$entity->set('aiParsingStatus', 'unknown');
$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);
}
}
}