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 and link Mietobjekt $mietobjekt = $this->entityManager ->getRepository('CVmhMietverhltnis') ->getRelation($mietverhaeltnis, 'vmhMietobjekt') ->findOne(); if ($mietobjekt) { $mietinkassoRepo ->getRelation($mietinkasso, 'mietobjekte') ->relate($mietobjekt); } // 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); } // 10. Copy all documents from Mietverhältnis, Mietobjekt and Beteiligte // 10a. Dokumente vom Mietverhältnis $dokumenteMV = $this->entityManager ->getRepository('CVmhMietverhltnis') ->getRelation($mietverhaeltnis, 'dokumentesvmhMietverhltnisse') ->find(); foreach ($dokumenteMV as $dokument) { $mietinkassoRepo ->getRelation($mietinkasso, 'dokumentesmietinkasso') ->relate($dokument); } // 10b. Dokumente vom Mietobjekt if ($mietobjekt) { $dokumenteMO = $this->entityManager ->getRepository('CMietobjekt') ->getRelation($mietobjekt, 'dokumentesMietobjekt') ->find(); foreach ($dokumenteMO as $dokument) { $mietinkassoRepo ->getRelation($mietinkasso, 'dokumentesmietinkasso') ->relate($dokument); } } // 10c. Dokumente von allen Beteiligten (Vermieter + Mieter + Sonstige) $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) { $mietinkassoRepo ->getRelation($mietinkasso, 'dokumentesmietinkasso') ->relate($dokument); } } // 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; } } /** * 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); } }