From 0d2d35bca17e7aa51f6ac96d6c747cc96638dc0b Mon Sep 17 00:00:00 2001 From: bsiggel Date: Sat, 24 Jan 2026 12:45:57 +0100 Subject: [PATCH] feat: Add termination functionality for rental agreements - Introduced new entity `CKuendigung` for managing terminations. - Added fields for termination details including date, reason, type, and status. - Implemented backend service to initiate terminations from rental agreements. - Created frontend handler for termination actions with confirmation dialog. - Updated metadata and layouts for `CKuendigung` to support new functionality. - Added internationalization support for English and German languages. - Enhanced existing entities to establish relationships with terminations. --- .../mietverhaeltnis/termination-action.js | 70 ++++ .../Custom/Controllers/CVmhMietverhltnis.php | 18 + .../Resources/i18n/de_DE/CBeteiligte.json | 4 + .../Resources/i18n/de_DE/CDokumente.json | 2 + .../Resources/i18n/de_DE/CKuendigung.json | 94 +++++ .../Resources/i18n/de_DE/CMietobjekt.json | 4 +- .../i18n/de_DE/CVmhMietverhltnis.json | 10 +- .../Custom/Resources/i18n/de_DE/Contact.json | 3 + .../Resources/i18n/en_US/CBeteiligte.json | 4 + .../Resources/i18n/en_US/CDokumente.json | 2 + .../Resources/i18n/en_US/CKuendigung.json | 94 +++++ .../Resources/i18n/en_US/CMietobjekt.json | 1 + .../i18n/en_US/CVmhMietverhltnis.json | 1 + .../Custom/Resources/i18n/en_US/Contact.json | 1 + .../metadata/clientDefs/CKuendigung.json | 55 +++ .../clientDefs/CVmhMietverhltnis.json | 10 + .../metadata/entityDefs/CBeteiligte.json | 16 + .../metadata/entityDefs/CDokumente.json | 8 + .../metadata/entityDefs/CKuendigung.json | 338 ++++++++++++++++++ .../metadata/entityDefs/CMietobjekt.json | 8 + .../entityDefs/CVmhMietverhltnis.json | 8 + .../metadata/entityDefs/Contact.json | 8 + .../metadata/layouts/CKuendigung/detail.json | 109 ++++++ .../layouts/CKuendigung/detailSmall.json | 40 +++ .../metadata/layouts/CKuendigung/list.json | 30 ++ .../metadata/scopes/CKuendigung.json | 11 + .../Custom/Services/CVmhMietverhltnis.php | 136 +++++++ data/config.php | 66 ++-- 28 files changed, 1115 insertions(+), 36 deletions(-) create mode 100644 client/custom/src/handlers/mietverhaeltnis/termination-action.js create mode 100644 custom/Espo/Custom/Resources/i18n/de_DE/CKuendigung.json create mode 100644 custom/Espo/Custom/Resources/i18n/en_US/CKuendigung.json create mode 100644 custom/Espo/Custom/Resources/metadata/clientDefs/CKuendigung.json create mode 100644 custom/Espo/Custom/Resources/metadata/entityDefs/CKuendigung.json create mode 100644 custom/Espo/Custom/Resources/metadata/layouts/CKuendigung/detail.json create mode 100644 custom/Espo/Custom/Resources/metadata/layouts/CKuendigung/detailSmall.json create mode 100644 custom/Espo/Custom/Resources/metadata/layouts/CKuendigung/list.json create mode 100644 custom/Espo/Custom/Resources/metadata/scopes/CKuendigung.json diff --git a/client/custom/src/handlers/mietverhaeltnis/termination-action.js b/client/custom/src/handlers/mietverhaeltnis/termination-action.js new file mode 100644 index 00000000..b1a02735 --- /dev/null +++ b/client/custom/src/handlers/mietverhaeltnis/termination-action.js @@ -0,0 +1,70 @@ +define('custom:handlers/mietverhaeltnis/termination-action', [], function () { + + class TerminationActionHandler { + + constructor(view) { + this.view = view; + } + + /** + * Setup-Methode wird automatisch aufgerufen + */ + initInitiateTermination() { + // Optional: Button-Logik nach Render + } + + /** + * Action-Handler (wird bei Button-Click aufgerufen) + */ + actionInitiateTermination() { + console.log('actionInitiateTermination called'); + const model = this.view.model; + + // Confirmation Dialog + this.view.confirm( + this.view.translate('confirmTermination', 'messages', 'CVmhMietverhltnis'), + () => { + console.log('Confirmation accepted, initiating termination'); + this.initiateTermination(model.id); + } + ); + } + + /** + * AJAX Request zum Backend + */ + initiateTermination(mietverhaeltnisId) { + Espo.Ui.notify(this.view.translate('pleaseWait', 'messages')); + + Espo.Ajax.postRequest('CVmhMietverhltnis/action/initiateTermination', { + id: mietverhaeltnisId + }) + .then(response => { + Espo.Ui.success( + this.view.translate('terminationCreated', 'messages', 'CVmhMietverhltnis') + ); + + // Navigation zur erstellten Kündigung + this.view.getRouter().navigate( + '#CKuendigung/view/' + response.id, + {trigger: true} + ); + }) + .catch(xhr => { + console.error('Termination initiation failed:', xhr); + + let errorMessage = this.view.translate('terminationError', '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 TerminationActionHandler; +}); diff --git a/custom/Espo/Custom/Controllers/CVmhMietverhltnis.php b/custom/Espo/Custom/Controllers/CVmhMietverhltnis.php index 78b1a241..2d491d2c 100644 --- a/custom/Espo/Custom/Controllers/CVmhMietverhltnis.php +++ b/custom/Espo/Custom/Controllers/CVmhMietverhltnis.php @@ -42,4 +42,22 @@ class CVmhMietverhltnis extends \Espo\Core\Templates\Controllers\BasePlus return $result; } + + /** + * POST Action: Initiate termination from Mietverhältnis + */ + public function postActionInitiateTermination(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->initiateTermination($id); + + return $result; + } } diff --git a/custom/Espo/Custom/Resources/i18n/de_DE/CBeteiligte.json b/custom/Espo/Custom/Resources/i18n/de_DE/CBeteiligte.json index 559d2481..e455369a 100644 --- a/custom/Espo/Custom/Resources/i18n/de_DE/CBeteiligte.json +++ b/custom/Espo/Custom/Resources/i18n/de_DE/CBeteiligte.json @@ -12,6 +12,8 @@ "vmhRumungsklagesBeklagte": "Beklagte", "mietinkassosKlaeger": "Mietinkasso (Kläger)", "mietinkassosBeklagte": "Mietinkasso (Beklagte)", + "kuendigungenVermieter": "Kündigungen (Vermieter)", + "kuendigungenMieter": "Kündigungen (Mieter)", "adressens": "Adressen", "calls1": "Anrufe", "contactsBeteiligte": "Freigegebene Nutzer", @@ -33,6 +35,8 @@ "vmhRumungsklagesBeklagte": "Beklagte", "mietinkassosKlaeger": "Mietinkasso (Kläger)", "mietinkassosBeklagte": "Mietinkasso (Beklagte)", + "kuendigungenVermieter": "Kündigungen (Vermieter)", + "kuendigungenMieter": "Kündigungen (Mieter)", "adressens": "Adressen", "calls1": "Anrufe", "contactsBeteiligte": "Freigegebene Nutzer", diff --git a/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json b/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json index 8484ef7a..459be10a 100644 --- a/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json +++ b/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json @@ -12,6 +12,7 @@ "vmhMietverhltnisesDokumente": "Mietverhältnisse", "vmhErstgespraechsdokumente": "Erstgespräche", "vmhRumungsklagesdokumente": "Räumungsklagen", + "kuendigungDokumente": "Kündigungen", "beteiligte2dokumente": "Beteiligte", "mietobjekt2dokumente": "Mietobjekte" }, @@ -20,6 +21,7 @@ "vmhMietverhltnisesDokumente": "Mietverhältnisse", "vmhErstgespraechsdokumente": "Erstgespräche", "vmhRumungsklagesdokumente": "Räumungsklagen", + "kuendigungDokumente": "Kündigungen", "beteiligte2dokumente": "Beteiligte", "mietobjekt2dokumente": "Mietobjekte", "mietinkassosdokumente": "Mietinkasso" diff --git a/custom/Espo/Custom/Resources/i18n/de_DE/CKuendigung.json b/custom/Espo/Custom/Resources/i18n/de_DE/CKuendigung.json new file mode 100644 index 00000000..91cb2258 --- /dev/null +++ b/custom/Espo/Custom/Resources/i18n/de_DE/CKuendigung.json @@ -0,0 +1,94 @@ +{ + "fields": { + "kuendigungsdatum": "Kündigungsdatum", + "kuendigungsfrist": "Kündigungsfrist / Auszugsdatum", + "kuendigungsgrund": "Kündigungsgrund", + "kuendigungsart": "Kündigungsart", + "kuendigenderPartei": "Kündigende Partei", + "status": "Status", + "zustellungsdatum": "Zustellungsdatum", + "zustellungsart": "Zustellungsart", + "rueckstandsbetrag": "Rückstandsbetrag", + "monateMietrückstand": "Monate Mietrückstand", + "schonfristGewaehrt": "Schonfrist gewährt", + "schonfristDatum": "Schonfrist Datum", + "besorgnisNichtRechtzeitigerAuszug": "Besorgnis nicht rechtzeitiger Auszug", + "anmerkungen": "Anmerkungen", + "vmhMietverhltnis": "Mietverhältnis", + "mietobjekt": "Mietobjekt", + "vermieter": "Vermieter", + "mieter": "Mieter", + "dokumenteKuendigung": "Dokumente", + "contactsKuendigung": "Freigegebene Nutzer" + }, + "links": { + "vmhMietverhltnis": "Mietverhältnis", + "mietobjekt": "Mietobjekt", + "vermieter": "Vermieter", + "mieter": "Mieter", + "dokumenteKuendigung": "Dokumente", + "contactsKuendigung": "Freigegebene Nutzer", + "meetings": "Besprechungen", + "calls": "Anrufe", + "tasks": "Aufgaben", + "emails": "E-Mails", + "collaborators": "Mitarbeiter" + }, + "labels": { + "Create CKuendigung": "Kündigung erstellen" + }, + "options": { + "kuendigungsgrund": { + "Mietrückstand": "Mietrückstand", + "Eigenbedarf": "Eigenbedarf", + "Fehlverhalten": "Fehlverhalten", + "Verwertung": "Verwertung", + "ZVG Eigenbedarf": "ZVG Eigenbedarf", + "573a Abs. 1 (nicht mehr als 2 Whng.)": "§573a Abs. 1 (nicht mehr als 2 Wohnungen)", + "573a Abs. 2 (Einliegerwohnung)": "§573a Abs. 2 (Einliegerwohnung)", + "GewerbeOrdentlich": "Gewerbe ordentlich", + "Sonstige": "Sonstige" + }, + "kuendigungsart": { + "Ordentlich": "Ordentlich", + "Außerordentlich (fristlos)": "Außerordentlich (fristlos)", + "Außerordentlich (mit sozialer Frist)": "Außerordentlich (mit sozialer Frist)" + }, + "kuendigenderPartei": { + "Vermieter": "Vermieter", + "Mieter": "Mieter" + }, + "status": { + "Entwurf": "Entwurf", + "Versendet": "Versendet", + "Zugestellt": "Zugestellt", + "Anerkannt": "Anerkannt", + "Bestritten": "Bestritten", + "Vollzogen": "Vollzogen", + "Widerrufen": "Widerrufen" + }, + "zustellungsart": { + "Persönlich": "Persönlich", + "Einschreiben": "Einschreiben", + "Gerichtlicher Zustellungsbevollmächtigter": "Gerichtlicher Zustellungsbevollmächtigter", + "E-Mail (sofern vereinbart)": "E-Mail (sofern vereinbart)", + "Sonstige": "Sonstige" + } + }, + "tooltips": { + "kuendigungsdatum": "Datum, an dem die Kündigung ausgesprochen wurde", + "kuendigungsfrist": "Datum, bis zu dem das Mietverhältnis beendet sein soll (Auszugsdatum)", + "kuendigungsgrund": "Rechtlicher Grund für die Kündigung (kann mehrere sein)", + "kuendigungsart": "Art der Kündigung: ordentlich mit Frist, außerordentlich fristlos oder mit sozialer Frist", + "kuendigenderPartei": "Welche Partei kündigt das Mietverhältnis", + "status": "Aktueller Bearbeitungsstatus der Kündigung", + "zustellungsdatum": "Datum, an dem die Kündigung dem Empfänger zugestellt wurde", + "zustellungsart": "Art der Zustellung (z.B. persönlich, Einschreiben)", + "rueckstandsbetrag": "Gesamtbetrag des Mietrückstands (bei Kündigung wegen Mietrückstand)", + "monateMietrückstand": "Anzahl der Monate, für die Mietrückstand besteht", + "schonfristGewaehrt": "Wurde eine Schonfrist nach § 569 Abs. 3 Nr. 2 BGB gewährt?", + "schonfristDatum": "Bis zu welchem Datum läuft die Schonfrist?", + "besorgnisNichtRechtzeitigerAuszug": "Besteht die Besorgnis, dass der Mieter nicht rechtzeitig auszieht? (Relevant für § 940a ZPO)", + "anmerkungen": "Zusätzliche Hinweise und Anmerkungen zur Kündigung" + } +} diff --git a/custom/Espo/Custom/Resources/i18n/de_DE/CMietobjekt.json b/custom/Espo/Custom/Resources/i18n/de_DE/CMietobjekt.json index 9638c128..e105f066 100644 --- a/custom/Espo/Custom/Resources/i18n/de_DE/CMietobjekt.json +++ b/custom/Espo/Custom/Resources/i18n/de_DE/CMietobjekt.json @@ -6,7 +6,8 @@ "vmhMietverhltnises2Mietobjekt": "Mietverhältnisse (veraltet)", "vmhMietverhltnises": "Mietverhältnisse", "contactsMietobjekt": "Freigegebene Nutzer", - "dokumentesMietobjekt": "Dokumente" + "dokumentesMietobjekt": "Dokumente", + "kuendigungen": "Kündigungen" }, "links": { "vmhMietverhltnises2Mietobjekt": "Mietverhältnisse (veraltet)", @@ -14,6 +15,7 @@ "contact2mietobjekt": "Kontakte", "vmhRumungsklages": "Räumungsklagen", "mietinkassos": "Mietinkasso", + "kuendigungen": "Kündigungen", "contactsMietobjekt": "Freigegebene Nutzer", "dokumentesMietobjekt": "Dokumente" }, diff --git a/custom/Espo/Custom/Resources/i18n/de_DE/CVmhMietverhltnis.json b/custom/Espo/Custom/Resources/i18n/de_DE/CVmhMietverhltnis.json index b95acc7a..da001597 100644 --- a/custom/Espo/Custom/Resources/i18n/de_DE/CVmhMietverhltnis.json +++ b/custom/Espo/Custom/Resources/i18n/de_DE/CVmhMietverhltnis.json @@ -13,6 +13,7 @@ "warmmiete": "Warmmiete", "vmhRumungsklages": "Räumungsklagen", "mietinkassos": "Mietinkasso", + "kuendigungen": "Kündigungen", "vmhbeteiligtevermieter": "Vermieter", "vmhbeteiligtemieter": "Mieter", "contactsMietverhltnis": "Freigegebene Nutzer", @@ -33,6 +34,7 @@ "tasks": "Aufgaben", "vmhRumungsklages": "Räumungsklagen", "mietinkassos": "Mietinkasso", + "kuendigungen": "Kündigungen", "vmhbeteiligtevermieter": "Vermieter", "vmhbeteiligtemieter": "Mieter", "contactsMietverhltnis": "Freigegebene Nutzer", @@ -44,7 +46,8 @@ "labels": { "Create CVmhMietverhltnis": "Mietverhältnis erstellen", "Initiate Eviction": "Räumungsklage einleiten", - "Initiate Rent Collection": "Mietinkasso einleiten" + "Initiate Rent Collection": "Mietinkasso einleiten", + "Initiate Termination": "Kündigung erstellen" }, "messages": { "confirmEviction": "Möchten Sie wirklich eine Räumungsklage aus diesem Mietverhältnis einleiten?", @@ -52,6 +55,9 @@ "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" + "rentCollectionError": "Fehler beim Erstellen des Mietinkassos", + "confirmTermination": "Möchten Sie wirklich eine Kündigung für dieses Mietverhältnis erstellen?", + "terminationCreated": "Kündigung wurde erfolgreich erstellt", + "terminationError": "Fehler beim Erstellen der Kündigung" } } \ No newline at end of file diff --git a/custom/Espo/Custom/Resources/i18n/de_DE/Contact.json b/custom/Espo/Custom/Resources/i18n/de_DE/Contact.json index ca681698..cbc1baae 100644 --- a/custom/Espo/Custom/Resources/i18n/de_DE/Contact.json +++ b/custom/Espo/Custom/Resources/i18n/de_DE/Contact.json @@ -14,6 +14,8 @@ "cMietobjekteContactPortal": "Mietobjekte (Portal)", "cAdressenContact": "Adressen", "cVmhRumungsklageContact": "Räumungsklagen (Portal)", + "cMietinkassoContact": "Mietinkasso (Portal)", + "cKuendigungContact": "Kündigungen (Portal)", "cBankverbindungenContact": "Bankverbindungen" }, "links": { @@ -29,6 +31,7 @@ "cAdressenContact": "Adressen", "cVmhRumungsklageContact": "Räumungsklagen (Portal)", "cMietinkassoContact": "Mietinkasso", + "cKuendigungContact": "Kündigungen (Portal)", "cBankverbindungenContact": "Bankverbindungen" }, "options": { diff --git a/custom/Espo/Custom/Resources/i18n/en_US/CBeteiligte.json b/custom/Espo/Custom/Resources/i18n/en_US/CBeteiligte.json index 64018d9c..fc2f92b7 100644 --- a/custom/Espo/Custom/Resources/i18n/en_US/CBeteiligte.json +++ b/custom/Espo/Custom/Resources/i18n/en_US/CBeteiligte.json @@ -11,6 +11,8 @@ "vmhRumungsklagesKlaeger": "Plaintiff", "mietinkassosKlaeger": "Rent Collection (Plaintiff)", "mietinkassosBeklagte": "Rent Collection (Defendant)", + "kuendigungenVermieter": "Terminations (Landlord)", + "kuendigungenMieter": "Terminations (Tenant)", "contactsBeteiligte": "Portal Users", "dokumentesBeteiligte": "Documents" }, @@ -27,6 +29,8 @@ "vmhRumungsklagesKlaeger": "Plaintiff", "mietinkassosKlaeger": "Rent Collection (Plaintiff)", "mietinkassosBeklagte": "Rent Collection (Defendant)", + "kuendigungenVermieter": "Terminations (Landlord)", + "kuendigungenMieter": "Terminations (Tenant)", "contactsBeteiligte": "Portal Users", "dokumentesBeteiligte": "Documents", "bankverbindungens": "Bank Accounts" diff --git a/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json b/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json index 03d224db..accad2a5 100644 --- a/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json +++ b/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json @@ -7,6 +7,7 @@ "vmhMietverhltnisesDokumente": "Tenancies", "vmhErstgespraechsdokumente": "Initial Consultations", "vmhRumungsklagesdokumente": "Eviction Lawsuits", + "kuendigungDokumente": "Terminations", "md5sum": "MD5 Checksum", "sha256": "SHA256 Checksum", "beteiligte2dokumente": "Parties", @@ -17,6 +18,7 @@ "vmhMietverhltnisesDokumente": "Tenancies", "vmhErstgespraechsdokumente": "Initial Consultations", "vmhRumungsklagesdokumente": "Eviction Lawsuits", + "kuendigungDokumente": "Terminations", "beteiligte2dokumente": "Parties", "mietobjekt2dokumente": "Properties", "mietinkassosdokumente": "Rent Collection" diff --git a/custom/Espo/Custom/Resources/i18n/en_US/CKuendigung.json b/custom/Espo/Custom/Resources/i18n/en_US/CKuendigung.json new file mode 100644 index 00000000..860d3ae9 --- /dev/null +++ b/custom/Espo/Custom/Resources/i18n/en_US/CKuendigung.json @@ -0,0 +1,94 @@ +{ + "fields": { + "kuendigungsdatum": "Termination Date", + "kuendigungsfrist": "Notice Period / Move-out Date", + "kuendigungsgrund": "Termination Reason", + "kuendigungsart": "Termination Type", + "kuendigenderPartei": "Terminating Party", + "status": "Status", + "zustellungsdatum": "Delivery Date", + "zustellungsart": "Delivery Method", + "rueckstandsbetrag": "Arrears Amount", + "monateMietrückstand": "Months of Arrears", + "schonfristGewaehrt": "Grace Period Granted", + "schonfristDatum": "Grace Period Date", + "besorgnisNichtRechtzeitigerAuszug": "Concern of Delayed Move-out", + "anmerkungen": "Notes", + "vmhMietverhltnis": "Rental Agreement", + "mietobjekt": "Property", + "vermieter": "Landlords", + "mieter": "Tenants", + "dokumenteKuendigung": "Documents", + "contactsKuendigung": "Shared Users" + }, + "links": { + "vmhMietverhltnis": "Rental Agreement", + "mietobjekt": "Property", + "vermieter": "Landlords", + "mieter": "Tenants", + "dokumenteKuendigung": "Documents", + "contactsKuendigung": "Shared Users", + "meetings": "Meetings", + "calls": "Calls", + "tasks": "Tasks", + "emails": "Emails", + "collaborators": "Collaborators" + }, + "labels": { + "Create CKuendigung": "Create Termination" + }, + "options": { + "kuendigungsgrund": { + "Mietrückstand": "Rent Arrears", + "Eigenbedarf": "Personal Use", + "Fehlverhalten": "Misconduct", + "Verwertung": "Utilization", + "ZVG Eigenbedarf": "Foreclosure Personal Use", + "573a Abs. 1 (nicht mehr als 2 Whng.)": "§573a Para. 1 (max 2 units)", + "573a Abs. 2 (Einliegerwohnung)": "§573a Para. 2 (granny flat)", + "GewerbeOrdentlich": "Commercial Regular", + "Sonstige": "Other" + }, + "kuendigungsart": { + "Ordentlich": "Regular", + "Außerordentlich (fristlos)": "Extraordinary (without notice)", + "Außerordentlich (mit sozialer Frist)": "Extraordinary (with social grace period)" + }, + "kuendigenderPartei": { + "Vermieter": "Landlord", + "Mieter": "Tenant" + }, + "status": { + "Entwurf": "Draft", + "Versendet": "Sent", + "Zugestellt": "Delivered", + "Anerkannt": "Acknowledged", + "Bestritten": "Disputed", + "Vollzogen": "Completed", + "Widerrufen": "Revoked" + }, + "zustellungsart": { + "Persönlich": "Personal", + "Einschreiben": "Registered Mail", + "Gerichtlicher Zustellungsbevollmächtigter": "Court Process Server", + "E-Mail (sofern vereinbart)": "E-Mail (if agreed)", + "Sonstige": "Other" + } + }, + "tooltips": { + "kuendigungsdatum": "Date when the termination was issued", + "kuendigungsfrist": "Date by which the tenancy should end (move-out date)", + "kuendigungsgrund": "Legal reason(s) for termination", + "kuendigungsart": "Type of termination: regular with notice period, extraordinary without notice, or with social grace period", + "kuendigenderPartei": "Which party terminates the tenancy", + "status": "Current processing status of the termination", + "zustellungsdatum": "Date when the termination was delivered to the recipient", + "zustellungsart": "Method of delivery (e.g., personal, registered mail)", + "rueckstandsbetrag": "Total amount of rent arrears (for termination due to rent arrears)", + "monateMietrückstand": "Number of months for which rent is in arrears", + "schonfristGewaehrt": "Was a grace period granted according to § 569 Para. 3 No. 2 BGB?", + "schonfristDatum": "Until what date does the grace period run?", + "besorgnisNichtRechtzeitigerAuszug": "Is there concern that the tenant will not move out on time? (Relevant for § 940a ZPO)", + "anmerkungen": "Additional notes and comments about the termination" + } +} diff --git a/custom/Espo/Custom/Resources/i18n/en_US/CMietobjekt.json b/custom/Espo/Custom/Resources/i18n/en_US/CMietobjekt.json index fc630b1c..f0482da7 100644 --- a/custom/Espo/Custom/Resources/i18n/en_US/CMietobjekt.json +++ b/custom/Espo/Custom/Resources/i18n/en_US/CMietobjekt.json @@ -20,6 +20,7 @@ "contact2mietobjekt": "Contacts", "vmhRumungsklages": "Eviction Lawsuits", "mietinkassos": "Rent Collection", + "kuendigungen": "Terminations", "contactsMietobjekt": "Portal Users", "dokumentesMietobjekt": "Documents" }, diff --git a/custom/Espo/Custom/Resources/i18n/en_US/CVmhMietverhltnis.json b/custom/Espo/Custom/Resources/i18n/en_US/CVmhMietverhltnis.json index 9b4b1962..40153de8 100644 --- a/custom/Espo/Custom/Resources/i18n/en_US/CVmhMietverhltnis.json +++ b/custom/Espo/Custom/Resources/i18n/en_US/CVmhMietverhltnis.json @@ -36,6 +36,7 @@ "tasks": "Tasks", "vmhRumungsklages": "Eviction Lawsuits", "mietinkassos": "Rent Collection", + "kuendigungen": "Terminations", "vmhbeteiligtevermieter": "Landlords", "vmhbeteiligtemieter": "Tenants", "contactsMietverhltnis": "Portal Users", diff --git a/custom/Espo/Custom/Resources/i18n/en_US/Contact.json b/custom/Espo/Custom/Resources/i18n/en_US/Contact.json index f4ac5932..66ee8879 100644 --- a/custom/Espo/Custom/Resources/i18n/en_US/Contact.json +++ b/custom/Espo/Custom/Resources/i18n/en_US/Contact.json @@ -23,6 +23,7 @@ "cAdressenContact": "Addresses", "cVmhRumungsklageContact": "Eviction Lawsuits (Portal)", "cMietinkassoContact": "Rent Collection", + "cKuendigungContact": "Terminations (Portal)", "cBankverbindungenContact": "Bank Accounts" }, "options": { diff --git a/custom/Espo/Custom/Resources/metadata/clientDefs/CKuendigung.json b/custom/Espo/Custom/Resources/metadata/clientDefs/CKuendigung.json new file mode 100644 index 00000000..c0b48d8d --- /dev/null +++ b/custom/Espo/Custom/Resources/metadata/clientDefs/CKuendigung.json @@ -0,0 +1,55 @@ +{ + "controller": "controllers/record", + "boolFilterList": [ + "onlyMy" + ], + "iconClass": "fas fa-file-contract", + "sidePanels": { + "detail": [ + { + "name": "activities", + "reference": "activities" + }, + { + "name": "history", + "reference": "history" + }, + { + "name": "tasks", + "reference": "tasks" + } + ] + }, + "bottomPanels": { + "detail": [ + { + "name": "activities", + "reference": "activities", + "disabled": true + }, + { + "name": "history", + "reference": "history", + "disabled": true + } + ] + }, + "relationshipPanels": { + "vermieter": { + "layout": null, + "selectPrimaryFilterName": null + }, + "mieter": { + "layout": null, + "selectPrimaryFilterName": null + }, + "dokumenteKuendigung": { + "layout": null, + "selectPrimaryFilterName": null + }, + "contactsKuendigung": { + "layout": null, + "selectPrimaryFilterName": "portalUsers" + } + } +} diff --git a/custom/Espo/Custom/Resources/metadata/clientDefs/CVmhMietverhltnis.json b/custom/Espo/Custom/Resources/metadata/clientDefs/CVmhMietverhltnis.json index d23a758e..07e82eca 100644 --- a/custom/Espo/Custom/Resources/metadata/clientDefs/CVmhMietverhltnis.json +++ b/custom/Espo/Custom/Resources/metadata/clientDefs/CVmhMietverhltnis.json @@ -25,6 +25,16 @@ "iconHtml": "", "style": "warning", "acl": "edit" + }, + { + "name": "initiateTermination", + "label": "Initiate Termination", + "handler": "custom:handlers/mietverhaeltnis/termination-action", + "initFunction": "initInitiateTermination", + "actionFunction": "actionInitiateTermination", + "iconHtml": "", + "style": "primary", + "acl": "edit" } ] } diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/CBeteiligte.json b/custom/Espo/Custom/Resources/metadata/entityDefs/CBeteiligte.json index 9eb14219..d83a6939 100644 --- a/custom/Espo/Custom/Resources/metadata/entityDefs/CBeteiligte.json +++ b/custom/Espo/Custom/Resources/metadata/entityDefs/CBeteiligte.json @@ -294,6 +294,22 @@ "audited": false, "isCustom": true }, + "kuendigungenVermieter": { + "type": "hasMany", + "relationName": "cBeteiligteKuendigungVermieter", + "foreign": "vermieter", + "entity": "CKuendigung", + "audited": false, + "isCustom": true + }, + "kuendigungenMieter": { + "type": "hasMany", + "relationName": "cBeteiligteKuendigungMieter", + "foreign": "mieter", + "entity": "CKuendigung", + "audited": false, + "isCustom": true + }, "dokumentesBeteiligte": { "type": "hasMany", "relationName": "cBeteiligteDokumente", diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json b/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json index ba5ce257..81794929 100644 --- a/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json +++ b/custom/Espo/Custom/Resources/metadata/entityDefs/CDokumente.json @@ -176,6 +176,14 @@ "audited": false, "isCustom": true }, + "kuendigungDokumente": { + "type": "hasMany", + "relationName": "cDokumenteKuendigung", + "foreign": "dokumenteKuendigung", + "entity": "CKuendigung", + "audited": false, + "isCustom": true + }, "beteiligte2dokumente": { "type": "hasMany", "relationName": "cBeteiligteDokumente", diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/CKuendigung.json b/custom/Espo/Custom/Resources/metadata/entityDefs/CKuendigung.json new file mode 100644 index 00000000..44176db2 --- /dev/null +++ b/custom/Espo/Custom/Resources/metadata/entityDefs/CKuendigung.json @@ -0,0 +1,338 @@ +{ + "fields": { + "name": { + "type": "varchar", + "required": true, + "pattern": "$noBadCharacters" + }, + "description": { + "type": "text" + }, + "createdAt": { + "type": "datetime", + "readOnly": true + }, + "modifiedAt": { + "type": "datetime", + "readOnly": true + }, + "createdBy": { + "type": "link", + "readOnly": true, + "view": "views/fields/user" + }, + "modifiedBy": { + "type": "link", + "readOnly": true, + "view": "views/fields/user" + }, + "assignedUser": { + "type": "link", + "required": false, + "view": "views/fields/assigned-user" + }, + "teams": { + "type": "linkMultiple", + "view": "views/fields/teams" + }, + "collaborators": { + "type": "linkMultiple", + "view": "views/fields/collaborators", + "maxCount": 30, + "fieldManagerParamList": [ + "readOnly", + "readOnlyAfterCreate", + "audited", + "autocompleteOnEmpty", + "maxCount", + "inlineEditDisabled", + "tooltipText" + ] + }, + "kuendigungsdatum": { + "type": "date", + "required": true, + "tooltip": true, + "isCustom": true + }, + "kuendigungsfrist": { + "type": "date", + "required": true, + "after": "kuendigungsdatum", + "tooltip": true, + "isCustom": true + }, + "kuendigungsgrund": { + "type": "multiEnum", + "required": true, + "options": [ + "Mietrückstand", + "Eigenbedarf", + "Fehlverhalten", + "Verwertung", + "ZVG Eigenbedarf", + "573a Abs. 1 (nicht mehr als 2 Whng.)", + "573a Abs. 2 (Einliegerwohnung)", + "GewerbeOrdentlich", + "Sonstige" + ], + "default": ["Mietrückstand"], + "tooltip": true, + "isCustom": true + }, + "kuendigungsart": { + "type": "enum", + "required": true, + "options": [ + "Ordentlich", + "Außerordentlich (fristlos)", + "Außerordentlich (mit sozialer Frist)" + ], + "style": { + "Ordentlich": "success", + "Außerordentlich (fristlos)": "danger", + "Außerordentlich (mit sozialer Frist)": "warning" + }, + "default": "Ordentlich", + "tooltip": true, + "isCustom": true + }, + "kuendigenderPartei": { + "type": "enum", + "required": true, + "options": [ + "Vermieter", + "Mieter" + ], + "style": { + "Vermieter": "primary", + "Mieter": "info" + }, + "default": "Vermieter", + "tooltip": true, + "isCustom": true + }, + "status": { + "type": "enum", + "required": true, + "options": [ + "Entwurf", + "Versendet", + "Zugestellt", + "Anerkannt", + "Bestritten", + "Vollzogen", + "Widerrufen" + ], + "style": { + "Entwurf": null, + "Versendet": "warning", + "Zugestellt": "info", + "Anerkannt": "success", + "Bestritten": "danger", + "Vollzogen": "success", + "Widerrufen": null + }, + "default": "Entwurf", + "tooltip": true, + "isCustom": true + }, + "zustellungsdatum": { + "type": "date", + "required": false, + "tooltip": true, + "isCustom": true + }, + "zustellungsart": { + "type": "enum", + "required": false, + "options": [ + "Persönlich", + "Einschreiben", + "Gerichtlicher Zustellungsbevollmächtigter", + "E-Mail (sofern vereinbart)", + "Sonstige" + ], + "tooltip": true, + "isCustom": true + }, + "rueckstandsbetrag": { + "type": "currency", + "required": false, + "onlyDefaultCurrency": true, + "conversionDisabled": true, + "min": 0, + "decimal": true, + "tooltip": true, + "isCustom": true + }, + "monateMietrückstand": { + "type": "int", + "required": false, + "min": 0, + "tooltip": true, + "isCustom": true + }, + "schonfristGewaehrt": { + "type": "bool", + "default": false, + "tooltip": true, + "isCustom": true + }, + "schonfristDatum": { + "type": "date", + "required": false, + "tooltip": true, + "isCustom": true + }, + "besorgnisNichtRechtzeitigerAuszug": { + "type": "bool", + "default": false, + "tooltip": true, + "isCustom": true + }, + "anmerkungen": { + "type": "text", + "required": false, + "isCustom": true + }, + "vmhMietverhltnis": { + "type": "link", + "required": false, + "isCustom": true + }, + "mietobjekt": { + "type": "link", + "required": false, + "isCustom": true + } + }, + "links": { + "createdBy": { + "type": "belongsTo", + "entity": "User" + }, + "modifiedBy": { + "type": "belongsTo", + "entity": "User" + }, + "assignedUser": { + "type": "belongsTo", + "entity": "User" + }, + "teams": { + "type": "hasMany", + "entity": "Team", + "relationName": "entityTeam", + "layoutRelationshipsDisabled": true + }, + "collaborators": { + "type": "hasMany", + "entity": "User", + "relationName": "entityCollaborator", + "layoutRelationshipsDisabled": true + }, + "meetings": { + "type": "hasMany", + "entity": "Meeting", + "foreign": "parent" + }, + "calls": { + "type": "hasMany", + "entity": "Call", + "foreign": "parent" + }, + "tasks": { + "type": "hasChildren", + "entity": "Task", + "foreign": "parent" + }, + "emails": { + "type": "hasChildren", + "entity": "Email", + "foreign": "parent", + "layoutRelationshipsDisabled": true + }, + "vmhMietverhltnis": { + "type": "belongsTo", + "foreign": "kuendigungen", + "entity": "CVmhMietverhltnis", + "audited": false, + "isCustom": true + }, + "mietobjekt": { + "type": "belongsTo", + "foreign": "kuendigungen", + "entity": "CMietobjekt", + "audited": false, + "isCustom": true + }, + "vermieter": { + "type": "hasMany", + "relationName": "cBeteiligteKuendigungVermieter", + "foreign": "kuendigungenVermieter", + "entity": "CBeteiligte", + "audited": false, + "isCustom": true + }, + "mieter": { + "type": "hasMany", + "relationName": "cBeteiligteKuendigungMieter", + "foreign": "kuendigungenMieter", + "entity": "CBeteiligte", + "audited": false, + "isCustom": true + }, + "dokumenteKuendigung": { + "type": "hasMany", + "relationName": "cDokumenteKuendigung", + "foreign": "kuendigungDokumente", + "entity": "CDokumente", + "audited": false, + "isCustom": true + }, + "contactsKuendigung": { + "type": "hasMany", + "relationName": "cKuendigungContact", + "foreign": "cKuendigungContact", + "entity": "Contact", + "audited": false, + "isCustom": true + } + }, + "collection": { + "orderBy": "createdAt", + "order": "desc", + "textFilterFields": [ + "name" + ], + "fullTextSearch": false, + "countDisabled": false + }, + "indexes": { + "name": { + "columns": [ + "name", + "deleted" + ] + }, + "assignedUser": { + "columns": [ + "assignedUserId", + "deleted" + ] + }, + "createdAt": { + "columns": [ + "createdAt", + "deleted" + ] + }, + "kuendigungsdatum": { + "columns": [ + "kuendigungsdatum", + "deleted" + ] + } + } +} diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/CMietobjekt.json b/custom/Espo/Custom/Resources/metadata/entityDefs/CMietobjekt.json index c653ac24..4d21c5d3 100644 --- a/custom/Espo/Custom/Resources/metadata/entityDefs/CMietobjekt.json +++ b/custom/Espo/Custom/Resources/metadata/entityDefs/CMietobjekt.json @@ -157,6 +157,14 @@ "entity": "CMietinkasso", "audited": false, "isCustom": true + }, + "kuendigungen": { + "type": "hasMany", + "relationName": "cKuendigungMietobjekt", + "foreign": "mietobjekt", + "entity": "CKuendigung", + "audited": false, + "isCustom": true } }, "collection": { diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/CVmhMietverhltnis.json b/custom/Espo/Custom/Resources/metadata/entityDefs/CVmhMietverhltnis.json index 45b642d2..cbb32325 100644 --- a/custom/Espo/Custom/Resources/metadata/entityDefs/CVmhMietverhltnis.json +++ b/custom/Espo/Custom/Resources/metadata/entityDefs/CVmhMietverhltnis.json @@ -280,6 +280,14 @@ "entity": "CMietobjekt", "audited": false, "isCustom": true + }, + "kuendigungen": { + "type": "hasMany", + "relationName": "cKuendigungVmhMietverhltnis", + "foreign": "vmhMietverhltnis", + "entity": "CKuendigung", + "audited": false, + "isCustom": true } }, "collection": { diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/Contact.json b/custom/Espo/Custom/Resources/metadata/entityDefs/Contact.json index 1e8fca88..7c66e2f4 100644 --- a/custom/Espo/Custom/Resources/metadata/entityDefs/Contact.json +++ b/custom/Espo/Custom/Resources/metadata/entityDefs/Contact.json @@ -94,6 +94,14 @@ "audited": false, "isCustom": true }, + "cKuendigungContact": { + "type": "hasMany", + "relationName": "cKuendigungContact", + "foreign": "contactsKuendigung", + "entity": "CKuendigung", + "audited": false, + "isCustom": true + }, "cBankverbindungenContact": { "type": "hasMany", "relationName": "cBankverbindungContact", diff --git a/custom/Espo/Custom/Resources/metadata/layouts/CKuendigung/detail.json b/custom/Espo/Custom/Resources/metadata/layouts/CKuendigung/detail.json new file mode 100644 index 00000000..68aec1ac --- /dev/null +++ b/custom/Espo/Custom/Resources/metadata/layouts/CKuendigung/detail.json @@ -0,0 +1,109 @@ +[ + [ + { + "name": "name" + }, + { + "name": "status" + } + ], + [ + { + "name": "kuendigungsart" + }, + { + "name": "kuendigenderPartei" + } + ], + [ + { + "name": "kuendigungsdatum" + }, + { + "name": "kuendigungsfrist" + } + ], + [ + { + "name": "vmhMietverhltnis" + }, + { + "name": "mietobjekt" + } + ], + [ + { + "name": "kuendigungsgrund", + "fullWidth": true + }, + false + ], + [ + { + "name": "zustellungsdatum" + }, + { + "name": "zustellungsart" + } + ], + [ + { + "name": "rueckstandsbetrag" + }, + { + "name": "monateMietrückstand" + } + ], + [ + { + "name": "schonfristGewaehrt" + }, + { + "name": "schonfristDatum" + } + ], + [ + { + "name": "besorgnisNichtRechtzeitigerAuszug" + }, + false + ], + [ + { + "name": "description", + "fullWidth": true + }, + false + ], + [ + { + "name": "anmerkungen", + "fullWidth": true + }, + false + ], + [ + { + "name": "assignedUser" + }, + { + "name": "teams" + } + ], + [ + { + "name": "createdAt" + }, + { + "name": "modifiedAt" + } + ], + [ + { + "name": "createdBy" + }, + { + "name": "modifiedBy" + } + ] +] diff --git a/custom/Espo/Custom/Resources/metadata/layouts/CKuendigung/detailSmall.json b/custom/Espo/Custom/Resources/metadata/layouts/CKuendigung/detailSmall.json new file mode 100644 index 00000000..5827690b --- /dev/null +++ b/custom/Espo/Custom/Resources/metadata/layouts/CKuendigung/detailSmall.json @@ -0,0 +1,40 @@ +[ + [ + { + "name": "name" + }, + { + "name": "status" + } + ], + [ + { + "name": "kuendigungsart" + }, + { + "name": "kuendigenderPartei" + } + ], + [ + { + "name": "kuendigungsdatum" + }, + { + "name": "kuendigungsfrist" + } + ], + [ + { + "name": "vmhMietverhltnis" + }, + { + "name": "mietobjekt" + } + ], + [ + { + "name": "assignedUser" + }, + false + ] +] diff --git a/custom/Espo/Custom/Resources/metadata/layouts/CKuendigung/list.json b/custom/Espo/Custom/Resources/metadata/layouts/CKuendigung/list.json new file mode 100644 index 00000000..16c6586b --- /dev/null +++ b/custom/Espo/Custom/Resources/metadata/layouts/CKuendigung/list.json @@ -0,0 +1,30 @@ +[ + { + "name": "name", + "link": true + }, + { + "name": "status" + }, + { + "name": "kuendigungsart" + }, + { + "name": "kuendigungsdatum" + }, + { + "name": "kuendigungsfrist" + }, + { + "name": "kuendigenderPartei" + }, + { + "name": "vmhMietverhltnis" + }, + { + "name": "mietobjekt" + }, + { + "name": "assignedUser" + } +] diff --git a/custom/Espo/Custom/Resources/metadata/scopes/CKuendigung.json b/custom/Espo/Custom/Resources/metadata/scopes/CKuendigung.json new file mode 100644 index 00000000..5dbb02da --- /dev/null +++ b/custom/Espo/Custom/Resources/metadata/scopes/CKuendigung.json @@ -0,0 +1,11 @@ +{ + "entity": true, + "layouts": true, + "tab": true, + "acl": true, + "customizable": true, + "type": "BasePlus", + "module": "Custom", + "object": true, + "isCustom": true +} diff --git a/custom/Espo/Custom/Services/CVmhMietverhltnis.php b/custom/Espo/Custom/Services/CVmhMietverhltnis.php index b28c3081..420c0f65 100644 --- a/custom/Espo/Custom/Services/CVmhMietverhltnis.php +++ b/custom/Espo/Custom/Services/CVmhMietverhltnis.php @@ -368,4 +368,140 @@ class CVmhMietverhltnis extends \Espo\Services\Record 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; + } + + // Pre-fill dates from Mietverhältnis + if ($mietverhaeltnis->get('auszugsfrist')) { + $data->kuendigungsfrist = $mietverhaeltnis->get('auszugsfrist'); + } + + // Pre-fill Kündigungsgrund from Mietverhältnis + if ($mietverhaeltnis->get('kndigungsgrundWohnraum')) { + $data->kuendigungsgrund = $mietverhaeltnis->get('kndigungsgrundWohnraum'); + } + + // Pre-fill Besorgnis nicht rechtzeitiger Auszug + if ($mietverhaeltnis->get('besorgnisNichtRechtzeitigerAuszug')) { + $data->besorgnisNichtRechtzeitigerAuszug = $mietverhaeltnis->get('besorgnisNichtRechtzeitigerAuszug'); + } + + // 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, 'vmhMietverhltnis') + ->relate($mietverhaeltnis); + + // 7. Get and link Mietobjekt + $mietobjekt = $this->entityManager + ->getRepository('CVmhMietverhltnis') + ->getRelation($mietverhaeltnis, 'vmhMietobjekt') + ->findOne(); + + if ($mietobjekt) { + $kuendigungRepo + ->getRelation($kuendigung, 'mietobjekt') + ->relate($mietobjekt); + } + + // 8. Get Vermieter from Mietverhältnis + $vermieterBeteiligte = $this->entityManager + ->getRepository('CVmhMietverhltnis') + ->getRelation($mietverhaeltnis, 'vmhbeteiligtevermieter') + ->find(); + + foreach ($vermieterBeteiligte as $vermieter) { + // Link as Vermieter + $kuendigungRepo + ->getRelation($kuendigung, 'vermieter') + ->relate($vermieter); + } + + // 9. Get Mieter from Mietverhältnis + $mieterBeteiligte = $this->entityManager + ->getRepository('CVmhMietverhltnis') + ->getRelation($mietverhaeltnis, 'vmhbeteiligtemieter') + ->find(); + + foreach ($mieterBeteiligte as $mieter) { + // Link as Mieter + $kuendigungRepo + ->getRelation($kuendigung, 'mieter') + ->relate($mieter); + } + + // 10. Link Portal Contacts + $portalContacts = $this->entityManager + ->getRepository('CVmhMietverhltnis') + ->getRelation($mietverhaeltnis, 'contactsMietverhltnis') + ->find(); + + foreach ($portalContacts as $contact) { + $kuendigungRepo + ->getRelation($kuendigung, 'contactsKuendigung') + ->relate($contact); + } + + // 11. 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; + } + } } diff --git a/data/config.php b/data/config.php index 16f00d17..0f8fa1d1 100644 --- a/data/config.php +++ b/data/config.php @@ -69,69 +69,69 @@ return [ ] ], 4 => 'CVmhMietverhltnis', - 5 => 'CVmhRumungsklage', - 6 => 'CMietinkasso', - 7 => 'CDokumente', - 8 => (object) [ + 5 => 'CKndigung', + 6 => 'CVmhRumungsklage', + 7 => 'CMietinkasso', + 8 => 'CDokumente', + 9 => (object) [ 'type' => 'divider', 'id' => '342567', 'text' => '$CRM' ], - 9 => 'Contact', - 10 => (object) [ + 10 => 'Contact', + 11 => (object) [ 'type' => 'divider', 'text' => '$Activities', 'id' => '219419' ], - 11 => 'Email', - 12 => 'Call', - 13 => 'Task', - 14 => 'Calendar', - 15 => (object) [ + 12 => 'Email', + 13 => 'Call', + 14 => 'Task', + 15 => 'Calendar', + 16 => (object) [ 'type' => 'divider', 'id' => '655187', 'text' => '$Support' ], - 16 => 'Case', - 17 => 'KnowledgeBaseArticle', - 18 => (object) [ + 17 => 'Case', + 18 => 'KnowledgeBaseArticle', + 19 => (object) [ 'type' => 'divider', 'text' => NULL, 'id' => '137994' ], - 19 => '_delimiter_', - 20 => (object) [ + 20 => '_delimiter_', + 21 => (object) [ 'type' => 'divider', 'text' => '$Marketing', 'id' => '463280' ], - 21 => 'Campaign', - 22 => 'TargetList', - 23 => (object) [ + 22 => 'Campaign', + 23 => 'TargetList', + 24 => (object) [ 'type' => 'divider', 'text' => '$Business', 'id' => '518202' ], - 24 => (object) [ + 25 => (object) [ 'type' => 'divider', 'text' => '$Organization', 'id' => '566592' ], - 25 => 'User', - 26 => (object) [ + 26 => 'User', + 27 => (object) [ 'type' => 'divider', 'text' => NULL, 'id' => '898671' ], - 27 => 'Team', - 28 => 'WorkingTimeCalendar', - 29 => 'EmailTemplate', - 30 => 'Template', - 31 => 'Import', - 32 => 'GlobalStream', - 33 => 'Report', - 34 => 'CCallQueues', - 35 => 'CKndigung' + 28 => 'Team', + 29 => 'WorkingTimeCalendar', + 30 => 'EmailTemplate', + 31 => 'Template', + 32 => 'Import', + 33 => 'GlobalStream', + 34 => 'Report', + 35 => 'CCallQueues' ], 'quickCreateList' => [ 0 => 'Account', @@ -360,8 +360,8 @@ return [ 0 => 'youtube.com', 1 => 'google.com' ], - 'cacheTimestamp' => 1769254421, - 'microtime' => 1769254421.498616, + 'cacheTimestamp' => 1769255131, + 'microtime' => 1769255131.563756, 'siteUrl' => 'https://crm.bitbylaw.com', 'fullTextSearchMinLength' => 4, 'appTimestamp' => 1768843902,