From 2bc3158cd555e7132a6ae8397163d8fdc8d935ba Mon Sep 17 00:00:00 2001 From: bsiggel Date: Sat, 24 Jan 2026 12:28:37 +0100 Subject: [PATCH] =?UTF-8?q?Refactor=20eviction=20and=20rent=20collection?= =?UTF-8?q?=20features;=20migrate=20logic=20from=20Mietobjekt=20to=20Mietv?= =?UTF-8?q?erh=C3=A4ltnis;=20update=20localization=20and=20UI=20handlers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../handlers/mietobjekt/eviction-action.js | 57 --- .../mietverhaeltnis/eviction-action.js | 70 ++++ .../mietverhaeltnis/rent-collection-action.js | 70 ++++ .../Espo/Custom/Controllers/CMietobjekt.php | 21 - .../Custom/Controllers/CVmhMietverhltnis.php | 38 ++ .../i18n/de_DE/CVmhMietverhltnis.json | 12 +- .../i18n/en_US/CVmhMietverhltnis.json | 12 +- .../metadata/clientDefs/CMietobjekt.json | 16 - .../clientDefs/CVmhMietverhltnis.json | 26 ++ custom/Espo/Custom/Services/CMietobjekt.php | 132 ------- .../Custom/Services/CVmhMietverhltnis.php | 371 ++++++++++++++++++ data/config.php | 4 +- 12 files changed, 599 insertions(+), 230 deletions(-) delete mode 100644 client/custom/src/handlers/mietobjekt/eviction-action.js create mode 100644 client/custom/src/handlers/mietverhaeltnis/eviction-action.js create mode 100644 client/custom/src/handlers/mietverhaeltnis/rent-collection-action.js delete mode 100644 custom/Espo/Custom/Services/CMietobjekt.php create mode 100644 custom/Espo/Custom/Services/CVmhMietverhltnis.php diff --git a/client/custom/src/handlers/mietobjekt/eviction-action.js b/client/custom/src/handlers/mietobjekt/eviction-action.js deleted file mode 100644 index 2cc1628e..00000000 --- a/client/custom/src/handlers/mietobjekt/eviction-action.js +++ /dev/null @@ -1,57 +0,0 @@ -define('custom:handlers/mietobjekt/eviction-action', [], function () { - - /** - * Handler for initiating eviction lawsuit from Mietobjekt - */ - return class { - - constructor(view) { - this.view = view; - } - - /** - * Initialize the handler - */ - initEvictionAction() { - // Initialization if needed - } - - /** - * Action to initiate eviction (Räumungsklage) - */ - initiateEviction() { - const model = this.view.model; - - // Confirm dialog - this.view.confirm( - this.view.translate('initiateEvictionConfirmation', 'messages', 'CMietobjekt'), - () => { - Espo.Ui.notify(this.view.translate('pleaseWait', 'messages')); - - // POST request to backend - Espo.Ajax.postRequest('CMietobjekt/action/initiateEviction', { - id: model.id - }).then(response => { - Espo.Ui.success( - this.view.translate('evictionCreatedSuccess', 'messages', 'CMietobjekt') - ); - - // Navigate to the newly created Räumungsklage - this.view.getRouter().navigate( - '#CVmhRumungsklage/view/' + response.id, - {trigger: true} - ); - }).catch(xhr => { - let message = this.view.translate('evictionCreatedError', 'messages', 'CMietobjekt'); - - if (xhr.responseJSON && xhr.responseJSON.message) { - message = xhr.responseJSON.message; - } - - Espo.Ui.error(message); - }); - } - ); - } - }; -}); diff --git a/client/custom/src/handlers/mietverhaeltnis/eviction-action.js b/client/custom/src/handlers/mietverhaeltnis/eviction-action.js new file mode 100644 index 00000000..cc761314 --- /dev/null +++ b/client/custom/src/handlers/mietverhaeltnis/eviction-action.js @@ -0,0 +1,70 @@ +define('custom:handlers/mietverhaeltnis/eviction-action', [], function () { + + class EvictionActionHandler { + + constructor(view) { + this.view = view; + } + + /** + * Setup-Methode wird automatisch aufgerufen + */ + initInitiateEviction() { + // Optional: Button-Logik nach Render + } + + /** + * Action-Handler (wird bei Button-Click aufgerufen) + */ + actionInitiateEviction() { + console.log('actionInitiateEviction called'); + const model = this.view.model; + + // Confirmation Dialog + this.view.confirm( + this.view.translate('confirmEviction', 'messages', 'CVmhMietverhltnis'), + () => { + console.log('Confirmation accepted, initiating eviction'); + this.initiateEviction(model.id); + } + ); + } + + /** + * AJAX Request zum Backend + */ + initiateEviction(mietverhaeltnisId) { + Espo.Ui.notify(this.view.translate('pleaseWait', 'messages')); + + Espo.Ajax.postRequest('CVmhMietverhltnis/action/initiateEviction', { + id: mietverhaeltnisId + }) + .then(response => { + Espo.Ui.success( + this.view.translate('evictionCreated', 'messages', 'CVmhMietverhltnis') + ); + + // Navigation zur erstellten Räumungsklage + this.view.getRouter().navigate( + '#CVmhRumungsklage/view/' + response.id, + {trigger: true} + ); + }) + .catch(xhr => { + console.error('Eviction initiation failed:', xhr); + + let errorMessage = this.view.translate('evictionError', 'messages', 'CVmhMietverhltnis'); + + if (xhr.status === 403) { + errorMessage = this.view.translate('Access denied', 'messages'); + } else if (xhr.status === 404) { + errorMessage = this.view.translate('Not found', 'messages'); + } + + Espo.Ui.error(errorMessage); + }); + } + } + + return EvictionActionHandler; +}); diff --git a/client/custom/src/handlers/mietverhaeltnis/rent-collection-action.js b/client/custom/src/handlers/mietverhaeltnis/rent-collection-action.js new file mode 100644 index 00000000..1ea00160 --- /dev/null +++ b/client/custom/src/handlers/mietverhaeltnis/rent-collection-action.js @@ -0,0 +1,70 @@ +define('custom:handlers/mietverhaeltnis/rent-collection-action', [], function () { + + class RentCollectionActionHandler { + + constructor(view) { + this.view = view; + } + + /** + * Setup-Methode wird automatisch aufgerufen + */ + initInitiateRentCollection() { + // Optional: Button-Logik nach Render + } + + /** + * Action-Handler (wird bei Button-Click aufgerufen) + */ + actionInitiateRentCollection() { + console.log('actionInitiateRentCollection called'); + const model = this.view.model; + + // Confirmation Dialog + this.view.confirm( + this.view.translate('confirmRentCollection', 'messages', 'CVmhMietverhltnis'), + () => { + console.log('Confirmation accepted, initiating rent collection'); + this.initiateRentCollection(model.id); + } + ); + } + + /** + * AJAX Request zum Backend + */ + initiateRentCollection(mietverhaeltnisId) { + Espo.Ui.notify(this.view.translate('pleaseWait', 'messages')); + + Espo.Ajax.postRequest('CVmhMietverhltnis/action/initiateRentCollection', { + id: mietverhaeltnisId + }) + .then(response => { + Espo.Ui.success( + this.view.translate('rentCollectionCreated', 'messages', 'CVmhMietverhltnis') + ); + + // Navigation zum erstellten Mietinkasso + this.view.getRouter().navigate( + '#CMietinkasso/view/' + response.id, + {trigger: true} + ); + }) + .catch(xhr => { + console.error('Rent collection initiation failed:', xhr); + + let errorMessage = this.view.translate('rentCollectionError', 'messages', 'CVmhMietverhltnis'); + + if (xhr.status === 403) { + errorMessage = this.view.translate('Access denied', 'messages'); + } else if (xhr.status === 404) { + errorMessage = this.view.translate('Not found', 'messages'); + } + + Espo.Ui.error(errorMessage); + }); + } + } + + return RentCollectionActionHandler; +}); diff --git a/custom/Espo/Custom/Controllers/CMietobjekt.php b/custom/Espo/Custom/Controllers/CMietobjekt.php index d904faaa..1a4f5380 100644 --- a/custom/Espo/Custom/Controllers/CMietobjekt.php +++ b/custom/Espo/Custom/Controllers/CMietobjekt.php @@ -2,27 +2,6 @@ namespace Espo\Custom\Controllers; -use Espo\Core\Exceptions\BadRequest; -use Espo\Core\Exceptions\Forbidden; -use Espo\Core\Api\Request; - class CMietobjekt extends \Espo\Core\Templates\Controllers\Base { - /** - * POST Action: Initiate eviction lawsuit from Mietobjekt - */ - public function postActionInitiateEviction(Request $request): array - { - $data = $request->getParsedBody(); - - $id = $data->id ?? null; - if (!$id) { - throw new BadRequest('No Mietobjekt ID provided'); - } - - $service = $this->getRecordService(); - $result = $service->initiateEviction($id); - - return $result; - } } diff --git a/custom/Espo/Custom/Controllers/CVmhMietverhltnis.php b/custom/Espo/Custom/Controllers/CVmhMietverhltnis.php index 6d64cea1..78b1a241 100644 --- a/custom/Espo/Custom/Controllers/CVmhMietverhltnis.php +++ b/custom/Espo/Custom/Controllers/CVmhMietverhltnis.php @@ -2,6 +2,44 @@ namespace Espo\Custom\Controllers; +use Espo\Core\Exceptions\BadRequest; +use Espo\Core\Api\Request; + class CVmhMietverhltnis extends \Espo\Core\Templates\Controllers\BasePlus { + /** + * POST Action: Initiate eviction lawsuit from Mietverhältnis + */ + public function postActionInitiateEviction(Request $request): array + { + $data = $request->getParsedBody(); + + $id = $data->id ?? null; + if (!$id) { + throw new BadRequest('No Mietverhältnis ID provided'); + } + + $service = $this->getRecordService(); + $result = $service->initiateEviction($id); + + return $result; + } + + /** + * POST Action: Initiate rent collection from Mietverhältnis + */ + public function postActionInitiateRentCollection(Request $request): array + { + $data = $request->getParsedBody(); + + $id = $data->id ?? null; + if (!$id) { + throw new BadRequest('No Mietverhältnis ID provided'); + } + + $service = $this->getRecordService(); + $result = $service->initiateRentCollection($id); + + return $result; + } } diff --git a/custom/Espo/Custom/Resources/i18n/de_DE/CVmhMietverhltnis.json b/custom/Espo/Custom/Resources/i18n/de_DE/CVmhMietverhltnis.json index 16f1c1f3..b95acc7a 100644 --- a/custom/Espo/Custom/Resources/i18n/de_DE/CVmhMietverhltnis.json +++ b/custom/Espo/Custom/Resources/i18n/de_DE/CVmhMietverhltnis.json @@ -42,6 +42,16 @@ "vmhMietobjekt": "Mietobjekt" }, "labels": { - "Create CVmhMietverhltnis": "Mietverhältnis erstellen" + "Create CVmhMietverhltnis": "Mietverhältnis erstellen", + "Initiate Eviction": "Räumungsklage einleiten", + "Initiate Rent Collection": "Mietinkasso einleiten" + }, + "messages": { + "confirmEviction": "Möchten Sie wirklich eine Räumungsklage aus diesem Mietverhältnis einleiten?", + "evictionCreated": "Räumungsklage wurde erfolgreich erstellt", + "evictionError": "Fehler beim Erstellen der Räumungsklage", + "confirmRentCollection": "Möchten Sie wirklich ein Mietinkasso aus diesem Mietverhältnis einleiten?", + "rentCollectionCreated": "Mietinkasso wurde erfolgreich erstellt", + "rentCollectionError": "Fehler beim Erstellen des Mietinkassos" } } \ No newline at end of file diff --git a/custom/Espo/Custom/Resources/i18n/en_US/CVmhMietverhltnis.json b/custom/Espo/Custom/Resources/i18n/en_US/CVmhMietverhltnis.json index f47e5b7a..9b4b1962 100644 --- a/custom/Espo/Custom/Resources/i18n/en_US/CVmhMietverhltnis.json +++ b/custom/Espo/Custom/Resources/i18n/en_US/CVmhMietverhltnis.json @@ -45,7 +45,17 @@ "vmhMietobjekt": "Property" }, "labels": { - "Create CVmhMietverhltnis": "Create Mietverhältnis" + "Create CVmhMietverhltnis": "Create Mietverhältnis", + "Initiate Eviction": "Initiate Eviction Lawsuit", + "Initiate Rent Collection": "Initiate Rent Collection" + }, + "messages": { + "confirmEviction": "Do you really want to initiate an eviction lawsuit from this tenancy?", + "evictionCreated": "Eviction lawsuit has been created successfully", + "evictionError": "Error creating eviction lawsuit", + "confirmRentCollection": "Do you really want to initiate rent collection from this tenancy?", + "rentCollectionCreated": "Rent collection has been created successfully", + "rentCollectionError": "Error creating rent collection" }, "options": { "status": { diff --git a/custom/Espo/Custom/Resources/metadata/clientDefs/CMietobjekt.json b/custom/Espo/Custom/Resources/metadata/clientDefs/CMietobjekt.json index d56ba627..21d6326f 100644 --- a/custom/Espo/Custom/Resources/metadata/clientDefs/CMietobjekt.json +++ b/custom/Espo/Custom/Resources/metadata/clientDefs/CMietobjekt.json @@ -5,22 +5,6 @@ ], "color": "#dea185", "iconClass": "fas fa-house", - "menu": { - "detail": { - "buttons": [ - { - "label": "Räumungsklage einleiten", - "name": "initiateEviction", - "iconHtml": "", - "style": "danger", - "acl": "edit", - "handler": "custom:handlers/mietobjekt/eviction-action", - "initFunction": "initEvictionAction", - "actionFunction": "initiateEviction" - } - ] - } - }, "relationshipPanels": { "vmhMietverhltnises2Mietobjekt": { "layout": null, diff --git a/custom/Espo/Custom/Resources/metadata/clientDefs/CVmhMietverhltnis.json b/custom/Espo/Custom/Resources/metadata/clientDefs/CVmhMietverhltnis.json index fa2ebc38..d23a758e 100644 --- a/custom/Espo/Custom/Resources/metadata/clientDefs/CVmhMietverhltnis.json +++ b/custom/Espo/Custom/Resources/metadata/clientDefs/CVmhMietverhltnis.json @@ -3,6 +3,32 @@ "boolFilterList": [ "onlyMy" ], + "menu": { + "detail": { + "buttons": [ + { + "name": "initiateEviction", + "label": "Initiate Eviction", + "handler": "custom:handlers/mietverhaeltnis/eviction-action", + "initFunction": "initInitiateEviction", + "actionFunction": "actionInitiateEviction", + "iconHtml": "", + "style": "danger", + "acl": "edit" + }, + { + "name": "initiateRentCollection", + "label": "Initiate Rent Collection", + "handler": "custom:handlers/mietverhaeltnis/rent-collection-action", + "initFunction": "initInitiateRentCollection", + "actionFunction": "actionInitiateRentCollection", + "iconHtml": "", + "style": "warning", + "acl": "edit" + } + ] + } + }, "sidePanels": { "detail": [ { diff --git a/custom/Espo/Custom/Services/CMietobjekt.php b/custom/Espo/Custom/Services/CMietobjekt.php deleted file mode 100644 index de1cd882..00000000 --- a/custom/Espo/Custom/Services/CMietobjekt.php +++ /dev/null @@ -1,132 +0,0 @@ -entityManager->getEntity('CMietobjekt', $mietobjektId); - if (!$mietobjekt) { - throw new NotFound('Mietobjekt not found'); - } - - // Check ACL - Read and Create permissions - if (!$this->acl->check($mietobjekt, 'read')) { - throw new Forbidden('No read access to Mietobjekt'); - } - - if (!$this->acl->checkScope('CVmhRumungsklage', 'create')) { - throw new Forbidden('No create access to Räumungsklage'); - } - - // Start transaction to ensure atomicity - $this->entityManager->getTransactionManager()->start(); - - try { - // Prepare data for new Räumungsklage - $data = new \stdClass(); - $data->name = 'Räumungsklage - ' . $mietobjekt->get('name'); - - // Copy assignedUser and teams - if ($mietobjekt->get('assignedUserId')) { - $data->assignedUserId = $mietobjekt->get('assignedUserId'); - } - - $teamsIds = $mietobjekt->getLinkMultipleIdList('teams'); - if (!empty($teamsIds)) { - $data->teamsIds = $teamsIds; - } - - // Create Räumungsklage entity - $raeumungsklage = $this->entityManager->createEntity('CVmhRumungsklage', (array)$data); - - if (!$raeumungsklage) { - throw new \RuntimeException('Failed to create Räumungsklage'); - } - - $raeumungsklagenRepo = $this->entityManager->getRepository('CVmhRumungsklage'); - - // Link Mietobjekt to Räumungsklage - $raeumungsklagenRepo - ->getRelation($raeumungsklage, 'mietobjekte') - ->relate($mietobjekt); - - // Get and link Mietverhältnisse - $mietverhaeltnisse = $this->entityManager - ->getRepository('CMietobjekt') - ->getRelation($mietobjekt, 'vmhMietverhltnises') - ->find(); - - foreach ($mietverhaeltnisse as $mietverhaeltnis) { - // Link Mietverhältnis to Räumungsklage - $raeumungsklagenRepo - ->getRelation($raeumungsklage, 'vmhMietverhltnises') - ->relate($mietverhaeltnis); - - // Get Vermieter (Kläger) from Mietverhältnis - $vermieterBeteiligte = $this->entityManager - ->getRepository('CVmhMietverhltnis') - ->getRelation($mietverhaeltnis, 'vmhbeteiligtevermieter') - ->find(); - - foreach ($vermieterBeteiligte as $vermieter) { - // Link as Kläger - $raeumungsklagenRepo - ->getRelation($raeumungsklage, 'klaeger') - ->relate($vermieter); - } - - // Get Mieter (Beklagte) from Mietverhältnis - $mieterBeteiligte = $this->entityManager - ->getRepository('CVmhMietverhltnis') - ->getRelation($mietverhaeltnis, 'vmhbeteiligtemieter') - ->find(); - - foreach ($mieterBeteiligte as $mieter) { - // Link as Beklagte - $raeumungsklagenRepo - ->getRelation($raeumungsklage, 'beklagte') - ->relate($mieter); - } - } - - // Copy portal contacts from Mietobjekt - $portalContacts = $this->entityManager - ->getRepository('CMietobjekt') - ->getRelation($mietobjekt, 'contactsMietobjekt') - ->find(); - - foreach ($portalContacts as $contact) { - $raeumungsklagenRepo - ->getRelation($raeumungsklage, 'contactsRumungsklage') - ->relate($contact); - } - - // Commit transaction - $this->entityManager->getTransactionManager()->commit(); - - return [ - 'id' => $raeumungsklage->getId(), - 'name' => $raeumungsklage->get('name') - ]; - } catch (\Exception $e) { - // Rollback on any error - $this->entityManager->getTransactionManager()->rollback(); - throw $e; - } - } -} diff --git a/custom/Espo/Custom/Services/CVmhMietverhltnis.php b/custom/Espo/Custom/Services/CVmhMietverhltnis.php new file mode 100644 index 00000000..b28c3081 --- /dev/null +++ b/custom/Espo/Custom/Services/CVmhMietverhltnis.php @@ -0,0 +1,371 @@ +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('CVmhRumungsklage', 'create')) { + throw new Forbidden('No create access to Räumungsklage'); + } + + // 3. Start Transaction + $this->entityManager->getTransactionManager()->start(); + + try { + // 4. Prepare data for new Räumungsklage + $data = new \stdClass(); + $data->name = 'Räumungsklage - ' . $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 Räumungsklage entity + $raeumungsklage = $this->entityManager->createEntity('CVmhRumungsklage', (array)$data); + + if (!$raeumungsklage) { + throw new \RuntimeException('Failed to create Räumungsklage'); + } + + $raeumungsklagenRepo = $this->entityManager->getRepository('CVmhRumungsklage'); + + // 6. Link Mietverhältnis to Räumungsklage + $raeumungsklagenRepo + ->getRelation($raeumungsklage, 'vmhMietverhltnises') + ->relate($mietverhaeltnis); + + // 7. Get and link Mietobjekt + $mietobjekt = $this->entityManager + ->getRepository('CVmhMietverhltnis') + ->getRelation($mietverhaeltnis, 'vmhMietobjekt') + ->findOne(); + + if ($mietobjekt) { + $raeumungsklagenRepo + ->getRelation($raeumungsklage, '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 + $raeumungsklagenRepo + ->getRelation($raeumungsklage, '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 + $raeumungsklagenRepo + ->getRelation($raeumungsklage, '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 + $raeumungsklagenRepo + ->getRelation($raeumungsklage, '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) { + $raeumungsklagenRepo + ->getRelation($raeumungsklage, 'dokumentesvmhraumungsklage') + ->relate($dokument); + } + + // 10b. Dokumente vom Mietobjekt + if ($mietobjekt) { + $dokumenteMO = $this->entityManager + ->getRepository('CMietobjekt') + ->getRelation($mietobjekt, 'dokumentesMietobjekt') + ->find(); + + foreach ($dokumenteMO as $dokument) { + $raeumungsklagenRepo + ->getRelation($raeumungsklage, 'dokumentesvmhraumungsklage') + ->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) { + $raeumungsklagenRepo + ->getRelation($raeumungsklage, 'dokumentesvmhraumungsklage') + ->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) { + $raeumungsklagenRepo + ->getRelation($raeumungsklage, 'contactsRumungsklage') + ->relate($contact); + } + + // 12. Commit transaction + $this->entityManager->getTransactionManager()->commit(); + + return [ + 'id' => $raeumungsklage->getId(), + 'name' => $raeumungsklage->get('name') + ]; + } catch (\Exception $e) { + // Rollback on any error + $this->entityManager->getTransactionManager()->rollback(); + throw $e; + } + } + + /** + * 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. 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; + } + } +} diff --git a/data/config.php b/data/config.php index 7f8ddeca..990aa67d 100644 --- a/data/config.php +++ b/data/config.php @@ -359,8 +359,8 @@ return [ 0 => 'youtube.com', 1 => 'google.com' ], - 'cacheTimestamp' => 1769252191, - 'microtime' => 1769252191.810945, + 'cacheTimestamp' => 1769253751, + 'microtime' => 1769253751.94842, 'siteUrl' => 'https://crm.bitbylaw.com', 'fullTextSearchMinLength' => 4, 'appTimestamp' => 1768843902,