Add AdvowareAkte and AIKnowledge creation for Kündigungen; synchronize between Kündigungen and Räumungsklagen; update localization and metadata files

This commit is contained in:
2026-03-23 21:29:26 +01:00
parent 672645673f
commit ea4738d9eb
19 changed files with 502 additions and 18 deletions

View File

@@ -0,0 +1,148 @@
<?php
namespace Espo\Custom\Hooks\CKuendigung;
use Espo\ORM\Entity;
use Espo\Core\Hook\Hook\AfterSave;
/**
* Hook: Erstellt automatisch AdvowareAkte für Kündigung
*
* Wenn eine Kündigung erstellt/gespeichert wird:
* - Prüfe ob bereits eine AdvowareAkte vorhanden ist (über verknüpfte Räumungsklage)
* - Wenn nein: Erstelle neue AdvowareAkte und verknüpfe sie
*/
class CreateAdvowareAkte implements AfterSave
{
private static array $processing = [];
public function __construct(
private \Espo\ORM\EntityManager $entityManager,
private \Espo\Core\InjectableFactory $injectableFactory
) {}
public function afterSave(
Entity $entity,
\Espo\ORM\Repository\Option\SaveOptions $options
): void {
// Skip if silent or during hooks
if ($options->get('silent') || $options->get('skipHooks')) {
return;
}
// Vermeide Loops
$key = $entity->getId() . '-create-akte';
if (isset(self::$processing[$key])) {
return;
}
self::$processing[$key] = true;
try {
// Prüfe ob Kündigung bereits eine AdvowareAkte hat
$existingAkteId = $entity->get('advowareAktenId');
if ($existingAkteId) {
$GLOBALS['log']->info("CKuendigung CreateAdvowareAkte: Kündigung already has AdvowareAkte: {$existingAkteId}");
unset(self::$processing[$key]);
return; // Bereits vorhanden
}
// Prüfe ob verknüpfte Räumungsklagen eine Akte haben
$raeumungsklagen = $this->entityManager
->getRDBRepository('CKuendigung')
->getRelation($entity, 'vmhRumungsklages')
->find();
foreach ($raeumungsklagen as $rk) {
$rkAkteId = $rk->get('advowareAktenId');
if ($rkAkteId) {
// Übernehme Akte von Räumungsklage
$entity->set('advowareAktenId', $rkAkteId);
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
// Synchronisiere Aktennummer
$akte = $this->entityManager->getEntity('CAdvowareAkten', $rkAkteId);
if ($akte) {
$this->syncAktennummer($entity, $akte);
}
$GLOBALS['log']->info("CKuendigung CreateAdvowareAkte: Using AdvowareAkte from Räumungsklage: {$rkAkteId}");
unset(self::$processing[$key]);
return;
}
}
// Keine Akte gefunden -> Erstelle neue
$this->createNewAkte($entity);
} catch (\Exception $e) {
$GLOBALS['log']->error('CKuendigung CreateAdvowareAkte Error: ' . $e->getMessage());
} finally {
unset(self::$processing[$key]);
}
}
private function createNewAkte(Entity $kuendigung): void
{
// Hole oder generiere Aktennummer
$aktennummer = $kuendigung->get('aktennr');
if (!$aktennummer) {
$aktennummer = time();
}
// Hole oder generiere Aktenzeichen
$aktenzeichen = $kuendigung->get('advowareAktenzeichen');
if (!$aktenzeichen) {
$aktenzeichen = 'AZ-' . date('Y-m-d-His');
}
// Erstelle AdvowareAkte
$akteData = [
'name' => 'Advoware Akte - ' . $kuendigung->get('name'),
'aktennummer' => $aktennummer,
'aktenzeichen' => $aktenzeichen,
'syncStatus' => 'unclean',
'assignedUserId' => $kuendigung->get('assignedUserId')
];
// Copy teams
$teamsIds = $kuendigung->getLinkMultipleIdList('teams');
if (!empty($teamsIds)) {
$akteData['teamsIds'] = $teamsIds;
}
$akte = $this->entityManager->createEntity('CAdvowareAkten', $akteData);
if ($akte) {
// Verknüpfe mit Kündigung
$kuendigung->set('advowareAktenId', $akte->getId());
$this->entityManager->saveEntity($kuendigung, ['silent' => true, 'skipHooks' => true]);
// Synchronisiere Aktennummer zurück zur Kündigung
$this->syncAktennummer($kuendigung, $akte);
$GLOBALS['log']->info("CKuendigung CreateAdvowareAkte: Created new AdvowareAkte: {$akte->getId()}");
} else {
$GLOBALS['log']->error('CKuendigung CreateAdvowareAkte: Failed to create AdvowareAkte');
}
}
private function syncAktennummer(Entity $kuendigung, Entity $akte): void
{
$needsUpdate = false;
if (!$kuendigung->get('aktennr') && $akte->get('aktennummer')) {
$kuendigung->set('aktennr', $akte->get('aktennummer'));
$needsUpdate = true;
}
if (!$kuendigung->get('advowareAktenzeichen') && $akte->get('aktenzeichen')) {
$kuendigung->set('advowareAktenzeichen', $akte->get('aktenzeichen'));
$needsUpdate = true;
}
if ($needsUpdate) {
$this->entityManager->saveEntity($kuendigung, ['silent' => true, 'skipHooks' => true]);
$GLOBALS['log']->info("CKuendigung CreateAdvowareAkte: Synchronized Aktennummer/Aktenzeichen");
}
}
}

