460 lines
18 KiB
PHP
460 lines
18 KiB
PHP
<?php
|
|
|
|
namespace Espo\Custom\Services;
|
|
|
|
use Espo\Core\Exceptions\Forbidden;
|
|
use Espo\Core\Exceptions\NotFound;
|
|
use Espo\Tools\Stream\Service as StreamService;
|
|
use Espo\Entities\Note;
|
|
|
|
class CVmhMietverhltnis extends \Espo\Services\Record
|
|
{
|
|
/**
|
|
* Initiate eviction lawsuit (Räumungsklage) from Mietverhältnis
|
|
*
|
|
* @param string $mietverhaeltnisId
|
|
* @return array
|
|
* @throws NotFound
|
|
* @throws Forbidden
|
|
*/
|
|
public function initiateEviction(string $mietverhaeltnisId): array
|
|
{
|
|
// Delegate to CVmhRumungsklage service
|
|
$raeumungsklagenService = $this->serviceFactory->create('CVmhRumungsklage');
|
|
return $raeumungsklagenService->createFromSource('CVmhMietverhltnis', $mietverhaeltnisId);
|
|
}
|
|
|
|
/**
|
|
* Initiate rent collection (Mietinkasso) from Mietverhältnis
|
|
*
|
|
* @param string $mietverhaeltnisId
|
|
* @return array
|
|
* @throws NotFound
|
|
* @throws Forbidden
|
|
*/
|
|
public function initiateRentCollection(string $mietverhaeltnisId): array
|
|
{
|
|
// 1. Load Mietverhältnis
|
|
$mietverhaeltnis = $this->entityManager->getEntity('CVmhMietverhltnis', $mietverhaeltnisId);
|
|
if (!$mietverhaeltnis) {
|
|
throw new NotFound('Mietverhältnis not found');
|
|
}
|
|
|
|
// 2. ACL Checks
|
|
if (!$this->acl->check($mietverhaeltnis, 'read')) {
|
|
throw new Forbidden('No read access to Mietverhältnis');
|
|
}
|
|
|
|
if (!$this->acl->checkScope('CMietinkasso', 'create')) {
|
|
throw new Forbidden('No create access to Mietinkasso');
|
|
}
|
|
|
|
// 3. Start Transaction
|
|
$this->entityManager->getTransactionManager()->start();
|
|
|
|
try {
|
|
// 4. Prepare data for new Mietinkasso
|
|
$data = new \stdClass();
|
|
$data->name = 'Mietinkasso - ' . $mietverhaeltnis->get('name');
|
|
|
|
// Copy assignedUser and teams
|
|
if ($mietverhaeltnis->get('assignedUserId')) {
|
|
$data->assignedUserId = $mietverhaeltnis->get('assignedUserId');
|
|
}
|
|
|
|
$teamsIds = $mietverhaeltnis->getLinkMultipleIdList('teams');
|
|
if (!empty($teamsIds)) {
|
|
$data->teamsIds = $teamsIds;
|
|
}
|
|
|
|
// 5. Create Mietinkasso entity
|
|
$mietinkasso = $this->entityManager->createEntity('CMietinkasso', (array)$data);
|
|
|
|
if (!$mietinkasso) {
|
|
throw new \RuntimeException('Failed to create Mietinkasso');
|
|
}
|
|
|
|
$mietinkassoRepo = $this->entityManager->getRepository('CMietinkasso');
|
|
|
|
// 6. Link Mietverhältnis to Mietinkasso
|
|
$mietinkassoRepo
|
|
->getRelation($mietinkasso, 'vmhMietverhltnises')
|
|
->relate($mietverhaeltnis);
|
|
|
|
// 7. Get Mietobjekt (for document collection only, not linked directly)
|
|
$mietobjekt = $this->entityManager
|
|
->getRepository('CVmhMietverhltnis')
|
|
->getRelation($mietverhaeltnis, 'vmhMietobjekt')
|
|
->findOne();
|
|
|
|
// Note: Mietobjekt wird NICHT mehr direkt zum Mietinkasso gelinkt
|
|
// Die Verbindung erfolgt indirekt über Mietverhältnis
|
|
|
|
// 8. Get Vermieter (Kläger) from Mietverhältnis
|
|
$vermieterBeteiligte = $this->entityManager
|
|
->getRepository('CVmhMietverhltnis')
|
|
->getRelation($mietverhaeltnis, 'vmhbeteiligtevermieter')
|
|
->find();
|
|
|
|
foreach ($vermieterBeteiligte as $vermieter) {
|
|
// Link as Kläger
|
|
$mietinkassoRepo
|
|
->getRelation($mietinkasso, 'klaeger')
|
|
->relate($vermieter);
|
|
}
|
|
|
|
// 9. Get Mieter (Beklagte) from Mietverhältnis
|
|
$mieterBeteiligte = $this->entityManager
|
|
->getRepository('CVmhMietverhltnis')
|
|
->getRelation($mietverhaeltnis, 'vmhbeteiligtemieter')
|
|
->find();
|
|
|
|
foreach ($mieterBeteiligte as $mieter) {
|
|
// Link as Beklagte
|
|
$mietinkassoRepo
|
|
->getRelation($mietinkasso, 'beklagte')
|
|
->relate($mieter);
|
|
}
|
|
|
|
// 9b. Get Sonstige Bewohner (auch Beklagte) from Mietverhältnis
|
|
$sonstigeBewohner = $this->entityManager
|
|
->getRepository('CVmhMietverhltnis')
|
|
->getRelation($mietverhaeltnis, 'sonstigebesitzervmhmietverhltnis')
|
|
->find();
|
|
|
|
foreach ($sonstigeBewohner as $bewohner) {
|
|
// Link as Beklagte
|
|
$mietinkassoRepo
|
|
->getRelation($mietinkasso, 'beklagte')
|
|
->relate($bewohner);
|
|
}
|
|
|
|
// 9c. Create AdvowareAkte and AIKnowledge (BEFORE document duplication!)
|
|
$this->createAdvowareAkteAndAIKnowledge($mietinkasso, $mietinkassoRepo);
|
|
|
|
// 10. Copy all documents from Mietverhältnis, Mietobjekt and Beteiligte
|
|
// Get CDokumente service for duplication
|
|
$dokumenteService = $this->injectableFactory->create(\Espo\Custom\Services\CDokumente::class);
|
|
|
|
// 10a. Dokumente vom Mietverhältnis - DUPLICATE instead of relate
|
|
$dokumenteMV = $this->entityManager
|
|
->getRepository('CVmhMietverhltnis')
|
|
->getRelation($mietverhaeltnis, 'dokumentesvmhMietverhltnisse')
|
|
->find();
|
|
|
|
foreach ($dokumenteMV as $dokument) {
|
|
try {
|
|
$duplicatedDoc = $dokumenteService->duplicateDocument($dokument->getId());
|
|
$mietinkassoRepo
|
|
->getRelation($mietinkasso, 'dokumentesmietinkasso')
|
|
->relate($duplicatedDoc);
|
|
} catch (\Exception $e) {
|
|
$GLOBALS['log']->error('Failed to duplicate document from Mietverhältnis: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
// 10b. Dokumente vom Mietobjekt - DUPLICATE instead of relate
|
|
if ($mietobjekt) {
|
|
$dokumenteMO = $this->entityManager
|
|
->getRepository('CMietobjekt')
|
|
->getRelation($mietobjekt, 'dokumentesMietobjekt')
|
|
->find();
|
|
|
|
foreach ($dokumenteMO as $dokument) {
|
|
try {
|
|
$duplicatedDoc = $dokumenteService->duplicateDocument($dokument->getId());
|
|
$mietinkassoRepo
|
|
->getRelation($mietinkasso, 'dokumentesmietinkasso')
|
|
->relate($duplicatedDoc);
|
|
} catch (\Exception $e) {
|
|
$GLOBALS['log']->error('Failed to duplicate document from Mietobjekt: ' . $e->getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
// 10c. Dokumente von allen Beteiligten (Vermieter + Mieter + Sonstige) - DUPLICATE instead of relate
|
|
$alleBeteiligte = array_merge(
|
|
iterator_to_array($vermieterBeteiligte),
|
|
iterator_to_array($mieterBeteiligte),
|
|
iterator_to_array($sonstigeBewohner)
|
|
);
|
|
|
|
foreach ($alleBeteiligte as $beteiligter) {
|
|
$dokumenteBet = $this->entityManager
|
|
->getRepository('CBeteiligte')
|
|
->getRelation($beteiligter, 'dokumentesBeteiligte')
|
|
->find();
|
|
|
|
foreach ($dokumenteBet as $dokument) {
|
|
try {
|
|
$duplicatedDoc = $dokumenteService->duplicateDocument($dokument->getId());
|
|
$mietinkassoRepo
|
|
->getRelation($mietinkasso, 'dokumentesmietinkasso')
|
|
->relate($duplicatedDoc);
|
|
} catch (\Exception $e) {
|
|
$GLOBALS['log']->error('Failed to duplicate document from Beteiligter: ' . $e->getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
// 11. Copy portal contacts from Mietverhältnis (nur vom Mietverhältnis!)
|
|
$portalContacts = $this->entityManager
|
|
->getRepository('CVmhMietverhltnis')
|
|
->getRelation($mietverhaeltnis, 'contactsMietverhltnis')
|
|
->find();
|
|
|
|
foreach ($portalContacts as $contact) {
|
|
$mietinkassoRepo
|
|
->getRelation($mietinkasso, 'contactsMietinkasso')
|
|
->relate($contact);
|
|
}
|
|
|
|
// 12. Log to stream
|
|
$this->logToStream($mietverhaeltnis, 'CVmhMietverhltnis', $mietinkasso->getId(), 'CMietinkasso', 'Mietinkasso erstellen');
|
|
|
|
// 13. Commit transaction
|
|
$this->entityManager->getTransactionManager()->commit();
|
|
|
|
return [
|
|
'id' => $mietinkasso->getId(),
|
|
'name' => $mietinkasso->get('name')
|
|
];
|
|
} catch (\Exception $e) {
|
|
// Rollback on any error
|
|
$this->entityManager->getTransactionManager()->rollback();
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initiate termination (Kündigung) from Mietverhältnis
|
|
*
|
|
* @param string $mietverhaeltnisId
|
|
* @return array
|
|
* @throws NotFound
|
|
* @throws Forbidden
|
|
*/
|
|
public function initiateTermination(string $mietverhaeltnisId): array
|
|
{
|
|
// 1. Load Mietverhältnis
|
|
$mietverhaeltnis = $this->entityManager->getEntity('CVmhMietverhltnis', $mietverhaeltnisId);
|
|
if (!$mietverhaeltnis) {
|
|
throw new NotFound('Mietverhältnis not found');
|
|
}
|
|
|
|
// 2. ACL Checks
|
|
if (!$this->acl->check($mietverhaeltnis, 'read')) {
|
|
throw new Forbidden('No read access to Mietverhältnis');
|
|
}
|
|
|
|
if (!$this->acl->checkScope('CKuendigung', 'create')) {
|
|
throw new Forbidden('No create access to Kündigung');
|
|
}
|
|
|
|
// 3. Start Transaction
|
|
$this->entityManager->getTransactionManager()->start();
|
|
|
|
try {
|
|
// 4. Prepare data for new Kündigung
|
|
$data = new \stdClass();
|
|
$data->name = 'Kündigung - ' . $mietverhaeltnis->get('name');
|
|
|
|
// Copy assignedUser and teams
|
|
if ($mietverhaeltnis->get('assignedUserId')) {
|
|
$data->assignedUserId = $mietverhaeltnis->get('assignedUserId');
|
|
}
|
|
|
|
$teamsIds = $mietverhaeltnis->getLinkMultipleIdList('teams');
|
|
if (!empty($teamsIds)) {
|
|
$data->teamsIds = $teamsIds;
|
|
}
|
|
|
|
// 5. Create Kündigung entity
|
|
$kuendigung = $this->entityManager->createEntity('CKuendigung', (array)$data);
|
|
|
|
if (!$kuendigung) {
|
|
throw new \RuntimeException('Failed to create Kündigung');
|
|
}
|
|
|
|
$kuendigungRepo = $this->entityManager->getRepository('CKuendigung');
|
|
|
|
// 6. Link Mietverhältnis to Kündigung
|
|
$kuendigungRepo
|
|
->getRelation($kuendigung, 'vmhMietverhltnises')
|
|
->relate($mietverhaeltnis);
|
|
|
|
// 7. Get Vermieter from Mietverhältnis
|
|
$vermieterBeteiligte = $this->entityManager
|
|
->getRepository('CVmhMietverhltnis')
|
|
->getRelation($mietverhaeltnis, 'vmhbeteiligtevermieter')
|
|
->find();
|
|
|
|
foreach ($vermieterBeteiligte as $vermieter) {
|
|
// Link as Kuendiger (Vermieter)
|
|
$kuendigungRepo
|
|
->getRelation($kuendigung, 'kuendiger')
|
|
->relate($vermieter);
|
|
}
|
|
|
|
// 8. Get Mieter from Mietverhältnis (NUR Mieter, NICHT sonstige Bewohner!)
|
|
$mieterBeteiligte = $this->entityManager
|
|
->getRepository('CVmhMietverhltnis')
|
|
->getRelation($mietverhaeltnis, 'vmhbeteiligtemieter')
|
|
->find();
|
|
|
|
foreach ($mieterBeteiligte as $mieter) {
|
|
// Link as Gekuendigte (Mieter)
|
|
$kuendigungRepo
|
|
->getRelation($kuendigung, 'gekuendigte')
|
|
->relate($mieter);
|
|
}
|
|
|
|
// 9. Copy all documents from Mietverhältnis and Beteiligte
|
|
// 9a. Dokumente vom Mietverhältnis
|
|
$dokumenteMV = $this->entityManager
|
|
->getRepository('CVmhMietverhltnis')
|
|
->getRelation($mietverhaeltnis, 'dokumentesvmhMietverhltnisse')
|
|
->find();
|
|
|
|
foreach ($dokumenteMV as $dokument) {
|
|
$kuendigungRepo
|
|
->getRelation($kuendigung, 'dokumenteskuendigung')
|
|
->relate($dokument);
|
|
}
|
|
|
|
// 9b. Dokumente von allen Beteiligten (Vermieter + Mieter)
|
|
$alleBeteiligte = array_merge(
|
|
iterator_to_array($vermieterBeteiligte),
|
|
iterator_to_array($mieterBeteiligte)
|
|
);
|
|
|
|
foreach ($alleBeteiligte as $beteiligter) {
|
|
$dokumenteBet = $this->entityManager
|
|
->getRepository('CBeteiligte')
|
|
->getRelation($beteiligter, 'dokumentesBeteiligte')
|
|
->find();
|
|
|
|
foreach ($dokumenteBet as $dokument) {
|
|
$kuendigungRepo
|
|
->getRelation($kuendigung, 'dokumenteskuendigung')
|
|
->relate($dokument);
|
|
}
|
|
}
|
|
|
|
// 10. Copy portal contacts from Mietverhältnis (nur vom Mietverhältnis!)
|
|
$portalContacts = $this->entityManager
|
|
->getRepository('CVmhMietverhltnis')
|
|
->getRelation($mietverhaeltnis, 'contactsMietverhltnis')
|
|
->find();
|
|
|
|
foreach ($portalContacts as $contact) {
|
|
$kuendigungRepo
|
|
->getRelation($kuendigung, 'contactsKuendigung')
|
|
->relate($contact);
|
|
}
|
|
|
|
// 11. Log to stream
|
|
$this->logToStream($mietverhaeltnis, 'CVmhMietverhltnis', $kuendigung->getId(), 'CKuendigung', 'Kündigung erstellen');
|
|
|
|
// 12. Commit transaction
|
|
$this->entityManager->getTransactionManager()->commit();
|
|
|
|
return [
|
|
'id' => $kuendigung->getId(),
|
|
'name' => $kuendigung->get('name')
|
|
];
|
|
} catch (\Exception $e) {
|
|
// Rollback on any error
|
|
$this->entityManager->getTransactionManager()->rollback();
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create AdvowareAkte and AIKnowledge for Mietinkasso
|
|
*
|
|
* @param object $mietinkasso The created Mietinkasso entity
|
|
* @param object $mietinkassoRepo Repository for relations
|
|
*/
|
|
private function createAdvowareAkteAndAIKnowledge($mietinkasso, $mietinkassoRepo): void
|
|
{
|
|
// 1. Create AdvowareAkte (aktenzeichen bleibt leer)
|
|
$aktennummer = time(); // Simple timestamp-based generation
|
|
|
|
$advowareAkteData = [
|
|
'name' => 'Advoware Akte - ' . $mietinkasso->get('name'),
|
|
'aktennummer' => $aktennummer,
|
|
'syncStatus' => 'unclean',
|
|
'assignedUserId' => $mietinkasso->get('assignedUserId')
|
|
];
|
|
|
|
// Copy teams
|
|
$teamsIds = $mietinkasso->getLinkMultipleIdList('teams');
|
|
if (!empty($teamsIds)) {
|
|
$advowareAkteData['teamsIds'] = $teamsIds;
|
|
}
|
|
|
|
$advowareAkte = $this->entityManager->createEntity('CAdvowareAkten', $advowareAkteData);
|
|
|
|
if ($advowareAkte) {
|
|
// Link AdvowareAkte to Mietinkasso (hasOne relationship - set field directly)
|
|
$mietinkasso->set('advowareAktenId', $advowareAkte->getId());
|
|
$this->entityManager->saveEntity($mietinkasso);
|
|
$GLOBALS['log']->info("CVmhMietverhltnis: Created and linked AdvowareAkte for Mietinkasso: {$advowareAkte->getId()}");
|
|
} else {
|
|
$GLOBALS['log']->error('CVmhMietverhltnis: Failed to create AdvowareAkte for Mietinkasso');
|
|
}
|
|
|
|
// 2. Create AIKnowledge
|
|
$aiKnowledgeData = [
|
|
'name' => 'AI Knowledge - ' . $mietinkasso->get('name'),
|
|
'aktivierungsstatus' => 'deactivated',
|
|
'syncStatus' => 'unclean',
|
|
'assignedUserId' => $mietinkasso->get('assignedUserId')
|
|
];
|
|
|
|
// Copy teams
|
|
if (!empty($teamsIds)) {
|
|
$aiKnowledgeData['teamsIds'] = $teamsIds;
|
|
}
|
|
|
|
$aiKnowledge = $this->entityManager->createEntity('CAIKnowledge', $aiKnowledgeData);
|
|
|
|
if ($aiKnowledge) {
|
|
// Link AIKnowledge to Mietinkasso (hasOne relationship - set field directly)
|
|
$mietinkasso->set('aIKnowledgeId', $aiKnowledge->getId());
|
|
$this->entityManager->saveEntity($mietinkasso);
|
|
$GLOBALS['log']->info("CVmhMietverhltnis: Created and linked AIKnowledge for Mietinkasso: {$aiKnowledge->getId()}");
|
|
} else {
|
|
$GLOBALS['log']->error('CVmhMietverhltnis: Failed to create AIKnowledge for Mietinkasso');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Log action to source entity stream
|
|
*
|
|
* @param object $sourceEntity Source entity (Mietverhältnis)
|
|
* @param string $sourceEntityType Entity type
|
|
* @param string $createdEntityId Created entity ID
|
|
* @param string $createdEntityType Created entity type
|
|
* @param string $actionLabel Label for the action
|
|
*/
|
|
private function logToStream($sourceEntity, string $sourceEntityType, string $createdEntityId, string $createdEntityType, string $actionLabel): void
|
|
{
|
|
// Create Note entity manually for custom message
|
|
$note = $this->entityManager->getEntity('Note');
|
|
$note->set([
|
|
'type' => Note::TYPE_CREATE_RELATED,
|
|
'parentType' => $sourceEntityType,
|
|
'parentId' => $sourceEntity->getId(),
|
|
'relatedType' => $createdEntityType,
|
|
'relatedId' => $createdEntityId,
|
|
'data' => [
|
|
'actionLabel' => $actionLabel
|
|
]
|
|
]);
|
|
|
|
$this->entityManager->saveEntity($note);
|
|
}
|
|
}
|