From 30326da8c6fe66188a84762d7f156f72875bc591 Mon Sep 17 00:00:00 2001 From: bsiggel Date: Sun, 25 Jan 2026 10:06:02 +0100 Subject: [PATCH] =?UTF-8?q?Add=20termination=20(K=C3=BCndigung)=20function?= =?UTF-8?q?ality=20and=20related=20translations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Implemented the ability to initiate terminations from Mietverhältnisse. - Added new fields and options for terminations in both German and English language files. - Updated metadata definitions to include relationships for terminations with Mietobjekte and Beteiligte. - Enhanced the service layer to handle termination creation, including linking relevant entities and copying documents. - Updated configuration timestamps for deployment. --- .../Custom/Controllers/CVmhMietverhltnis.php | 18 ++ .../Resources/i18n/de_DE/CBeteiligte.json | 4 + .../Resources/i18n/de_DE/CDokumente.json | 7 +- .../Resources/i18n/de_DE/CKndigung.json | 89 +++++- .../Resources/i18n/de_DE/CMietobjekt.json | 1 + .../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 | 7 +- .../Resources/i18n/en_US/CKndigung.json | 86 +++++- .../Resources/i18n/en_US/CMietobjekt.json | 1 + .../i18n/en_US/CVmhMietverhltnis.json | 10 +- .../Custom/Resources/i18n/en_US/Contact.json | 5 +- .../metadata/clientDefs/CKndigung.json | 28 +- .../clientDefs/CVmhMietverhltnis.json | 10 + .../metadata/entityDefs/CBeteiligte.json | 16 + .../metadata/entityDefs/CDokumente.json | 8 + .../metadata/entityDefs/CKndigung.json | 273 +++++++++++++++++- .../metadata/entityDefs/CMietobjekt.json | 8 + .../entityDefs/CVmhMietverhltnis.json | 8 + .../metadata/entityDefs/Contact.json | 8 + .../Custom/Services/CVmhMietverhltnis.php | 181 ++++++++++++ data/config.php | 4 +- 23 files changed, 771 insertions(+), 18 deletions(-) diff --git a/custom/Espo/Custom/Controllers/CVmhMietverhltnis.php b/custom/Espo/Custom/Controllers/CVmhMietverhltnis.php index 78b1a241..36adbe88 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 (Kündigung) 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..ed853e77 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)", + "kndigungenKuendiger": "Kündigungen (Kündigende)", + "kndigungenGekuendigte": "Kündigungen (Gekündigte)", "adressens": "Adressen", "calls1": "Anrufe", "contactsBeteiligte": "Freigegebene Nutzer", @@ -33,6 +35,8 @@ "vmhRumungsklagesBeklagte": "Beklagte", "mietinkassosKlaeger": "Mietinkasso (Kläger)", "mietinkassosBeklagte": "Mietinkasso (Beklagte)", + "kndigungenKuendiger": "Kündigungen (Kündigende)", + "kndigungenGekuendigte": "Kündigungen (Gekündigte)", "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..3650c189 100644 --- a/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json +++ b/custom/Espo/Custom/Resources/i18n/de_DE/CDokumente.json @@ -13,7 +13,9 @@ "vmhErstgespraechsdokumente": "Erstgespräche", "vmhRumungsklagesdokumente": "Räumungsklagen", "beteiligte2dokumente": "Beteiligte", - "mietobjekt2dokumente": "Mietobjekte" + "mietobjekt2dokumente": "Mietobjekte", + "mietinkassosdokumente": "Mietinkasso", + "kndigungensdokumente": "Kündigungen" }, "links": { "contactsvmhdokumente": "Freigegebene Nutzer", @@ -22,7 +24,8 @@ "vmhRumungsklagesdokumente": "Räumungsklagen", "beteiligte2dokumente": "Beteiligte", "mietobjekt2dokumente": "Mietobjekte", - "mietinkassosdokumente": "Mietinkasso" + "mietinkassosdokumente": "Mietinkasso", + "kndigungensdokumente": "Kündigungen" }, "labels": { "Create CDokumente": "Dokument erstellen" diff --git a/custom/Espo/Custom/Resources/i18n/de_DE/CKndigung.json b/custom/Espo/Custom/Resources/i18n/de_DE/CKndigung.json index 01a25372..adca8af6 100644 --- a/custom/Espo/Custom/Resources/i18n/de_DE/CKndigung.json +++ b/custom/Espo/Custom/Resources/i18n/de_DE/CKndigung.json @@ -1,9 +1,94 @@ { "links": { + "meetings": "Termine", "calls": "Anrufe", - "tasks": "Aufgaben" + "tasks": "Aufgaben", + "collaborators": "Mitarbeiter", + "vmhMietverhltnises": "Mietverhältnisse", + "mietobjekte": "Mietobjekte", + "kuendiger": "Kündigende (Vermieter)", + "gekuendigte": "Gekündigte (Mieter)", + "dokumenteskuendigung": "Dokumente", + "contactsKuendigung": "Portal-Freigaben" }, "labels": { - "Create CKndigung": "Kündigung erstellen" + "Create CKndigung": "Kündigung erstellen", + "CKndigung": "Kündigung" + }, + "fields": { + "name": "Name", + "description": "Beschreibung", + "assignedUser": "Zugewiesen", + "teams": "Teams", + "createdAt": "Erstellt am", + "modifiedAt": "Geändert am", + "createdBy": "Erstellt von", + "modifiedBy": "Geändert von", + "freigeschalteteNutzer": "Freigeschaltete Nutzer", + "collaborators": "Mitarbeiter", + "advowareAktenzeichen": "Advoware Aktenzeichen", + "betnr": "Betreuernummer", + "advowareLastSync": "Letzter Sync", + "syncStatus": "Sync Status", + "kuendigungsart": "Kündigungsart", + "kuendigungsgrund": "Kündigungsgrund", + "kuendigungsgrundDetails": "Kündigungsgrund Details", + "kuendigungsdatum": "Kündigungsdatum", + "zustelldatum": "Zustelldatum", + "kuendigungsfrist": "Kündigungsfrist", + "beendigungstermin": "Beendigungstermin", + "status": "Status", + "zustellart": "Zustellart", + "reaktionMieter": "Reaktion Mieter", + "notizen": "Notizen", + "rueckstandMiete": "Rückstand Miete", + "rueckstandNebenkosten": "Rückstand Nebenkosten", + "sonstigeForderungen": "Sonstige Forderungen", + "aussergerichtlicheGebuehren13": "Außergerichtliche Gebühren (1,3)" + }, + "options": { + "kuendigungsart": { + "Ordentlich": "Ordentlich", + "Ausserordentlich": "Außerordentlich", + "Fristlos": "Fristlos", + "AufgabeerklärungMieter": "Aufgabeerklärung Mieter" + }, + "kuendigungsgrund": { + "Zahlungsverzug": "Zahlungsverzug", + "Pflichtverletzung": "Pflichtverletzung", + "Eigenbedarf": "Eigenbedarf", + "Verwertung": "Verwertung", + "VerhaltensbedingteLaermruhestoerung": "Verhaltensbedingte Lärm-/Ruhestörung", + "BeschaedigungSubstanz": "Beschädigung der Substanz", + "UnerlaubteUntervermietung": "Unerlaubte Untervermietung", + "StoerendeGeschaeftsfuehrung": "Störende Geschäftsführung", + "Sonstiges": "Sonstiges" + }, + "status": { + "Entwurf": "Entwurf", + "Versendet": "Versendet", + "Zugestellt": "Zugestellt", + "Akzeptiert": "Akzeptiert", + "Bestritten": "Bestritten", + "Abgewickelt": "Abgewickelt", + "Zurückgezogen": "Zurückgezogen" + }, + "zustellart": { + "Einschreiben": "Einschreiben", + "Persoenlich": "Persönlich", + "Gerichtsvollzieher": "Gerichtsvollzieher", + "Oeffentlich": "Öffentlich", + "Sonstiges": "Sonstiges" + }, + "syncStatus": { + "clean": "Synchronisiert", + "unclean": "Änderungen ausstehend", + "failed": "Fehler" + } + }, + "tooltips": { + "advowareAktenzeichen": "Aktenzeichen aus Advoware für die Synchronisation", + "betnr": "Betreuernummer aus Advoware", + "syncStatus": "Status der Synchronisation mit Advoware" } } \ No newline at end of file diff --git a/custom/Espo/Custom/Resources/i18n/de_DE/CMietobjekt.json b/custom/Espo/Custom/Resources/i18n/de_DE/CMietobjekt.json index 9638c128..b9d58133 100644 --- a/custom/Espo/Custom/Resources/i18n/de_DE/CMietobjekt.json +++ b/custom/Espo/Custom/Resources/i18n/de_DE/CMietobjekt.json @@ -14,6 +14,7 @@ "contact2mietobjekt": "Kontakte", "vmhRumungsklages": "Räumungsklagen", "mietinkassos": "Mietinkasso", + "kndigungen": "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..b4eccee8 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", + "kndigungen": "Kündigungen", "vmhbeteiligtevermieter": "Vermieter", "vmhbeteiligtemieter": "Mieter", "contactsMietverhltnis": "Freigegebene Nutzer", @@ -33,6 +34,7 @@ "tasks": "Aufgaben", "vmhRumungsklages": "Räumungsklagen", "mietinkassos": "Mietinkasso", + "kndigungen": "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 aus diesem 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..f0e22e86 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", + "cKuendigungContact": "Kündigungen", "cBankverbindungenContact": "Bankverbindungen" }, "links": { @@ -29,6 +31,7 @@ "cAdressenContact": "Adressen", "cVmhRumungsklageContact": "Räumungsklagen (Portal)", "cMietinkassoContact": "Mietinkasso", + "cKuendigungContact": "Kündigungen", "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..857943bd 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)", + "kndigungenKuendiger": "Terminations (Terminating Party)", + "kndigungenGekuendigte": "Terminations (Terminated Party)", "contactsBeteiligte": "Portal Users", "dokumentesBeteiligte": "Documents" }, @@ -27,6 +29,8 @@ "vmhRumungsklagesKlaeger": "Plaintiff", "mietinkassosKlaeger": "Rent Collection (Plaintiff)", "mietinkassosBeklagte": "Rent Collection (Defendant)", + "kndigungenKuendiger": "Terminations (Terminating Party)", + "kndigungenGekuendigte": "Terminations (Terminated Party)", "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..db20161c 100644 --- a/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json +++ b/custom/Espo/Custom/Resources/i18n/en_US/CDokumente.json @@ -10,7 +10,9 @@ "md5sum": "MD5 Checksum", "sha256": "SHA256 Checksum", "beteiligte2dokumente": "Parties", - "mietobjekt2dokumente": "Properties" + "mietobjekt2dokumente": "Properties", + "mietinkassosdokumente": "Rent Collection", + "kndigungensdokumente": "Terminations" }, "links": { "contactsvmhdokumente": "Portal Users", @@ -19,7 +21,8 @@ "vmhRumungsklagesdokumente": "Eviction Lawsuits", "beteiligte2dokumente": "Parties", "mietobjekt2dokumente": "Properties", - "mietinkassosdokumente": "Rent Collection" + "mietinkassosdokumente": "Rent Collection", + "kndigungensdokumente": "Terminations" }, "labels": { "Create CDokumente": "Create Dokument" diff --git a/custom/Espo/Custom/Resources/i18n/en_US/CKndigung.json b/custom/Espo/Custom/Resources/i18n/en_US/CKndigung.json index 9f9079f3..f34c66b9 100644 --- a/custom/Espo/Custom/Resources/i18n/en_US/CKndigung.json +++ b/custom/Espo/Custom/Resources/i18n/en_US/CKndigung.json @@ -1,12 +1,94 @@ { "fields": { + "name": "Name", + "description": "Description", + "assignedUser": "Assigned User", + "teams": "Teams", + "createdAt": "Created At", + "modifiedAt": "Modified At", + "createdBy": "Created By", + "modifiedBy": "Modified By", + "freigeschalteteNutzer": "Authorized Users", + "collaborators": "Collaborators", + "advowareAktenzeichen": "Advoware File Number", + "betnr": "Case Number", + "advowareLastSync": "Last Sync", + "syncStatus": "Sync Status", + "kuendigungsart": "Termination Type", + "kuendigungsgrund": "Termination Reason", + "kuendigungsgrundDetails": "Termination Reason Details", + "kuendigungsdatum": "Termination Date", + "zustelldatum": "Delivery Date", + "kuendigungsfrist": "Notice Period", + "beendigungstermin": "End Date", + "status": "Status", + "zustellart": "Delivery Method", + "reaktionMieter": "Tenant Response", + "notizen": "Notes", + "rueckstandMiete": "Rent Arrears", + "rueckstandNebenkosten": "Utility Arrears", + "sonstigeForderungen": "Other Claims", + "aussergerichtlicheGebuehren13": "Extrajudicial Fees (1.3)" }, "links": { "meetings": "Meetings", "calls": "Calls", - "tasks": "Tasks" + "tasks": "Tasks", + "collaborators": "Collaborators", + "vmhMietverhltnises": "Tenancies", + "mietobjekte": "Properties", + "kuendiger": "Terminating Party (Landlord)", + "gekuendigte": "Terminated Party (Tenant)", + "dokumenteskuendigung": "Documents", + "contactsKuendigung": "Portal Access" }, "labels": { - "Create CKndigung": "Create Kündigung" + "Create CKndigung": "Create Termination", + "CKndigung": "Termination" + }, + "options": { + "kuendigungsart": { + "Ordentlich": "Regular", + "Ausserordentlich": "Extraordinary", + "Fristlos": "Immediate", + "AufgabeerklärungMieter": "Tenant Surrender" + }, + "kuendigungsgrund": { + "Zahlungsverzug": "Payment Default", + "Pflichtverletzung": "Breach of Contract", + "Eigenbedarf": "Owner's Need", + "Verwertung": "Exploitation", + "VerhaltensbedingteLaermruhestoerung": "Behavioral - Noise/Disturbance", + "BeschaedigungSubstanz": "Property Damage", + "UnerlaubteUntervermietung": "Unauthorized Subletting", + "StoerendeGeschaeftsfuehrung": "Disruptive Business Operations", + "Sonstiges": "Other" + }, + "status": { + "Entwurf": "Draft", + "Versendet": "Sent", + "Zugestellt": "Delivered", + "Akzeptiert": "Accepted", + "Bestritten": "Disputed", + "Abgewickelt": "Settled", + "Zurückgezogen": "Withdrawn" + }, + "zustellart": { + "Einschreiben": "Registered Mail", + "Persoenlich": "Personal Delivery", + "Gerichtsvollzieher": "Bailiff", + "Oeffentlich": "Public Notice", + "Sonstiges": "Other" + }, + "syncStatus": { + "clean": "Synchronized", + "unclean": "Changes Pending", + "failed": "Failed" + } + }, + "tooltips": { + "advowareAktenzeichen": "File number from Advoware for synchronization", + "betnr": "Case number from Advoware", + "syncStatus": "Synchronization status with Advoware" } } diff --git a/custom/Espo/Custom/Resources/i18n/en_US/CMietobjekt.json b/custom/Espo/Custom/Resources/i18n/en_US/CMietobjekt.json index fc630b1c..33210f1a 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", + "kndigungen": "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..dffabb6e 100644 --- a/custom/Espo/Custom/Resources/i18n/en_US/CVmhMietverhltnis.json +++ b/custom/Espo/Custom/Resources/i18n/en_US/CVmhMietverhltnis.json @@ -3,6 +3,7 @@ "status": "Status", "vmhRumungsklages": "Eviction Lawsuits", "mietinkassos": "Rent Collection", + "kndigungen": "Terminations", "nutzungsart": "Type of Use", "kndigungsgrundWohnraum": "Reason for Termination", "auszugsfrist": "Move-out Deadline", @@ -36,6 +37,7 @@ "tasks": "Tasks", "vmhRumungsklages": "Eviction Lawsuits", "mietinkassos": "Rent Collection", + "kndigungen": "Terminations", "vmhbeteiligtevermieter": "Landlords", "vmhbeteiligtemieter": "Tenants", "contactsMietverhltnis": "Portal Users", @@ -47,7 +49,8 @@ "labels": { "Create CVmhMietverhltnis": "Create Mietverhältnis", "Initiate Eviction": "Initiate Eviction Lawsuit", - "Initiate Rent Collection": "Initiate Rent Collection" + "Initiate Rent Collection": "Initiate Rent Collection", + "Initiate Termination": "Create Termination" }, "messages": { "confirmEviction": "Do you really want to initiate an eviction lawsuit from this tenancy?", @@ -55,7 +58,10 @@ "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" + "rentCollectionError": "Error creating rent collection", + "confirmTermination": "Do you really want to create a termination notice from this tenancy?", + "terminationCreated": "Termination notice has been created successfully", + "terminationError": "Error creating termination notice" }, "options": { "status": { diff --git a/custom/Espo/Custom/Resources/i18n/en_US/Contact.json b/custom/Espo/Custom/Resources/i18n/en_US/Contact.json index f4ac5932..83229c6f 100644 --- a/custom/Espo/Custom/Resources/i18n/en_US/Contact.json +++ b/custom/Espo/Custom/Resources/i18n/en_US/Contact.json @@ -8,7 +8,9 @@ "cVmhVermietersKontaktpersonen": "Vermieter", "cVmhMietverhltnisesContact": "Mietverhältnisse", "cDokumentesvmhcontact": "Dokumente", - "cVmhmietobjekt2contact": "Mietobjekts" + "cVmhmietobjekt2contact": "Mietobjekts", + "cMietinkassoContact": "Rent Collection", + "cKuendigungContact": "Terminations" }, "links": { "cVmhRumungsklages": "Räumungsklagen", @@ -23,6 +25,7 @@ "cAdressenContact": "Addresses", "cVmhRumungsklageContact": "Eviction Lawsuits (Portal)", "cMietinkassoContact": "Rent Collection", + "cKuendigungContact": "Terminations", "cBankverbindungenContact": "Bank Accounts" }, "options": { diff --git a/custom/Espo/Custom/Resources/metadata/clientDefs/CKndigung.json b/custom/Espo/Custom/Resources/metadata/clientDefs/CKndigung.json index 0115fec8..4a1513ab 100644 --- a/custom/Espo/Custom/Resources/metadata/clientDefs/CKndigung.json +++ b/custom/Espo/Custom/Resources/metadata/clientDefs/CKndigung.json @@ -33,5 +33,31 @@ } ] }, - "iconClass": "fas fa-circle-stop" + "iconClass": "fas fa-file-contract", + "relationshipPanels": { + "vmhMietverhltnises": { + "layout": null, + "selectPrimaryFilterName": null + }, + "mietobjekte": { + "layout": null, + "selectPrimaryFilterName": null + }, + "kuendiger": { + "layout": null, + "selectPrimaryFilterName": null + }, + "gekuendigte": { + "layout": null, + "selectPrimaryFilterName": null + }, + "dokumenteskuendigung": { + "layout": null, + "selectPrimaryFilterName": null + }, + "contactsKuendigung": { + "layout": null, + "selectPrimaryFilterName": "portalUsers" + } + } } \ No newline at end of file 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..78120690 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 }, + "kndigungenKuendiger": { + "type": "hasMany", + "relationName": "cBeteiligteKuendigungKuendiger", + "foreign": "kuendiger", + "entity": "CKndigung", + "audited": false, + "isCustom": true + }, + "kndigungenGekuendigte": { + "type": "hasMany", + "relationName": "cBeteiligteKuendigungGekuendigte", + "foreign": "gekuendigte", + "entity": "CKndigung", + "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..8517b980 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 }, + "kndigungensdokumente": { + "type": "hasMany", + "relationName": "cDokumenteKuendigung", + "foreign": "dokumenteskuendigung", + "entity": "CKndigung", + "audited": false, + "isCustom": true + }, "beteiligte2dokumente": { "type": "hasMany", "relationName": "cBeteiligteDokumente", diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/CKndigung.json b/custom/Espo/Custom/Resources/metadata/entityDefs/CKndigung.json index d521dd6a..c95347c5 100644 --- a/custom/Espo/Custom/Resources/metadata/entityDefs/CKndigung.json +++ b/custom/Espo/Custom/Resources/metadata/entityDefs/CKndigung.json @@ -34,6 +34,176 @@ "teams": { "type": "linkMultiple", "view": "views/fields/teams" + }, + "freigeschalteteNutzer": { + "type": "link" + }, + "collaborators": { + "type": "linkMultiple", + "view": "views/fields/collaborators", + "maxCount": 30, + "fieldManagerParamList": [ + "readOnly", + "readOnlyAfterCreate", + "audited", + "autocompleteOnEmpty", + "maxCount", + "inlineEditDisabled", + "tooltipText" + ] + }, + "advowareAktenzeichen": { + "type": "varchar", + "required": false, + "maxLength": 100, + "tooltip": true, + "isCustom": true, + "copyToClipboard": true + }, + "betnr": { + "type": "int", + "required": false, + "tooltip": true, + "isCustom": true + }, + "advowareLastSync": { + "type": "datetime", + "required": false, + "readOnly": true, + "tooltip": true, + "isCustom": true + }, + "syncStatus": { + "type": "enum", + "required": false, + "options": [ + "clean", + "unclean", + "failed" + ], + "style": { + "clean": "success", + "unclean": "warning", + "failed": "danger" + }, + "default": "clean", + "tooltip": true, + "isCustom": true + }, + "kuendigungsart": { + "type": "enum", + "required": false, + "options": [ + "Ordentlich", + "Ausserordentlich", + "Fristlos", + "AufgabeerklärungMieter" + ], + "default": "Ordentlich", + "isCustom": true + }, + "kuendigungsgrund": { + "type": "enum", + "required": false, + "options": [ + "Zahlungsverzug", + "Pflichtverletzung", + "Eigenbedarf", + "Verwertung", + "VerhaltensbedingteLaermruhestoerung", + "BeschaedigungSubstanz", + "UnerlaubteUntervermietung", + "StoerendeGeschaeftsfuehrung", + "Sonstiges" + ], + "isCustom": true + }, + "kuendigungsgrundDetails": { + "type": "text", + "required": false, + "isCustom": true + }, + "kuendigungsdatum": { + "type": "date", + "required": false, + "isCustom": true + }, + "zustelldatum": { + "type": "date", + "required": false, + "isCustom": true + }, + "kuendigungsfrist": { + "type": "varchar", + "required": false, + "maxLength": 50, + "isCustom": true + }, + "beendigungstermin": { + "type": "date", + "required": false, + "isCustom": true + }, + "status": { + "type": "enum", + "required": false, + "options": [ + "Entwurf", + "Versendet", + "Zugestellt", + "Akzeptiert", + "Bestritten", + "Abgewickelt", + "Zurückgezogen" + ], + "default": "Entwurf", + "isCustom": true + }, + "zustellart": { + "type": "enum", + "required": false, + "options": [ + "Einschreiben", + "Persoenlich", + "Gerichtsvollzieher", + "Oeffentlich", + "Sonstiges" + ], + "isCustom": true + }, + "reaktionMieter": { + "type": "text", + "required": false, + "isCustom": true + }, + "notizen": { + "type": "text", + "required": false, + "isCustom": true + }, + "rueckstandMiete": { + "type": "currency", + "required": false, + "default": 0, + "isCustom": true + }, + "rueckstandNebenkosten": { + "type": "currency", + "required": false, + "default": 0, + "isCustom": true + }, + "sonstigeForderungen": { + "type": "currency", + "required": false, + "default": 0, + "isCustom": true + }, + "aussergerichtlicheGebuehren13": { + "type": "currency", + "required": false, + "default": 0, + "isCustom": true } }, "links": { @@ -75,11 +245,77 @@ "entity": "Email", "foreign": "parent", "layoutRelationshipsDisabled": true + }, + "vmhMietverhltnises": { + "type": "hasMany", + "relationName": "cKuendigungVmhMietverhltnis", + "foreign": "kndigungen", + "entity": "CVmhMietverhltnis", + "audited": false, + "isCustom": true + }, + "mietobjekte": { + "type": "hasMany", + "relationName": "cMietobjektKuendigung", + "foreign": "kndigungen", + "entity": "CMietobjekt", + "audited": false, + "isCustom": true + }, + "freigeschalteteNutzer": { + "type": "belongsTo", + "foreign": "cKndigungen", + "entity": "Contact", + "audited": false, + "isCustom": true + }, + "collaborators": { + "type": "hasMany", + "entity": "User", + "relationName": "entityCollaborator", + "layoutRelationshipsDisabled": true + }, + "dokumenteskuendigung": { + "type": "hasMany", + "relationName": "cDokumenteKuendigung", + "foreign": "kndigungensdokumente", + "entity": "CDokumente", + "audited": false, + "isCustom": true + }, + "contactsKuendigung": { + "type": "hasMany", + "relationName": "cKuendigungContact", + "foreign": "cKuendigungContact", + "entity": "Contact", + "audited": false, + "isCustom": true + }, + "kuendiger": { + "type": "hasMany", + "relationName": "cBeteiligteKuendigungKuendiger", + "foreign": "kndigungenKuendiger", + "entity": "CBeteiligte", + "audited": false, + "isCustom": true + }, + "gekuendigte": { + "type": "hasMany", + "relationName": "cBeteiligteKuendigungGekuendigte", + "foreign": "kndigungenGekuendigte", + "entity": "CBeteiligte", + "audited": false, + "isCustom": true } }, "collection": { "orderBy": "createdAt", - "order": "desc" + "order": "desc", + "textFilterFields": [ + "name" + ], + "fullTextSearch": false, + "countDisabled": false }, "indexes": { "name": { @@ -105,6 +341,39 @@ "createdAt", "id" ] + }, + "betnr": { + "columns": [ + "betnr" + ] + }, + "advowareAktenzeichen": { + "columns": [ + "advowareAktenzeichen" + ] + }, + "status": { + "columns": [ + "status", + "deleted" + ] + }, + "kuendigungsdatum": { + "columns": [ + "kuendigungsdatum" + ] + }, + "beendigungstermin": { + "columns": [ + "beendigungstermin" + ] + }, + "syncStatus": { + "columns": [ + "syncStatus", + "deleted" + ] } - } + }, + "optimisticConcurrencyControl": false } \ No newline at end of file diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/CMietobjekt.json b/custom/Espo/Custom/Resources/metadata/entityDefs/CMietobjekt.json index c653ac24..b54e7cd8 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 + }, + "kndigungen": { + "type": "hasMany", + "relationName": "cMietobjektKuendigung", + "foreign": "mietobjekte", + "entity": "CKndigung", + "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..e6ba3874 100644 --- a/custom/Espo/Custom/Resources/metadata/entityDefs/CVmhMietverhltnis.json +++ b/custom/Espo/Custom/Resources/metadata/entityDefs/CVmhMietverhltnis.json @@ -234,6 +234,14 @@ "audited": false, "isCustom": true }, + "kndigungen": { + "type": "hasMany", + "relationName": "cKuendigungVmhMietverhltnis", + "foreign": "vmhMietverhltnises", + "entity": "CKndigung", + "audited": false, + "isCustom": true + }, "vmhbeteiligtevermieter": { "type": "hasMany", "relationName": "cBeteiligteVmhMietverhltnis", diff --git a/custom/Espo/Custom/Resources/metadata/entityDefs/Contact.json b/custom/Espo/Custom/Resources/metadata/entityDefs/Contact.json index 1e8fca88..a1f5a00d 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": "CKndigung", + "audited": false, + "isCustom": true + }, "cBankverbindungenContact": { "type": "hasMany", "relationName": "cBankverbindungContact", diff --git a/custom/Espo/Custom/Services/CVmhMietverhltnis.php b/custom/Espo/Custom/Services/CVmhMietverhltnis.php index b28c3081..e23fcc0b 100644 --- a/custom/Espo/Custom/Services/CVmhMietverhltnis.php +++ b/custom/Espo/Custom/Services/CVmhMietverhltnis.php @@ -368,4 +368,185 @@ 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('CKndigung', '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('CKndigung', (array)$data); + + if (!$kuendigung) { + throw new \RuntimeException('Failed to create Kündigung'); + } + + $kuendigungRepo = $this->entityManager->getRepository('CKndigung'); + + // 6. Link Mietverhältnis to Kündigung + $kuendigungRepo + ->getRelation($kuendigung, 'vmhMietverhltnises') + ->relate($mietverhaeltnis); + + // 7. Get and link Mietobjekt + $mietobjekt = $this->entityManager + ->getRepository('CVmhMietverhltnis') + ->getRelation($mietverhaeltnis, 'vmhMietobjekt') + ->findOne(); + + if ($mietobjekt) { + $kuendigungRepo + ->getRelation($kuendigung, 'mietobjekte') + ->relate($mietobjekt); + } + + // 8. Get Vermieter (Kündigende) from Mietverhältnis + $vermieterBeteiligte = $this->entityManager + ->getRepository('CVmhMietverhltnis') + ->getRelation($mietverhaeltnis, 'vmhbeteiligtevermieter') + ->find(); + + foreach ($vermieterBeteiligte as $vermieter) { + // Link as Kündigende + $kuendigungRepo + ->getRelation($kuendigung, 'kuendiger') + ->relate($vermieter); + } + + // 9. Get Mieter (Gekündigte) from Mietverhältnis + $mieterBeteiligte = $this->entityManager + ->getRepository('CVmhMietverhltnis') + ->getRelation($mietverhaeltnis, 'vmhbeteiligtemieter') + ->find(); + + foreach ($mieterBeteiligte as $mieter) { + // Link as Gekündigte + $kuendigungRepo + ->getRelation($kuendigung, 'gekuendigte') + ->relate($mieter); + } + + // 9b. Get Sonstige Bewohner (auch Gekündigte) from Mietverhältnis + $sonstigeBewohner = $this->entityManager + ->getRepository('CVmhMietverhltnis') + ->getRelation($mietverhaeltnis, 'sonstigebesitzervmhmietverhltnis') + ->find(); + + foreach ($sonstigeBewohner as $bewohner) { + // Link as Gekündigte + $kuendigungRepo + ->getRelation($kuendigung, 'gekuendigte') + ->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) { + $kuendigungRepo + ->getRelation($kuendigung, 'dokumenteskuendigung') + ->relate($dokument); + } + + // 10b. Dokumente vom Mietobjekt + if ($mietobjekt) { + $dokumenteMO = $this->entityManager + ->getRepository('CMietobjekt') + ->getRelation($mietobjekt, 'dokumentesMietobjekt') + ->find(); + + foreach ($dokumenteMO as $dokument) { + $kuendigungRepo + ->getRelation($kuendigung, 'dokumenteskuendigung') + ->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) { + $kuendigungRepo + ->getRelation($kuendigung, 'dokumenteskuendigung') + ->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) { + $kuendigungRepo + ->getRelation($kuendigung, 'contactsKuendigung') + ->relate($contact); + } + + // 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; + } + } } diff --git a/data/config.php b/data/config.php index b5e1d35a..d325c9d3 100644 --- a/data/config.php +++ b/data/config.php @@ -360,8 +360,8 @@ return [ 0 => 'youtube.com', 1 => 'google.com' ], - 'cacheTimestamp' => 1769256001, - 'microtime' => 1769256001.008295, + 'cacheTimestamp' => 1769331937, + 'microtime' => 1769331937.84435, 'siteUrl' => 'https://crm.bitbylaw.com', 'fullTextSearchMinLength' => 4, 'appTimestamp' => 1768843902,