View File

@@ -0,0 +1,92 @@
<?php
namespace Espo\Custom\Hooks\CKuendigung;
use Espo\ORM\Entity;
use Espo\Core\Hook\Hook\AfterRelate;
/**
* Hook: Synchronisiert AdvowareAkte zwischen Kündigung und Räumungsklage
*
* Wenn eine Kündigung mit einer Räumungsklage verknüpft wird:
* - Prüfe ob Räumungsklage eine AdvowareAkte hat
* - Wenn ja, verknüpfe diese Akte auch mit der Kündigung
* - Übernehme/Synchronisiere Aktennummer und Aktenzeichen
*/
class SyncAdvowareAkte implements AfterRelate
{
private static array $processing = [];
public function __construct(
private \Espo\ORM\EntityManager $entityManager
) {}
public function afterRelate(
Entity $entity,
string $relationName,
Entity $foreignEntity,
array $columnData,
\Espo\ORM\Repository\Option\RelateOptions $options
): void {
// Nur für vmhRumungsklages-Beziehung (wenn Räumungsklage zu Kündigung hinzugefügt wird)
if ($relationName !== 'vmhRumungsklages') {
return;
}
// Vermeide Loops
$key = $entity->getId() . '-' . $foreignEntity->getId() . '-sync-akte';
if (isset(self::$processing[$key])) {
return;
}
self::$processing[$key] = true;
try {
// $entity = CKuendigung
// $foreignEntity = CVmhRumungsklage
// Hole AdvowareAkte von der Räumungsklage (hasOne relationship - get via field)
$advowareAkteId = $foreignEntity->get('advowareAktenId');
if ($advowareAkteId) {
$advowareAkte = $this->entityManager->getEntity('CAdvowareAkten', $advowareAkteId);
if ($advowareAkte) {
$GLOBALS['log']->info("CKuendigung SyncAdvowareAkte: Found AdvowareAkte {$advowareAkte->getId()} on Räumungsklage {$foreignEntity->getId()}");
// Prüfe ob Kündigung bereits eine andere Akte hat
$existingAktenId = $entity->get('advowareAktenId');
if ($existingAktenId && $existingAktenId !== $advowareAkteId) {
$GLOBALS['log']->warning("CKuendigung SyncAdvowareAkte: Kündigung already has different AdvowareAkte {$existingAktenId}, will replace with {$advowareAkteId}");
}
// Verknüpfe AdvowareAkte mit Kündigung (belongsTo relationship - set field directly)
$entity->set('advowareAktenId', $advowareAkteId);
// Synchronisiere Aktennummer und Aktenzeichen
$needsUpdate = false;
if (!$entity->get('aktennr') && $advowareAkte->get('aktennummer')) {
$entity->set('aktennr', $advowareAkte->get('aktennummer'));
$needsUpdate = true;
}
if (!$entity->get('advowareAktenzeichen') && $advowareAkte->get('aktenzeichen')) {
$entity->set('advowareAktenzeichen', $advowareAkte->get('aktenzeichen'));
$needsUpdate = true;
}
// Save once with all changes
$this->entityManager->saveEntity($entity, ['silent' => true, 'skipHooks' => true]);
$GLOBALS['log']->info("CKuendigung SyncAdvowareAkte: Successfully linked AdvowareAkte and synchronized fields to Kündigung");
}
} else {
$GLOBALS['log']->info("CKuendigung SyncAdvowareAkte: Räumungsklage {$foreignEntity->getId()} has no AdvowareAkte yet");
}
} catch (\Exception $e) {
$GLOBALS['log']->error('CKuendigung SyncAdvowareAkte Error: ' . $e->getMessage());
} finally {
unset(self::$processing[$key]);
}
}
}