From a032e2c2e97864940907be7c90484264fd0a851a Mon Sep 17 00:00:00 2001 From: Kai Lawrence Date: Wed, 6 Aug 2025 17:54:44 +0000 Subject: [PATCH 1/3] Fix: Don't split Personenzeitanteile if Personenzahl has not changed on Version --- .../PersonenZeitanteil.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Deeplex.Saverwalter.BetriebskostenabrechnungService/PersonenZeitanteil.cs b/Deeplex.Saverwalter.BetriebskostenabrechnungService/PersonenZeitanteil.cs index 84fecb5b..130e9a4b 100644 --- a/Deeplex.Saverwalter.BetriebskostenabrechnungService/PersonenZeitanteil.cs +++ b/Deeplex.Saverwalter.BetriebskostenabrechnungService/PersonenZeitanteil.cs @@ -94,10 +94,19 @@ public static List GetPersonenZeitanteile( private static List getTimestampsOfPersonenAnzahlChanges(List vertraege, Zeitraum zeitraum) { + var personenzahl = 0; var begins = vertraege .SelectMany(e => e.Versionen) + .OrderBy(e => e.Beginn) + .Where(e => + { + var filter = e.Personenzahl != personenzahl; + personenzahl = e.Personenzahl; + return filter; + }) .Select(e => e.Beginn) .ToList(); + var ends = vertraege .Where(e => e.Ende != null) .Select(e => e.Ende is DateOnly d ? d.AddDays(1) : new DateOnly()) From d69e613324b35080cca21154db2e7757f3f368c2 Mon Sep 17 00:00:00 2001 From: Kai Lawrence Date: Wed, 6 Aug 2025 22:40:32 +0000 Subject: [PATCH 2/3] Feat: Add Abrechnungsresultate --- .devcontainer/devcontainer.json | 28 +- ...806203327_Abrechnungsresultate.Designer.cs | 1683 ++++++++++++++++ .../20250806203327_Abrechnungsresultate.cs | 51 + ..._AbrechnungsresultatAbgesendet.Designer.cs | 1687 +++++++++++++++++ ...806210125_AbrechnungsresultatAbgesendet.cs | 29 + .../Npgsql/SaverwalterContextModelSnapshot.cs | 62 + .../SaverWalterContext.cs | 3 +- .../model/Abrechnungsresultat.cs | 40 + Deeplex.Saverwalter.Model/model/Vertrag.cs | 13 +- Deeplex.Saverwalter.PrintService/Utils.cs | 4 +- .../Betriebskostenabrechnung.Tests.cs | 14 +- .../BetriebskostenabrechnungController.cs | 28 +- .../Controllers/VertragController.cs | 4 + .../Services/Betriebskostenabrechnung.cs | 49 +- .../Services/DbServices/UmlageDbService.cs | 4 +- .../abrechnung/WalterAbrechnung.svelte | 5 +- .../WalterAltesAbrechnungsresultat.svelte | 91 + .../components/details/WalterUmlage.svelte | 4 +- .../elements/WalterDataTable.svelte | 11 +- .../svelte/src/components/index.ts | 4 +- .../lists/WalterAbrechnungsresultate.svelte | 47 + .../components/subdetails/WalterAnhaenge.ts | 4 +- .../src/lib/WalterBetriebskostenrechnung.ts | 7 +- .../svelte/src/lib/WalterVertrag.ts | 5 + .../src/routes/(app)/abrechnung/+page.svelte | 68 +- .../routes/(app)/vertraege/[id]/+page.svelte | 6 + .../src/routes/(app)/vertraege/[id]/utils.ts | 3 +- .../WalterBetriebskostenabrechnung.type.ts | 13 +- .../svelte/src/types/index.ts | 5 +- 29 files changed, 3888 insertions(+), 84 deletions(-) create mode 100644 Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806203327_Abrechnungsresultate.Designer.cs create mode 100644 Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806203327_Abrechnungsresultate.cs create mode 100644 Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806210125_AbrechnungsresultatAbgesendet.Designer.cs create mode 100644 Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806210125_AbrechnungsresultatAbgesendet.cs create mode 100644 Deeplex.Saverwalter.Model/model/Abrechnungsresultat.cs create mode 100644 Deeplex.Saverwalter.WebAPI/svelte/src/components/abrechnung/WalterAltesAbrechnungsresultat.svelte create mode 100644 Deeplex.Saverwalter.WebAPI/svelte/src/components/lists/WalterAbrechnungsresultate.svelte diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0094bcc5..ffcca874 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,29 +1,29 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/dotnet-postgres { - "name": "C# (.NET) and PostgreSQL", - "dockerComposeFile": "docker-compose.yml", - "service": "app", + "name": "C# (.NET) and PostgreSQL", + "dockerComposeFile": "docker-compose.yml", + "service": "app", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", "features": { "ghcr.io/devcontainers/features/node:1": { "version": "lts" } }, - "postCreateCommand": "dotnet restore", - + "postCreateCommand": "dotnet tool install --global dotnet ef && dotnet restore", "customizations": { "vscode": { - "extensions": ["svelte.svelte-vscode", "mhutchie.git-graph", "eamodio.gitlens"] + "extensions": [ + "svelte.svelte-vscode", + "mhutchie.git-graph", + "eamodio.gitlens" + ] } - } - + } // Features to add to the dev container. More info: https://containers.dev/features. // "features": {}, - // Configure tool-specific properties. // "customizations": {}, - // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": ["app:5254"], // "portsAttributes": { @@ -31,10 +31,8 @@ // "protocol": "https" // } // } - - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "dotnet --info", - + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "dotnet --info", // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. // "remoteUser": "root" -} +} \ No newline at end of file diff --git a/Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806203327_Abrechnungsresultate.Designer.cs b/Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806203327_Abrechnungsresultate.Designer.cs new file mode 100644 index 00000000..8264b0c8 --- /dev/null +++ b/Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806203327_Abrechnungsresultate.Designer.cs @@ -0,0 +1,1683 @@ +// +using System; +using Deeplex.Saverwalter.Model; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Deeplex.Saverwalter.Model.Migrations.Npgsql +{ + [DbContext(typeof(SaverwalterContext))] + [Migration("20250806203327_Abrechnungsresultate")] + partial class Abrechnungsresultate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true) + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "uuid-ossp"); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Abrechnungsresultat", b => + { + b.Property("AbrechnungsresultatId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("abrechnungsresultat_id"); + + b.Property("IstBeglichen") + .HasColumnType("boolean") + .HasColumnName("ist_beglichen"); + + b.Property("Jahr") + .HasColumnType("integer") + .HasColumnName("jahr"); + + b.Property("Kaltmiete") + .HasColumnType("double precision") + .HasColumnName("kaltmiete"); + + b.Property("Minderung") + .HasColumnType("double precision") + .HasColumnName("minderung"); + + b.Property("Rechnungsbetrag") + .HasColumnType("double precision") + .HasColumnName("rechnungsbetrag"); + + b.Property("VertragId") + .HasColumnType("integer") + .HasColumnName("vertrag_id"); + + b.Property("Vorauszahlung") + .HasColumnType("double precision") + .HasColumnName("vorauszahlung"); + + b.HasKey("AbrechnungsresultatId") + .HasName("pk_abrechnungsresultate"); + + b.HasIndex("VertragId") + .HasDatabaseName("ix_abrechnungsresultate_vertrag_id"); + + b.ToTable("abrechnungsresultate", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Adresse", b => + { + b.Property("AdresseId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("adresse_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("AdresseId")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Hausnummer") + .IsRequired() + .HasColumnType("text") + .HasColumnName("hausnummer"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Postleitzahl") + .IsRequired() + .HasColumnType("text") + .HasColumnName("postleitzahl"); + + b.Property("Stadt") + .IsRequired() + .HasColumnType("text") + .HasColumnName("stadt"); + + b.Property("Strasse") + .IsRequired() + .HasColumnType("text") + .HasColumnName("strasse"); + + b.HasKey("AdresseId") + .HasName("pk_adressen"); + + b.ToTable("adressen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.Pbkdf2PasswordCredential", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Iterations") + .HasColumnType("integer") + .HasColumnName("iterations"); + + b.Property("PasswordHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("bytea") + .HasColumnName("password_hash"); + + b.Property("Salt") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("bytea") + .HasColumnName("salt"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("pk_pbkdf2password_credentials"); + + b.HasIndex("UserId") + .IsUnique() + .HasDatabaseName("ix_pbkdf2password_credentials_user_id"); + + b.ToTable("pbkdf2password_credentials", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.UserAccount", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Email") + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("KontaktId") + .HasColumnType("integer") + .HasColumnName("kontakt_id"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Role") + .HasColumnType("integer") + .HasColumnName("role"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_user_accounts"); + + b.HasIndex("KontaktId") + .HasDatabaseName("ix_user_accounts_kontakt_id"); + + b.HasIndex("Username") + .IsUnique() + .HasDatabaseName("ix_user_accounts_username"); + + b.ToTable("user_accounts", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.UserResetCredential", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expires_at"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("bytea") + .HasColumnName("token"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("pk_user_reset_credentials"); + + b.HasIndex("Token") + .IsUnique() + .HasDatabaseName("ix_user_reset_credentials_token"); + + b.HasIndex("UserId") + .IsUnique() + .HasDatabaseName("ix_user_reset_credentials_user_id"); + + b.ToTable("user_reset_credentials", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Betriebskostenrechnung", b => + { + b.Property("BetriebskostenrechnungId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("betriebskostenrechnung_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("BetriebskostenrechnungId")); + + b.Property("Betrag") + .HasColumnType("double precision") + .HasColumnName("betrag"); + + b.Property("BetreffendesJahr") + .HasColumnType("integer") + .HasColumnName("betreffendes_jahr"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Datum") + .HasColumnType("date") + .HasColumnName("datum"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("UmlageId") + .HasColumnType("integer") + .HasColumnName("umlage_id"); + + b.HasKey("BetriebskostenrechnungId") + .HasName("pk_betriebskostenrechnungen"); + + b.HasIndex("UmlageId") + .HasDatabaseName("ix_betriebskostenrechnungen_umlage_id"); + + b.ToTable("betriebskostenrechnungen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Erhaltungsaufwendung", b => + { + b.Property("ErhaltungsaufwendungId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("erhaltungsaufwendung_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ErhaltungsaufwendungId")); + + b.Property("AusstellerKontaktId") + .HasColumnType("integer") + .HasColumnName("aussteller_kontakt_id"); + + b.Property("Betrag") + .HasColumnType("double precision") + .HasColumnName("betrag"); + + b.Property("Bezeichnung") + .IsRequired() + .HasColumnType("text") + .HasColumnName("bezeichnung"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Datum") + .HasColumnType("date") + .HasColumnName("datum"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("WohnungId") + .HasColumnType("integer") + .HasColumnName("wohnung_id"); + + b.HasKey("ErhaltungsaufwendungId") + .HasName("pk_erhaltungsaufwendungen"); + + b.HasIndex("AusstellerKontaktId") + .HasDatabaseName("ix_erhaltungsaufwendungen_aussteller_kontakt_id"); + + b.HasIndex("WohnungId") + .HasDatabaseName("ix_erhaltungsaufwendungen_wohnung_id"); + + b.ToTable("erhaltungsaufwendungen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Garage", b => + { + b.Property("GarageId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("garage_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("GarageId")); + + b.Property("AdresseId") + .HasColumnType("integer") + .HasColumnName("adresse_id"); + + b.Property("BesitzerKontaktId") + .HasColumnType("integer") + .HasColumnName("besitzer_kontakt_id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Kennung") + .IsRequired() + .HasColumnType("text") + .HasColumnName("kennung"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.HasKey("GarageId") + .HasName("pk_garagen"); + + b.HasIndex("AdresseId") + .HasDatabaseName("ix_garagen_adresse_id"); + + b.HasIndex("BesitzerKontaktId") + .HasDatabaseName("ix_garagen_besitzer_kontakt_id"); + + b.ToTable("garagen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.HKVO", b => + { + b.Property("HKVOId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("hkvo_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("HKVOId")); + + b.Property("BetriebsstromUmlageId") + .HasColumnType("integer") + .HasColumnName("betriebsstrom_umlage_id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("HKVO_P7") + .HasColumnType("double precision") + .HasColumnName("hkvo_p7"); + + b.Property("HKVO_P8") + .HasColumnType("double precision") + .HasColumnName("hkvo_p8"); + + b.Property("HKVO_P9") + .HasColumnType("integer") + .HasColumnName("hkvo_p9"); + + b.Property("HeizkostenId") + .HasColumnType("integer") + .HasColumnName("heizkosten_id"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Strompauschale") + .HasColumnType("double precision") + .HasColumnName("strompauschale"); + + b.HasKey("HKVOId") + .HasName("pk_hkvo"); + + b.HasIndex("BetriebsstromUmlageId") + .HasDatabaseName("ix_hkvo_betriebsstrom_umlage_id"); + + b.HasIndex("HeizkostenId") + .IsUnique() + .HasDatabaseName("ix_hkvo_heizkosten_id"); + + b.ToTable("hkvo", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Kontakt", b => + { + b.Property("KontaktId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("kontakt_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("KontaktId")); + + b.Property("AdresseId") + .HasColumnType("integer") + .HasColumnName("adresse_id"); + + b.Property("Anrede") + .HasColumnType("integer") + .HasColumnName("anrede"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Email") + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("Fax") + .HasColumnType("text") + .HasColumnName("fax"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Mobil") + .HasColumnType("text") + .HasColumnName("mobil"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Rechtsform") + .HasColumnType("integer") + .HasColumnName("rechtsform"); + + b.Property("Telefon") + .HasColumnType("text") + .HasColumnName("telefon"); + + b.Property("Vorname") + .HasColumnType("text") + .HasColumnName("vorname"); + + b.HasKey("KontaktId") + .HasName("pk_kontakte"); + + b.HasIndex("AdresseId") + .HasDatabaseName("ix_kontakte_adresse_id"); + + b.ToTable("kontakte", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Konto", b => + { + b.Property("KontoId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("konto_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("KontoId")); + + b.Property("Bank") + .IsRequired() + .HasColumnType("text") + .HasColumnName("bank"); + + b.Property("BesitzerKontaktId") + .HasColumnType("integer") + .HasColumnName("besitzer_kontakt_id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Iban") + .IsRequired() + .HasColumnType("text") + .HasColumnName("iban"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.HasKey("KontoId") + .HasName("pk_kontos"); + + b.HasIndex("BesitzerKontaktId") + .HasDatabaseName("ix_kontos_besitzer_kontakt_id"); + + b.ToTable("kontos", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Miete", b => + { + b.Property("MieteId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("miete_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("MieteId")); + + b.Property("Betrag") + .HasColumnType("double precision") + .HasColumnName("betrag"); + + b.Property("BetreffenderMonat") + .HasColumnType("date") + .HasColumnName("betreffender_monat"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("VertragId") + .HasColumnType("integer") + .HasColumnName("vertrag_id"); + + b.Property("Zahlungsdatum") + .HasColumnType("date") + .HasColumnName("zahlungsdatum"); + + b.HasKey("MieteId") + .HasName("pk_mieten"); + + b.HasIndex("VertragId") + .HasDatabaseName("ix_mieten_vertrag_id"); + + b.ToTable("mieten", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Mietminderung", b => + { + b.Property("MietminderungId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("mietminderung_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("MietminderungId")); + + b.Property("Beginn") + .HasColumnType("date") + .HasColumnName("beginn"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Ende") + .HasColumnType("date") + .HasColumnName("ende"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Minderung") + .HasColumnType("double precision") + .HasColumnName("minderung"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("VertragId") + .HasColumnType("integer") + .HasColumnName("vertrag_id"); + + b.HasKey("MietminderungId") + .HasName("pk_mietminderungen"); + + b.HasIndex("VertragId") + .HasDatabaseName("ix_mietminderungen_vertrag_id"); + + b.ToTable("mietminderungen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Umlage", b => + { + b.Property("UmlageId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("umlage_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("UmlageId")); + + b.Property("Beschreibung") + .HasColumnType("text") + .HasColumnName("beschreibung"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Schluessel") + .HasColumnType("integer") + .HasColumnName("schluessel"); + + b.Property("TypUmlagetypId") + .HasColumnType("integer") + .HasColumnName("typ_umlagetyp_id"); + + b.HasKey("UmlageId") + .HasName("pk_umlagen"); + + b.HasIndex("TypUmlagetypId") + .HasDatabaseName("ix_umlagen_typ_umlagetyp_id"); + + b.ToTable("umlagen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Umlagetyp", b => + { + b.Property("UmlagetypId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("umlagetyp_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("UmlagetypId")); + + b.Property("Bezeichnung") + .IsRequired() + .HasColumnType("text") + .HasColumnName("bezeichnung"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.HasKey("UmlagetypId") + .HasName("pk_umlagetypen"); + + b.ToTable("umlagetypen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Vertrag", b => + { + b.Property("VertragId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("vertrag_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("VertragId")); + + b.Property("AnsprechpartnerKontaktId") + .HasColumnType("integer") + .HasColumnName("ansprechpartner_kontakt_id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Ende") + .HasColumnType("date") + .HasColumnName("ende"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("WohnungId") + .HasColumnType("integer") + .HasColumnName("wohnung_id"); + + b.HasKey("VertragId") + .HasName("pk_vertraege"); + + b.HasIndex("AnsprechpartnerKontaktId") + .HasDatabaseName("ix_vertraege_ansprechpartner_kontakt_id"); + + b.HasIndex("WohnungId") + .HasDatabaseName("ix_vertraege_wohnung_id"); + + b.ToTable("vertraege", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.VertragVersion", b => + { + b.Property("VertragVersionId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("vertrag_version_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("VertragVersionId")); + + b.Property("Beginn") + .HasColumnType("date") + .HasColumnName("beginn"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Grundmiete") + .HasColumnType("double precision") + .HasColumnName("grundmiete"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Personenzahl") + .HasColumnType("integer") + .HasColumnName("personenzahl"); + + b.Property("VertragId") + .HasColumnType("integer") + .HasColumnName("vertrag_id"); + + b.HasKey("VertragVersionId") + .HasName("pk_vertrag_versionen"); + + b.HasIndex("VertragId") + .HasDatabaseName("ix_vertrag_versionen_vertrag_id"); + + b.ToTable("vertrag_versionen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.VertragsBetriebskostenrechnung", b => + { + b.Property("VertragsBetriebskostenrechnungId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("vertrags_betriebskostenrechnung_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("VertragsBetriebskostenrechnungId")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("RechnungBetriebskostenrechnungId") + .HasColumnType("integer") + .HasColumnName("rechnung_betriebskostenrechnung_id"); + + b.Property("VertragId") + .HasColumnType("integer") + .HasColumnName("vertrag_id"); + + b.HasKey("VertragsBetriebskostenrechnungId") + .HasName("pk_vertrags_betriebskostenrechnung"); + + b.HasIndex("RechnungBetriebskostenrechnungId") + .HasDatabaseName("ix_vertrags_betriebskostenrechnung_rechnung_betriebskostenrech"); + + b.HasIndex("VertragId") + .HasDatabaseName("ix_vertrags_betriebskostenrechnung_vertrag_id"); + + b.ToTable("vertrags_betriebskostenrechnung", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Verwalter", b => + { + b.Property("VerwalterId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("verwalter_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("VerwalterId")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Rolle") + .HasColumnType("integer") + .HasColumnName("rolle"); + + b.Property("UserAccountId") + .HasColumnType("uuid") + .HasColumnName("user_account_id"); + + b.Property("WohnungId") + .HasColumnType("integer") + .HasColumnName("wohnung_id"); + + b.HasKey("VerwalterId") + .HasName("pk_verwalter_set"); + + b.HasIndex("UserAccountId") + .HasDatabaseName("ix_verwalter_set_user_account_id"); + + b.HasIndex("WohnungId") + .HasDatabaseName("ix_verwalter_set_wohnung_id"); + + b.ToTable("verwalter_set", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Wohnung", b => + { + b.Property("WohnungId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("wohnung_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("WohnungId")); + + b.Property("AdresseId") + .HasColumnType("integer") + .HasColumnName("adresse_id"); + + b.Property("BesitzerKontaktId") + .HasColumnType("integer") + .HasColumnName("besitzer_kontakt_id"); + + b.Property("Bezeichnung") + .IsRequired() + .HasColumnType("text") + .HasColumnName("bezeichnung"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Miteigentumsanteile") + .HasColumnType("double precision") + .HasColumnName("miteigentumsanteile"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Nutzeinheit") + .HasColumnType("integer") + .HasColumnName("nutzeinheit"); + + b.Property("Nutzflaeche") + .HasColumnType("double precision") + .HasColumnName("nutzflaeche"); + + b.Property("Wohnflaeche") + .HasColumnType("double precision") + .HasColumnName("wohnflaeche"); + + b.HasKey("WohnungId") + .HasName("pk_wohnungen"); + + b.HasIndex("AdresseId") + .HasDatabaseName("ix_wohnungen_adresse_id"); + + b.HasIndex("BesitzerKontaktId") + .HasDatabaseName("ix_wohnungen_besitzer_kontakt_id"); + + b.ToTable("wohnungen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Zaehler", b => + { + b.Property("ZaehlerId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("zaehler_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ZaehlerId")); + + b.Property("AdresseId") + .HasColumnType("integer") + .HasColumnName("adresse_id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Ende") + .HasColumnType("date") + .HasColumnName("ende"); + + b.Property("Kennnummer") + .IsRequired() + .HasColumnType("text") + .HasColumnName("kennnummer"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Typ") + .HasColumnType("integer") + .HasColumnName("typ"); + + b.Property("WohnungId") + .HasColumnType("integer") + .HasColumnName("wohnung_id"); + + b.HasKey("ZaehlerId") + .HasName("pk_zaehler_set"); + + b.HasIndex("AdresseId") + .HasDatabaseName("ix_zaehler_set_adresse_id"); + + b.HasIndex("WohnungId") + .HasDatabaseName("ix_zaehler_set_wohnung_id"); + + b.ToTable("zaehler_set", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Zaehlerstand", b => + { + b.Property("ZaehlerstandId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("zaehlerstand_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ZaehlerstandId")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Datum") + .HasColumnType("date") + .HasColumnName("datum"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Stand") + .HasColumnType("double precision") + .HasColumnName("stand"); + + b.Property("ZaehlerId") + .HasColumnType("integer") + .HasColumnName("zaehler_id"); + + b.HasKey("ZaehlerstandId") + .HasName("pk_zaehlerstaende"); + + b.HasIndex("ZaehlerId") + .HasDatabaseName("ix_zaehlerstaende_zaehler_id"); + + b.ToTable("zaehlerstaende", (string)null); + }); + + modelBuilder.Entity("GarageVertrag", b => + { + b.Property("GaragenGarageId") + .HasColumnType("integer") + .HasColumnName("garagen_garage_id"); + + b.Property("VertraegeVertragId") + .HasColumnType("integer") + .HasColumnName("vertraege_vertrag_id"); + + b.HasKey("GaragenGarageId", "VertraegeVertragId") + .HasName("pk_garage_vertrag"); + + b.HasIndex("VertraegeVertragId") + .HasDatabaseName("ix_garage_vertrag_vertraege_vertrag_id"); + + b.ToTable("garage_vertrag", (string)null); + }); + + modelBuilder.Entity("KontaktKontakt", b => + { + b.Property("JuristischePersonenKontaktId") + .HasColumnType("integer") + .HasColumnName("juristische_personen_kontakt_id"); + + b.Property("MitgliederKontaktId") + .HasColumnType("integer") + .HasColumnName("mitglieder_kontakt_id"); + + b.HasKey("JuristischePersonenKontaktId", "MitgliederKontaktId") + .HasName("pk_kontakt_kontakt"); + + b.HasIndex("MitgliederKontaktId") + .HasDatabaseName("ix_kontakt_kontakt_mitglieder_kontakt_id"); + + b.ToTable("kontakt_kontakt", (string)null); + }); + + modelBuilder.Entity("KontaktVertrag", b => + { + b.Property("MieterKontaktId") + .HasColumnType("integer") + .HasColumnName("mieter_kontakt_id"); + + b.Property("MietvertraegeVertragId") + .HasColumnType("integer") + .HasColumnName("mietvertraege_vertrag_id"); + + b.HasKey("MieterKontaktId", "MietvertraegeVertragId") + .HasName("pk_kontakt_vertrag"); + + b.HasIndex("MietvertraegeVertragId") + .HasDatabaseName("ix_kontakt_vertrag_mietvertraege_vertrag_id"); + + b.ToTable("kontakt_vertrag", (string)null); + }); + + modelBuilder.Entity("UmlageWohnung", b => + { + b.Property("UmlagenUmlageId") + .HasColumnType("integer") + .HasColumnName("umlagen_umlage_id"); + + b.Property("WohnungenWohnungId") + .HasColumnType("integer") + .HasColumnName("wohnungen_wohnung_id"); + + b.HasKey("UmlagenUmlageId", "WohnungenWohnungId") + .HasName("pk_umlage_wohnung"); + + b.HasIndex("WohnungenWohnungId") + .HasDatabaseName("ix_umlage_wohnung_wohnungen_wohnung_id"); + + b.ToTable("umlage_wohnung", (string)null); + }); + + modelBuilder.Entity("UmlageZaehler", b => + { + b.Property("UmlagenUmlageId") + .HasColumnType("integer") + .HasColumnName("umlagen_umlage_id"); + + b.Property("ZaehlerId") + .HasColumnType("integer") + .HasColumnName("zaehler_id"); + + b.HasKey("UmlagenUmlageId", "ZaehlerId") + .HasName("pk_umlage_zaehler"); + + b.HasIndex("ZaehlerId") + .HasDatabaseName("ix_umlage_zaehler_zaehler_id"); + + b.ToTable("umlage_zaehler", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Abrechnungsresultat", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", "Vertrag") + .WithMany("Abrechnungsresultate") + .HasForeignKey("VertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_abrechnungsresultate_vertraege_vertrag_id"); + + b.Navigation("Vertrag"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.Pbkdf2PasswordCredential", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Auth.UserAccount", "User") + .WithOne("Pbkdf2PasswordCredential") + .HasForeignKey("Deeplex.Saverwalter.Model.Auth.Pbkdf2PasswordCredential", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_pbkdf2password_credentials_user_accounts_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.UserAccount", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", null) + .WithMany("Accounts") + .HasForeignKey("KontaktId") + .HasConstraintName("fk_user_accounts_kontakte_kontakt_id"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.UserResetCredential", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Auth.UserAccount", "User") + .WithOne("UserResetCredential") + .HasForeignKey("Deeplex.Saverwalter.Model.Auth.UserResetCredential", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_reset_credentials_user_accounts_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Betriebskostenrechnung", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Umlage", "Umlage") + .WithMany("Betriebskostenrechnungen") + .HasForeignKey("UmlageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_betriebskostenrechnungen_umlagen_umlage_id"); + + b.Navigation("Umlage"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Erhaltungsaufwendung", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", "Aussteller") + .WithMany("Erhaltungsaufwendungen") + .HasForeignKey("AusstellerKontaktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_erhaltungsaufwendungen_kontakte_aussteller_kontakt_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Wohnung", "Wohnung") + .WithMany("Erhaltungsaufwendungen") + .HasForeignKey("WohnungId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_erhaltungsaufwendungen_wohnungen_wohnung_id"); + + b.Navigation("Aussteller"); + + b.Navigation("Wohnung"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Garage", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Adresse", "Adresse") + .WithMany("Garagen") + .HasForeignKey("AdresseId") + .HasConstraintName("fk_garagen_adressen_adresse_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", "Besitzer") + .WithMany("Garagen") + .HasForeignKey("BesitzerKontaktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_garagen_kontakte_besitzer_kontakt_id"); + + b.Navigation("Adresse"); + + b.Navigation("Besitzer"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.HKVO", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Umlage", "Betriebsstrom") + .WithMany("HKVOs") + .HasForeignKey("BetriebsstromUmlageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_hkvo_umlagen_betriebsstrom_umlage_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Umlage", "Heizkosten") + .WithOne("HKVO") + .HasForeignKey("Deeplex.Saverwalter.Model.HKVO", "HeizkostenId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_hkvo_umlagen_heizkosten_id"); + + b.Navigation("Betriebsstrom"); + + b.Navigation("Heizkosten"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Kontakt", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Adresse", "Adresse") + .WithMany("Kontakte") + .HasForeignKey("AdresseId") + .HasConstraintName("fk_kontakte_adressen_adresse_id"); + + b.Navigation("Adresse"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Konto", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", "Besitzer") + .WithMany() + .HasForeignKey("BesitzerKontaktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_kontos_kontakte_besitzer_kontakt_id"); + + b.Navigation("Besitzer"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Miete", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", "Vertrag") + .WithMany("Mieten") + .HasForeignKey("VertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_mieten_vertraege_vertrag_id"); + + b.Navigation("Vertrag"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Mietminderung", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", "Vertrag") + .WithMany("Mietminderungen") + .HasForeignKey("VertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_mietminderungen_vertraege_vertrag_id"); + + b.Navigation("Vertrag"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Umlage", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Umlagetyp", "Typ") + .WithMany("Umlagen") + .HasForeignKey("TypUmlagetypId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_umlagen_umlagetypen_typ_umlagetyp_id"); + + b.Navigation("Typ"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Vertrag", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", "Ansprechpartner") + .WithMany("VerwaltetVertraege") + .HasForeignKey("AnsprechpartnerKontaktId") + .HasConstraintName("fk_vertraege_kontakte_ansprechpartner_kontakt_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Wohnung", "Wohnung") + .WithMany("Vertraege") + .HasForeignKey("WohnungId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_vertraege_wohnungen_wohnung_id"); + + b.Navigation("Ansprechpartner"); + + b.Navigation("Wohnung"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.VertragVersion", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", "Vertrag") + .WithMany("Versionen") + .HasForeignKey("VertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_vertrag_versionen_vertraege_vertrag_id"); + + b.Navigation("Vertrag"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.VertragsBetriebskostenrechnung", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Betriebskostenrechnung", "Rechnung") + .WithMany() + .HasForeignKey("RechnungBetriebskostenrechnungId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_vertrags_betriebskostenrechnung_betriebskostenrechnungen_re"); + + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", "Vertrag") + .WithMany() + .HasForeignKey("VertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_vertrags_betriebskostenrechnung_vertraege_vertrag_id"); + + b.Navigation("Rechnung"); + + b.Navigation("Vertrag"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Verwalter", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Auth.UserAccount", "UserAccount") + .WithMany("Verwalter") + .HasForeignKey("UserAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_verwalter_set_user_accounts_user_account_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Wohnung", "Wohnung") + .WithMany("Verwalter") + .HasForeignKey("WohnungId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_verwalter_set_wohnungen_wohnung_id"); + + b.Navigation("UserAccount"); + + b.Navigation("Wohnung"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Wohnung", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Adresse", "Adresse") + .WithMany("Wohnungen") + .HasForeignKey("AdresseId") + .HasConstraintName("fk_wohnungen_adressen_adresse_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", "Besitzer") + .WithMany("Wohnungen") + .HasForeignKey("BesitzerKontaktId") + .HasConstraintName("fk_wohnungen_kontakte_besitzer_kontakt_id"); + + b.Navigation("Adresse"); + + b.Navigation("Besitzer"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Zaehler", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Adresse", "Adresse") + .WithMany("Zaehler") + .HasForeignKey("AdresseId") + .HasConstraintName("fk_zaehler_set_adressen_adresse_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Wohnung", "Wohnung") + .WithMany("Zaehler") + .HasForeignKey("WohnungId") + .HasConstraintName("fk_zaehler_set_wohnungen_wohnung_id"); + + b.Navigation("Adresse"); + + b.Navigation("Wohnung"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Zaehlerstand", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Zaehler", "Zaehler") + .WithMany("Staende") + .HasForeignKey("ZaehlerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_zaehlerstaende_zaehler_set_zaehler_id"); + + b.Navigation("Zaehler"); + }); + + modelBuilder.Entity("GarageVertrag", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Garage", null) + .WithMany() + .HasForeignKey("GaragenGarageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_garage_vertrag_garagen_garagen_garage_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", null) + .WithMany() + .HasForeignKey("VertraegeVertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_garage_vertrag_vertraege_vertraege_vertrag_id"); + }); + + modelBuilder.Entity("KontaktKontakt", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", null) + .WithMany() + .HasForeignKey("JuristischePersonenKontaktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_kontakt_kontakt_kontakte_juristische_personen_kontakt_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", null) + .WithMany() + .HasForeignKey("MitgliederKontaktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_kontakt_kontakt_kontakte_mitglieder_kontakt_id"); + }); + + modelBuilder.Entity("KontaktVertrag", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", null) + .WithMany() + .HasForeignKey("MieterKontaktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_kontakt_vertrag_kontakte_mieter_kontakt_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", null) + .WithMany() + .HasForeignKey("MietvertraegeVertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_kontakt_vertrag_vertraege_mietvertraege_vertrag_id"); + }); + + modelBuilder.Entity("UmlageWohnung", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Umlage", null) + .WithMany() + .HasForeignKey("UmlagenUmlageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_umlage_wohnung_umlagen_umlagen_umlage_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Wohnung", null) + .WithMany() + .HasForeignKey("WohnungenWohnungId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_umlage_wohnung_wohnungen_wohnungen_wohnung_id"); + }); + + modelBuilder.Entity("UmlageZaehler", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Umlage", null) + .WithMany() + .HasForeignKey("UmlagenUmlageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_umlage_zaehler_umlagen_umlagen_umlage_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Zaehler", null) + .WithMany() + .HasForeignKey("ZaehlerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_umlage_zaehler_zaehler_set_zaehler_id"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Adresse", b => + { + b.Navigation("Garagen"); + + b.Navigation("Kontakte"); + + b.Navigation("Wohnungen"); + + b.Navigation("Zaehler"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.UserAccount", b => + { + b.Navigation("Pbkdf2PasswordCredential"); + + b.Navigation("UserResetCredential"); + + b.Navigation("Verwalter"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Kontakt", b => + { + b.Navigation("Accounts"); + + b.Navigation("Erhaltungsaufwendungen"); + + b.Navigation("Garagen"); + + b.Navigation("VerwaltetVertraege"); + + b.Navigation("Wohnungen"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Umlage", b => + { + b.Navigation("Betriebskostenrechnungen"); + + b.Navigation("HKVO"); + + b.Navigation("HKVOs"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Umlagetyp", b => + { + b.Navigation("Umlagen"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Vertrag", b => + { + b.Navigation("Abrechnungsresultate"); + + b.Navigation("Mieten"); + + b.Navigation("Mietminderungen"); + + b.Navigation("Versionen"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Wohnung", b => + { + b.Navigation("Erhaltungsaufwendungen"); + + b.Navigation("Vertraege"); + + b.Navigation("Verwalter"); + + b.Navigation("Zaehler"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Zaehler", b => + { + b.Navigation("Staende"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806203327_Abrechnungsresultate.cs b/Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806203327_Abrechnungsresultate.cs new file mode 100644 index 00000000..0871a849 --- /dev/null +++ b/Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806203327_Abrechnungsresultate.cs @@ -0,0 +1,51 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Deeplex.Saverwalter.Model.Migrations.Npgsql +{ + /// + public partial class Abrechnungsresultate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "abrechnungsresultate", + columns: table => new + { + abrechnungsresultat_id = table.Column(type: "uuid", nullable: false), + vertrag_id = table.Column(type: "integer", nullable: false), + jahr = table.Column(type: "integer", nullable: false), + kaltmiete = table.Column(type: "double precision", nullable: false), + vorauszahlung = table.Column(type: "double precision", nullable: false), + minderung = table.Column(type: "double precision", nullable: false), + rechnungsbetrag = table.Column(type: "double precision", nullable: false), + ist_beglichen = table.Column(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("pk_abrechnungsresultate", x => x.abrechnungsresultat_id); + table.ForeignKey( + name: "fk_abrechnungsresultate_vertraege_vertrag_id", + column: x => x.vertrag_id, + principalTable: "vertraege", + principalColumn: "vertrag_id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "ix_abrechnungsresultate_vertrag_id", + table: "abrechnungsresultate", + column: "vertrag_id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "abrechnungsresultate"); + } + } +} diff --git a/Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806210125_AbrechnungsresultatAbgesendet.Designer.cs b/Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806210125_AbrechnungsresultatAbgesendet.Designer.cs new file mode 100644 index 00000000..49906a05 --- /dev/null +++ b/Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806210125_AbrechnungsresultatAbgesendet.Designer.cs @@ -0,0 +1,1687 @@ +// +using System; +using Deeplex.Saverwalter.Model; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Deeplex.Saverwalter.Model.Migrations.Npgsql +{ + [DbContext(typeof(SaverwalterContext))] + [Migration("20250806210125_AbrechnungsresultatAbgesendet")] + partial class AbrechnungsresultatAbgesendet + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Proxies:ChangeTracking", false) + .HasAnnotation("Proxies:CheckEquality", false) + .HasAnnotation("Proxies:LazyLoading", true) + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "uuid-ossp"); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Abrechnungsresultat", b => + { + b.Property("AbrechnungsresultatId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("abrechnungsresultat_id"); + + b.Property("Abgesendet") + .HasColumnType("boolean") + .HasColumnName("abgesendet"); + + b.Property("IstBeglichen") + .HasColumnType("boolean") + .HasColumnName("ist_beglichen"); + + b.Property("Jahr") + .HasColumnType("integer") + .HasColumnName("jahr"); + + b.Property("Kaltmiete") + .HasColumnType("double precision") + .HasColumnName("kaltmiete"); + + b.Property("Minderung") + .HasColumnType("double precision") + .HasColumnName("minderung"); + + b.Property("Rechnungsbetrag") + .HasColumnType("double precision") + .HasColumnName("rechnungsbetrag"); + + b.Property("VertragId") + .HasColumnType("integer") + .HasColumnName("vertrag_id"); + + b.Property("Vorauszahlung") + .HasColumnType("double precision") + .HasColumnName("vorauszahlung"); + + b.HasKey("AbrechnungsresultatId") + .HasName("pk_abrechnungsresultate"); + + b.HasIndex("VertragId") + .HasDatabaseName("ix_abrechnungsresultate_vertrag_id"); + + b.ToTable("abrechnungsresultate", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Adresse", b => + { + b.Property("AdresseId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("adresse_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("AdresseId")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Hausnummer") + .IsRequired() + .HasColumnType("text") + .HasColumnName("hausnummer"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Postleitzahl") + .IsRequired() + .HasColumnType("text") + .HasColumnName("postleitzahl"); + + b.Property("Stadt") + .IsRequired() + .HasColumnType("text") + .HasColumnName("stadt"); + + b.Property("Strasse") + .IsRequired() + .HasColumnType("text") + .HasColumnName("strasse"); + + b.HasKey("AdresseId") + .HasName("pk_adressen"); + + b.ToTable("adressen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.Pbkdf2PasswordCredential", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Iterations") + .HasColumnType("integer") + .HasColumnName("iterations"); + + b.Property("PasswordHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("bytea") + .HasColumnName("password_hash"); + + b.Property("Salt") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("bytea") + .HasColumnName("salt"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("pk_pbkdf2password_credentials"); + + b.HasIndex("UserId") + .IsUnique() + .HasDatabaseName("ix_pbkdf2password_credentials_user_id"); + + b.ToTable("pbkdf2password_credentials", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.UserAccount", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Email") + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("KontaktId") + .HasColumnType("integer") + .HasColumnName("kontakt_id"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Role") + .HasColumnType("integer") + .HasColumnName("role"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("Id") + .HasName("pk_user_accounts"); + + b.HasIndex("KontaktId") + .HasDatabaseName("ix_user_accounts_kontakt_id"); + + b.HasIndex("Username") + .IsUnique() + .HasDatabaseName("ix_user_accounts_username"); + + b.ToTable("user_accounts", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.UserResetCredential", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expires_at"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(16) + .HasColumnType("bytea") + .HasColumnName("token"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("pk_user_reset_credentials"); + + b.HasIndex("Token") + .IsUnique() + .HasDatabaseName("ix_user_reset_credentials_token"); + + b.HasIndex("UserId") + .IsUnique() + .HasDatabaseName("ix_user_reset_credentials_user_id"); + + b.ToTable("user_reset_credentials", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Betriebskostenrechnung", b => + { + b.Property("BetriebskostenrechnungId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("betriebskostenrechnung_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("BetriebskostenrechnungId")); + + b.Property("Betrag") + .HasColumnType("double precision") + .HasColumnName("betrag"); + + b.Property("BetreffendesJahr") + .HasColumnType("integer") + .HasColumnName("betreffendes_jahr"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Datum") + .HasColumnType("date") + .HasColumnName("datum"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("UmlageId") + .HasColumnType("integer") + .HasColumnName("umlage_id"); + + b.HasKey("BetriebskostenrechnungId") + .HasName("pk_betriebskostenrechnungen"); + + b.HasIndex("UmlageId") + .HasDatabaseName("ix_betriebskostenrechnungen_umlage_id"); + + b.ToTable("betriebskostenrechnungen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Erhaltungsaufwendung", b => + { + b.Property("ErhaltungsaufwendungId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("erhaltungsaufwendung_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ErhaltungsaufwendungId")); + + b.Property("AusstellerKontaktId") + .HasColumnType("integer") + .HasColumnName("aussteller_kontakt_id"); + + b.Property("Betrag") + .HasColumnType("double precision") + .HasColumnName("betrag"); + + b.Property("Bezeichnung") + .IsRequired() + .HasColumnType("text") + .HasColumnName("bezeichnung"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Datum") + .HasColumnType("date") + .HasColumnName("datum"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("WohnungId") + .HasColumnType("integer") + .HasColumnName("wohnung_id"); + + b.HasKey("ErhaltungsaufwendungId") + .HasName("pk_erhaltungsaufwendungen"); + + b.HasIndex("AusstellerKontaktId") + .HasDatabaseName("ix_erhaltungsaufwendungen_aussteller_kontakt_id"); + + b.HasIndex("WohnungId") + .HasDatabaseName("ix_erhaltungsaufwendungen_wohnung_id"); + + b.ToTable("erhaltungsaufwendungen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Garage", b => + { + b.Property("GarageId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("garage_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("GarageId")); + + b.Property("AdresseId") + .HasColumnType("integer") + .HasColumnName("adresse_id"); + + b.Property("BesitzerKontaktId") + .HasColumnType("integer") + .HasColumnName("besitzer_kontakt_id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Kennung") + .IsRequired() + .HasColumnType("text") + .HasColumnName("kennung"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.HasKey("GarageId") + .HasName("pk_garagen"); + + b.HasIndex("AdresseId") + .HasDatabaseName("ix_garagen_adresse_id"); + + b.HasIndex("BesitzerKontaktId") + .HasDatabaseName("ix_garagen_besitzer_kontakt_id"); + + b.ToTable("garagen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.HKVO", b => + { + b.Property("HKVOId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("hkvo_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("HKVOId")); + + b.Property("BetriebsstromUmlageId") + .HasColumnType("integer") + .HasColumnName("betriebsstrom_umlage_id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("HKVO_P7") + .HasColumnType("double precision") + .HasColumnName("hkvo_p7"); + + b.Property("HKVO_P8") + .HasColumnType("double precision") + .HasColumnName("hkvo_p8"); + + b.Property("HKVO_P9") + .HasColumnType("integer") + .HasColumnName("hkvo_p9"); + + b.Property("HeizkostenId") + .HasColumnType("integer") + .HasColumnName("heizkosten_id"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Strompauschale") + .HasColumnType("double precision") + .HasColumnName("strompauschale"); + + b.HasKey("HKVOId") + .HasName("pk_hkvo"); + + b.HasIndex("BetriebsstromUmlageId") + .HasDatabaseName("ix_hkvo_betriebsstrom_umlage_id"); + + b.HasIndex("HeizkostenId") + .IsUnique() + .HasDatabaseName("ix_hkvo_heizkosten_id"); + + b.ToTable("hkvo", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Kontakt", b => + { + b.Property("KontaktId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("kontakt_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("KontaktId")); + + b.Property("AdresseId") + .HasColumnType("integer") + .HasColumnName("adresse_id"); + + b.Property("Anrede") + .HasColumnType("integer") + .HasColumnName("anrede"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Email") + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("Fax") + .HasColumnType("text") + .HasColumnName("fax"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Mobil") + .HasColumnType("text") + .HasColumnName("mobil"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Rechtsform") + .HasColumnType("integer") + .HasColumnName("rechtsform"); + + b.Property("Telefon") + .HasColumnType("text") + .HasColumnName("telefon"); + + b.Property("Vorname") + .HasColumnType("text") + .HasColumnName("vorname"); + + b.HasKey("KontaktId") + .HasName("pk_kontakte"); + + b.HasIndex("AdresseId") + .HasDatabaseName("ix_kontakte_adresse_id"); + + b.ToTable("kontakte", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Konto", b => + { + b.Property("KontoId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("konto_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("KontoId")); + + b.Property("Bank") + .IsRequired() + .HasColumnType("text") + .HasColumnName("bank"); + + b.Property("BesitzerKontaktId") + .HasColumnType("integer") + .HasColumnName("besitzer_kontakt_id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Iban") + .IsRequired() + .HasColumnType("text") + .HasColumnName("iban"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.HasKey("KontoId") + .HasName("pk_kontos"); + + b.HasIndex("BesitzerKontaktId") + .HasDatabaseName("ix_kontos_besitzer_kontakt_id"); + + b.ToTable("kontos", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Miete", b => + { + b.Property("MieteId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("miete_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("MieteId")); + + b.Property("Betrag") + .HasColumnType("double precision") + .HasColumnName("betrag"); + + b.Property("BetreffenderMonat") + .HasColumnType("date") + .HasColumnName("betreffender_monat"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("VertragId") + .HasColumnType("integer") + .HasColumnName("vertrag_id"); + + b.Property("Zahlungsdatum") + .HasColumnType("date") + .HasColumnName("zahlungsdatum"); + + b.HasKey("MieteId") + .HasName("pk_mieten"); + + b.HasIndex("VertragId") + .HasDatabaseName("ix_mieten_vertrag_id"); + + b.ToTable("mieten", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Mietminderung", b => + { + b.Property("MietminderungId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("mietminderung_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("MietminderungId")); + + b.Property("Beginn") + .HasColumnType("date") + .HasColumnName("beginn"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Ende") + .HasColumnType("date") + .HasColumnName("ende"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Minderung") + .HasColumnType("double precision") + .HasColumnName("minderung"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("VertragId") + .HasColumnType("integer") + .HasColumnName("vertrag_id"); + + b.HasKey("MietminderungId") + .HasName("pk_mietminderungen"); + + b.HasIndex("VertragId") + .HasDatabaseName("ix_mietminderungen_vertrag_id"); + + b.ToTable("mietminderungen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Umlage", b => + { + b.Property("UmlageId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("umlage_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("UmlageId")); + + b.Property("Beschreibung") + .HasColumnType("text") + .HasColumnName("beschreibung"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Schluessel") + .HasColumnType("integer") + .HasColumnName("schluessel"); + + b.Property("TypUmlagetypId") + .HasColumnType("integer") + .HasColumnName("typ_umlagetyp_id"); + + b.HasKey("UmlageId") + .HasName("pk_umlagen"); + + b.HasIndex("TypUmlagetypId") + .HasDatabaseName("ix_umlagen_typ_umlagetyp_id"); + + b.ToTable("umlagen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Umlagetyp", b => + { + b.Property("UmlagetypId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("umlagetyp_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("UmlagetypId")); + + b.Property("Bezeichnung") + .IsRequired() + .HasColumnType("text") + .HasColumnName("bezeichnung"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.HasKey("UmlagetypId") + .HasName("pk_umlagetypen"); + + b.ToTable("umlagetypen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Vertrag", b => + { + b.Property("VertragId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("vertrag_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("VertragId")); + + b.Property("AnsprechpartnerKontaktId") + .HasColumnType("integer") + .HasColumnName("ansprechpartner_kontakt_id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Ende") + .HasColumnType("date") + .HasColumnName("ende"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("WohnungId") + .HasColumnType("integer") + .HasColumnName("wohnung_id"); + + b.HasKey("VertragId") + .HasName("pk_vertraege"); + + b.HasIndex("AnsprechpartnerKontaktId") + .HasDatabaseName("ix_vertraege_ansprechpartner_kontakt_id"); + + b.HasIndex("WohnungId") + .HasDatabaseName("ix_vertraege_wohnung_id"); + + b.ToTable("vertraege", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.VertragVersion", b => + { + b.Property("VertragVersionId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("vertrag_version_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("VertragVersionId")); + + b.Property("Beginn") + .HasColumnType("date") + .HasColumnName("beginn"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("Grundmiete") + .HasColumnType("double precision") + .HasColumnName("grundmiete"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Personenzahl") + .HasColumnType("integer") + .HasColumnName("personenzahl"); + + b.Property("VertragId") + .HasColumnType("integer") + .HasColumnName("vertrag_id"); + + b.HasKey("VertragVersionId") + .HasName("pk_vertrag_versionen"); + + b.HasIndex("VertragId") + .HasDatabaseName("ix_vertrag_versionen_vertrag_id"); + + b.ToTable("vertrag_versionen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.VertragsBetriebskostenrechnung", b => + { + b.Property("VertragsBetriebskostenrechnungId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("vertrags_betriebskostenrechnung_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("VertragsBetriebskostenrechnungId")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("RechnungBetriebskostenrechnungId") + .HasColumnType("integer") + .HasColumnName("rechnung_betriebskostenrechnung_id"); + + b.Property("VertragId") + .HasColumnType("integer") + .HasColumnName("vertrag_id"); + + b.HasKey("VertragsBetriebskostenrechnungId") + .HasName("pk_vertrags_betriebskostenrechnung"); + + b.HasIndex("RechnungBetriebskostenrechnungId") + .HasDatabaseName("ix_vertrags_betriebskostenrechnung_rechnung_betriebskostenrech"); + + b.HasIndex("VertragId") + .HasDatabaseName("ix_vertrags_betriebskostenrechnung_vertrag_id"); + + b.ToTable("vertrags_betriebskostenrechnung", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Verwalter", b => + { + b.Property("VerwalterId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("verwalter_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("VerwalterId")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Rolle") + .HasColumnType("integer") + .HasColumnName("rolle"); + + b.Property("UserAccountId") + .HasColumnType("uuid") + .HasColumnName("user_account_id"); + + b.Property("WohnungId") + .HasColumnType("integer") + .HasColumnName("wohnung_id"); + + b.HasKey("VerwalterId") + .HasName("pk_verwalter_set"); + + b.HasIndex("UserAccountId") + .HasDatabaseName("ix_verwalter_set_user_account_id"); + + b.HasIndex("WohnungId") + .HasDatabaseName("ix_verwalter_set_wohnung_id"); + + b.ToTable("verwalter_set", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Wohnung", b => + { + b.Property("WohnungId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("wohnung_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("WohnungId")); + + b.Property("AdresseId") + .HasColumnType("integer") + .HasColumnName("adresse_id"); + + b.Property("BesitzerKontaktId") + .HasColumnType("integer") + .HasColumnName("besitzer_kontakt_id"); + + b.Property("Bezeichnung") + .IsRequired() + .HasColumnType("text") + .HasColumnName("bezeichnung"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Miteigentumsanteile") + .HasColumnType("double precision") + .HasColumnName("miteigentumsanteile"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Nutzeinheit") + .HasColumnType("integer") + .HasColumnName("nutzeinheit"); + + b.Property("Nutzflaeche") + .HasColumnType("double precision") + .HasColumnName("nutzflaeche"); + + b.Property("Wohnflaeche") + .HasColumnType("double precision") + .HasColumnName("wohnflaeche"); + + b.HasKey("WohnungId") + .HasName("pk_wohnungen"); + + b.HasIndex("AdresseId") + .HasDatabaseName("ix_wohnungen_adresse_id"); + + b.HasIndex("BesitzerKontaktId") + .HasDatabaseName("ix_wohnungen_besitzer_kontakt_id"); + + b.ToTable("wohnungen", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Zaehler", b => + { + b.Property("ZaehlerId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("zaehler_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ZaehlerId")); + + b.Property("AdresseId") + .HasColumnType("integer") + .HasColumnName("adresse_id"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Ende") + .HasColumnType("date") + .HasColumnName("ende"); + + b.Property("Kennnummer") + .IsRequired() + .HasColumnType("text") + .HasColumnName("kennnummer"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Typ") + .HasColumnType("integer") + .HasColumnName("typ"); + + b.Property("WohnungId") + .HasColumnType("integer") + .HasColumnName("wohnung_id"); + + b.HasKey("ZaehlerId") + .HasName("pk_zaehler_set"); + + b.HasIndex("AdresseId") + .HasDatabaseName("ix_zaehler_set_adresse_id"); + + b.HasIndex("WohnungId") + .HasDatabaseName("ix_zaehler_set_wohnung_id"); + + b.ToTable("zaehler_set", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Zaehlerstand", b => + { + b.Property("ZaehlerstandId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("zaehlerstand_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ZaehlerstandId")); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasDefaultValueSql("NOW()"); + + b.Property("Datum") + .HasColumnType("date") + .HasColumnName("datum"); + + b.Property("LastModified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified") + .HasDefaultValueSql("NOW()"); + + b.Property("Notiz") + .HasColumnType("text") + .HasColumnName("notiz"); + + b.Property("Stand") + .HasColumnType("double precision") + .HasColumnName("stand"); + + b.Property("ZaehlerId") + .HasColumnType("integer") + .HasColumnName("zaehler_id"); + + b.HasKey("ZaehlerstandId") + .HasName("pk_zaehlerstaende"); + + b.HasIndex("ZaehlerId") + .HasDatabaseName("ix_zaehlerstaende_zaehler_id"); + + b.ToTable("zaehlerstaende", (string)null); + }); + + modelBuilder.Entity("GarageVertrag", b => + { + b.Property("GaragenGarageId") + .HasColumnType("integer") + .HasColumnName("garagen_garage_id"); + + b.Property("VertraegeVertragId") + .HasColumnType("integer") + .HasColumnName("vertraege_vertrag_id"); + + b.HasKey("GaragenGarageId", "VertraegeVertragId") + .HasName("pk_garage_vertrag"); + + b.HasIndex("VertraegeVertragId") + .HasDatabaseName("ix_garage_vertrag_vertraege_vertrag_id"); + + b.ToTable("garage_vertrag", (string)null); + }); + + modelBuilder.Entity("KontaktKontakt", b => + { + b.Property("JuristischePersonenKontaktId") + .HasColumnType("integer") + .HasColumnName("juristische_personen_kontakt_id"); + + b.Property("MitgliederKontaktId") + .HasColumnType("integer") + .HasColumnName("mitglieder_kontakt_id"); + + b.HasKey("JuristischePersonenKontaktId", "MitgliederKontaktId") + .HasName("pk_kontakt_kontakt"); + + b.HasIndex("MitgliederKontaktId") + .HasDatabaseName("ix_kontakt_kontakt_mitglieder_kontakt_id"); + + b.ToTable("kontakt_kontakt", (string)null); + }); + + modelBuilder.Entity("KontaktVertrag", b => + { + b.Property("MieterKontaktId") + .HasColumnType("integer") + .HasColumnName("mieter_kontakt_id"); + + b.Property("MietvertraegeVertragId") + .HasColumnType("integer") + .HasColumnName("mietvertraege_vertrag_id"); + + b.HasKey("MieterKontaktId", "MietvertraegeVertragId") + .HasName("pk_kontakt_vertrag"); + + b.HasIndex("MietvertraegeVertragId") + .HasDatabaseName("ix_kontakt_vertrag_mietvertraege_vertrag_id"); + + b.ToTable("kontakt_vertrag", (string)null); + }); + + modelBuilder.Entity("UmlageWohnung", b => + { + b.Property("UmlagenUmlageId") + .HasColumnType("integer") + .HasColumnName("umlagen_umlage_id"); + + b.Property("WohnungenWohnungId") + .HasColumnType("integer") + .HasColumnName("wohnungen_wohnung_id"); + + b.HasKey("UmlagenUmlageId", "WohnungenWohnungId") + .HasName("pk_umlage_wohnung"); + + b.HasIndex("WohnungenWohnungId") + .HasDatabaseName("ix_umlage_wohnung_wohnungen_wohnung_id"); + + b.ToTable("umlage_wohnung", (string)null); + }); + + modelBuilder.Entity("UmlageZaehler", b => + { + b.Property("UmlagenUmlageId") + .HasColumnType("integer") + .HasColumnName("umlagen_umlage_id"); + + b.Property("ZaehlerId") + .HasColumnType("integer") + .HasColumnName("zaehler_id"); + + b.HasKey("UmlagenUmlageId", "ZaehlerId") + .HasName("pk_umlage_zaehler"); + + b.HasIndex("ZaehlerId") + .HasDatabaseName("ix_umlage_zaehler_zaehler_id"); + + b.ToTable("umlage_zaehler", (string)null); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Abrechnungsresultat", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", "Vertrag") + .WithMany("Abrechnungsresultate") + .HasForeignKey("VertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_abrechnungsresultate_vertraege_vertrag_id"); + + b.Navigation("Vertrag"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.Pbkdf2PasswordCredential", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Auth.UserAccount", "User") + .WithOne("Pbkdf2PasswordCredential") + .HasForeignKey("Deeplex.Saverwalter.Model.Auth.Pbkdf2PasswordCredential", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_pbkdf2password_credentials_user_accounts_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.UserAccount", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", null) + .WithMany("Accounts") + .HasForeignKey("KontaktId") + .HasConstraintName("fk_user_accounts_kontakte_kontakt_id"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.UserResetCredential", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Auth.UserAccount", "User") + .WithOne("UserResetCredential") + .HasForeignKey("Deeplex.Saverwalter.Model.Auth.UserResetCredential", "UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_reset_credentials_user_accounts_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Betriebskostenrechnung", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Umlage", "Umlage") + .WithMany("Betriebskostenrechnungen") + .HasForeignKey("UmlageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_betriebskostenrechnungen_umlagen_umlage_id"); + + b.Navigation("Umlage"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Erhaltungsaufwendung", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", "Aussteller") + .WithMany("Erhaltungsaufwendungen") + .HasForeignKey("AusstellerKontaktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_erhaltungsaufwendungen_kontakte_aussteller_kontakt_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Wohnung", "Wohnung") + .WithMany("Erhaltungsaufwendungen") + .HasForeignKey("WohnungId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_erhaltungsaufwendungen_wohnungen_wohnung_id"); + + b.Navigation("Aussteller"); + + b.Navigation("Wohnung"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Garage", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Adresse", "Adresse") + .WithMany("Garagen") + .HasForeignKey("AdresseId") + .HasConstraintName("fk_garagen_adressen_adresse_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", "Besitzer") + .WithMany("Garagen") + .HasForeignKey("BesitzerKontaktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_garagen_kontakte_besitzer_kontakt_id"); + + b.Navigation("Adresse"); + + b.Navigation("Besitzer"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.HKVO", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Umlage", "Betriebsstrom") + .WithMany("HKVOs") + .HasForeignKey("BetriebsstromUmlageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_hkvo_umlagen_betriebsstrom_umlage_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Umlage", "Heizkosten") + .WithOne("HKVO") + .HasForeignKey("Deeplex.Saverwalter.Model.HKVO", "HeizkostenId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_hkvo_umlagen_heizkosten_id"); + + b.Navigation("Betriebsstrom"); + + b.Navigation("Heizkosten"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Kontakt", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Adresse", "Adresse") + .WithMany("Kontakte") + .HasForeignKey("AdresseId") + .HasConstraintName("fk_kontakte_adressen_adresse_id"); + + b.Navigation("Adresse"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Konto", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", "Besitzer") + .WithMany() + .HasForeignKey("BesitzerKontaktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_kontos_kontakte_besitzer_kontakt_id"); + + b.Navigation("Besitzer"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Miete", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", "Vertrag") + .WithMany("Mieten") + .HasForeignKey("VertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_mieten_vertraege_vertrag_id"); + + b.Navigation("Vertrag"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Mietminderung", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", "Vertrag") + .WithMany("Mietminderungen") + .HasForeignKey("VertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_mietminderungen_vertraege_vertrag_id"); + + b.Navigation("Vertrag"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Umlage", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Umlagetyp", "Typ") + .WithMany("Umlagen") + .HasForeignKey("TypUmlagetypId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_umlagen_umlagetypen_typ_umlagetyp_id"); + + b.Navigation("Typ"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Vertrag", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", "Ansprechpartner") + .WithMany("VerwaltetVertraege") + .HasForeignKey("AnsprechpartnerKontaktId") + .HasConstraintName("fk_vertraege_kontakte_ansprechpartner_kontakt_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Wohnung", "Wohnung") + .WithMany("Vertraege") + .HasForeignKey("WohnungId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_vertraege_wohnungen_wohnung_id"); + + b.Navigation("Ansprechpartner"); + + b.Navigation("Wohnung"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.VertragVersion", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", "Vertrag") + .WithMany("Versionen") + .HasForeignKey("VertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_vertrag_versionen_vertraege_vertrag_id"); + + b.Navigation("Vertrag"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.VertragsBetriebskostenrechnung", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Betriebskostenrechnung", "Rechnung") + .WithMany() + .HasForeignKey("RechnungBetriebskostenrechnungId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_vertrags_betriebskostenrechnung_betriebskostenrechnungen_re"); + + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", "Vertrag") + .WithMany() + .HasForeignKey("VertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_vertrags_betriebskostenrechnung_vertraege_vertrag_id"); + + b.Navigation("Rechnung"); + + b.Navigation("Vertrag"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Verwalter", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Auth.UserAccount", "UserAccount") + .WithMany("Verwalter") + .HasForeignKey("UserAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_verwalter_set_user_accounts_user_account_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Wohnung", "Wohnung") + .WithMany("Verwalter") + .HasForeignKey("WohnungId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_verwalter_set_wohnungen_wohnung_id"); + + b.Navigation("UserAccount"); + + b.Navigation("Wohnung"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Wohnung", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Adresse", "Adresse") + .WithMany("Wohnungen") + .HasForeignKey("AdresseId") + .HasConstraintName("fk_wohnungen_adressen_adresse_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", "Besitzer") + .WithMany("Wohnungen") + .HasForeignKey("BesitzerKontaktId") + .HasConstraintName("fk_wohnungen_kontakte_besitzer_kontakt_id"); + + b.Navigation("Adresse"); + + b.Navigation("Besitzer"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Zaehler", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Adresse", "Adresse") + .WithMany("Zaehler") + .HasForeignKey("AdresseId") + .HasConstraintName("fk_zaehler_set_adressen_adresse_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Wohnung", "Wohnung") + .WithMany("Zaehler") + .HasForeignKey("WohnungId") + .HasConstraintName("fk_zaehler_set_wohnungen_wohnung_id"); + + b.Navigation("Adresse"); + + b.Navigation("Wohnung"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Zaehlerstand", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Zaehler", "Zaehler") + .WithMany("Staende") + .HasForeignKey("ZaehlerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_zaehlerstaende_zaehler_set_zaehler_id"); + + b.Navigation("Zaehler"); + }); + + modelBuilder.Entity("GarageVertrag", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Garage", null) + .WithMany() + .HasForeignKey("GaragenGarageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_garage_vertrag_garagen_garagen_garage_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", null) + .WithMany() + .HasForeignKey("VertraegeVertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_garage_vertrag_vertraege_vertraege_vertrag_id"); + }); + + modelBuilder.Entity("KontaktKontakt", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", null) + .WithMany() + .HasForeignKey("JuristischePersonenKontaktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_kontakt_kontakt_kontakte_juristische_personen_kontakt_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", null) + .WithMany() + .HasForeignKey("MitgliederKontaktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_kontakt_kontakt_kontakte_mitglieder_kontakt_id"); + }); + + modelBuilder.Entity("KontaktVertrag", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Kontakt", null) + .WithMany() + .HasForeignKey("MieterKontaktId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_kontakt_vertrag_kontakte_mieter_kontakt_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", null) + .WithMany() + .HasForeignKey("MietvertraegeVertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_kontakt_vertrag_vertraege_mietvertraege_vertrag_id"); + }); + + modelBuilder.Entity("UmlageWohnung", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Umlage", null) + .WithMany() + .HasForeignKey("UmlagenUmlageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_umlage_wohnung_umlagen_umlagen_umlage_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Wohnung", null) + .WithMany() + .HasForeignKey("WohnungenWohnungId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_umlage_wohnung_wohnungen_wohnungen_wohnung_id"); + }); + + modelBuilder.Entity("UmlageZaehler", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Umlage", null) + .WithMany() + .HasForeignKey("UmlagenUmlageId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_umlage_zaehler_umlagen_umlagen_umlage_id"); + + b.HasOne("Deeplex.Saverwalter.Model.Zaehler", null) + .WithMany() + .HasForeignKey("ZaehlerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_umlage_zaehler_zaehler_set_zaehler_id"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Adresse", b => + { + b.Navigation("Garagen"); + + b.Navigation("Kontakte"); + + b.Navigation("Wohnungen"); + + b.Navigation("Zaehler"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.UserAccount", b => + { + b.Navigation("Pbkdf2PasswordCredential"); + + b.Navigation("UserResetCredential"); + + b.Navigation("Verwalter"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Kontakt", b => + { + b.Navigation("Accounts"); + + b.Navigation("Erhaltungsaufwendungen"); + + b.Navigation("Garagen"); + + b.Navigation("VerwaltetVertraege"); + + b.Navigation("Wohnungen"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Umlage", b => + { + b.Navigation("Betriebskostenrechnungen"); + + b.Navigation("HKVO"); + + b.Navigation("HKVOs"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Umlagetyp", b => + { + b.Navigation("Umlagen"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Vertrag", b => + { + b.Navigation("Abrechnungsresultate"); + + b.Navigation("Mieten"); + + b.Navigation("Mietminderungen"); + + b.Navigation("Versionen"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Wohnung", b => + { + b.Navigation("Erhaltungsaufwendungen"); + + b.Navigation("Vertraege"); + + b.Navigation("Verwalter"); + + b.Navigation("Zaehler"); + }); + + modelBuilder.Entity("Deeplex.Saverwalter.Model.Zaehler", b => + { + b.Navigation("Staende"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806210125_AbrechnungsresultatAbgesendet.cs b/Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806210125_AbrechnungsresultatAbgesendet.cs new file mode 100644 index 00000000..2fe90a42 --- /dev/null +++ b/Deeplex.Saverwalter.Model/Migrations/Npgsql/20250806210125_AbrechnungsresultatAbgesendet.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Deeplex.Saverwalter.Model.Migrations.Npgsql +{ + /// + public partial class AbrechnungsresultatAbgesendet : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "abgesendet", + table: "abrechnungsresultate", + type: "boolean", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "abgesendet", + table: "abrechnungsresultate"); + } + } +} diff --git a/Deeplex.Saverwalter.Model/Migrations/Npgsql/SaverwalterContextModelSnapshot.cs b/Deeplex.Saverwalter.Model/Migrations/Npgsql/SaverwalterContextModelSnapshot.cs index d90599dc..9413d23f 100644 --- a/Deeplex.Saverwalter.Model/Migrations/Npgsql/SaverwalterContextModelSnapshot.cs +++ b/Deeplex.Saverwalter.Model/Migrations/Npgsql/SaverwalterContextModelSnapshot.cs @@ -26,6 +26,54 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "uuid-ossp"); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + modelBuilder.Entity("Deeplex.Saverwalter.Model.Abrechnungsresultat", b => + { + b.Property("AbrechnungsresultatId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("abrechnungsresultat_id"); + + b.Property("Abgesendet") + .HasColumnType("boolean") + .HasColumnName("abgesendet"); + + b.Property("IstBeglichen") + .HasColumnType("boolean") + .HasColumnName("ist_beglichen"); + + b.Property("Jahr") + .HasColumnType("integer") + .HasColumnName("jahr"); + + b.Property("Kaltmiete") + .HasColumnType("double precision") + .HasColumnName("kaltmiete"); + + b.Property("Minderung") + .HasColumnType("double precision") + .HasColumnName("minderung"); + + b.Property("Rechnungsbetrag") + .HasColumnType("double precision") + .HasColumnName("rechnungsbetrag"); + + b.Property("VertragId") + .HasColumnType("integer") + .HasColumnName("vertrag_id"); + + b.Property("Vorauszahlung") + .HasColumnType("double precision") + .HasColumnName("vorauszahlung"); + + b.HasKey("AbrechnungsresultatId") + .HasName("pk_abrechnungsresultate"); + + b.HasIndex("VertragId") + .HasDatabaseName("ix_abrechnungsresultate_vertrag_id"); + + b.ToTable("abrechnungsresultate", (string)null); + }); + modelBuilder.Entity("Deeplex.Saverwalter.Model.Adresse", b => { b.Property("AdresseId") @@ -1178,6 +1226,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("umlage_zaehler", (string)null); }); + modelBuilder.Entity("Deeplex.Saverwalter.Model.Abrechnungsresultat", b => + { + b.HasOne("Deeplex.Saverwalter.Model.Vertrag", "Vertrag") + .WithMany("Abrechnungsresultate") + .HasForeignKey("VertragId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_abrechnungsresultate_vertraege_vertrag_id"); + + b.Navigation("Vertrag"); + }); + modelBuilder.Entity("Deeplex.Saverwalter.Model.Auth.Pbkdf2PasswordCredential", b => { b.HasOne("Deeplex.Saverwalter.Model.Auth.UserAccount", "User") @@ -1594,6 +1654,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Deeplex.Saverwalter.Model.Vertrag", b => { + b.Navigation("Abrechnungsresultate"); + b.Navigation("Mieten"); b.Navigation("Mietminderungen"); diff --git a/Deeplex.Saverwalter.Model/SaverWalterContext.cs b/Deeplex.Saverwalter.Model/SaverWalterContext.cs index b1bd6ea9..b26728bd 100644 --- a/Deeplex.Saverwalter.Model/SaverWalterContext.cs +++ b/Deeplex.Saverwalter.Model/SaverWalterContext.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023-2024 Henrik S. Gaßmann, Kai Lawrence +// Copyright (c) 2023-2025 Henrik S. Gaßmann, Kai Lawrence // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -20,6 +20,7 @@ namespace Deeplex.Saverwalter.Model { public sealed class SaverwalterContext : DbContext { + public DbSet Abrechnungsresultate { get; set; } = null!; public DbSet Adressen { get; set; } = null!; public DbSet Betriebskostenrechnungen { get; set; } = null!; public DbSet Erhaltungsaufwendungen { get; set; } = null!; diff --git a/Deeplex.Saverwalter.Model/model/Abrechnungsresultat.cs b/Deeplex.Saverwalter.Model/model/Abrechnungsresultat.cs new file mode 100644 index 00000000..2d87efb5 --- /dev/null +++ b/Deeplex.Saverwalter.Model/model/Abrechnungsresultat.cs @@ -0,0 +1,40 @@ +// Copyright (c) 2023-2025 Kai Lawrence +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +using System.ComponentModel.DataAnnotations; + +namespace Deeplex.Saverwalter.Model; + +public class Abrechnungsresultat +{ + [Required] + public Guid AbrechnungsresultatId { get; set; } + + [Required] + public virtual Vertrag Vertrag { get; set; } = null!; + [Required] + public int Jahr { get; set; } + [Required] + public double Kaltmiete { get; set; } + [Required] + public double Vorauszahlung { get; set; } + [Required] + public double Minderung { get; set; } + [Required] + public double Rechnungsbetrag { get; set; } + public bool Abgesendet { get; set; } + public bool IstBeglichen { get; set; } + +} diff --git a/Deeplex.Saverwalter.Model/model/Vertrag.cs b/Deeplex.Saverwalter.Model/model/Vertrag.cs index 21d7ebd2..d0e78ffb 100644 --- a/Deeplex.Saverwalter.Model/model/Vertrag.cs +++ b/Deeplex.Saverwalter.Model/model/Vertrag.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023-2024 Kai Lawrence +// Copyright (c) 2023-2025 Kai Lawrence // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -26,11 +26,12 @@ public class Vertrag public string? Notiz { get; set; } public DateOnly? Ende { get; set; } - public virtual List Versionen { get; private set; } = new(); - public virtual List Mieten { get; private set; } = new(); - public virtual List Mietminderungen { get; private set; } = new(); - public virtual List Garagen { get; private set; } = new(); - public virtual List Mieter { get; private set; } = new(); + public virtual List Versionen { get; private set; } = []; + public virtual List Mieten { get; private set; } = []; + public virtual List Mietminderungen { get; private set; } = []; + public virtual List Garagen { get; private set; } = []; + public virtual List Mieter { get; private set; } = []; + public virtual List Abrechnungsresultate { get; private set; } = []; public DateTime CreatedAt { get; private set; } public DateTime LastModified { get; set; } public Vertrag() diff --git a/Deeplex.Saverwalter.PrintService/Utils.cs b/Deeplex.Saverwalter.PrintService/Utils.cs index 8c531c79..898001e6 100644 --- a/Deeplex.Saverwalter.PrintService/Utils.cs +++ b/Deeplex.Saverwalter.PrintService/Utils.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023-2024 Kai Lawrence +// Copyright (c) 2023-2025 Kai Lawrence // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -92,7 +92,7 @@ public static string RefundDemand(double result) public const string GenerischerTextFirstPart = "Die Abrechnung betrifft zunächst die mietvertraglich vereinbarten Nebenkosten (die kalten Betriebskosten). "; public const string GenerischerTextHeizungPart - = "Die Kosten für die Heizung und für die Erwärmung von Wasser über die Heizanlage Ihres Wohnhauses (warme Betriebskosten) werden gesondert berechnet, nach Verbrauch und Wohn -/ Nutzfläche auf die einzelnen Wohnungen umgelegt („Ihre Heizungsrechnung“) und mit dem Ergebnis aus der Aufrechnung Ihrer Nebenkosten und der Summe der von Ihnen geleisteten Vorauszahlungen verrechnet."; + = "Die Kosten für die Heizung und für die Erwärmung von Wasser über die Heizanlage Ihres Wohnhauses (warme Betriebskosten) werden gesondert berechnet, nach Verbrauch und Wohn -/ Nutzfläche auf die einzelnen Wohnungen umgelegt („Ihre Heizungsrechnung“) und mit dem Ergebnis aus der Aufrechnung Ihrer Nebenkosten und der Summe der von Ihnen geleisteten Vorauszahlungen verrechnet. "; public const string GenerischerTextFinalPart = "Bei bestehenden Mietrückständen ist das Ergebnis der Abrechnung zusätzlich mit den Mietrückständen verrechnet. Gegebenenfalls bestehende Mietminderungen / Ratenzahlungsvereinbarungen sind hier nicht berücksichtigt, haben aber weiterhin für den vereinbarten Zeitraum Bestand. Aufgelöste oder gekündigte Mietverhältnisse werden durch dieses Schreiben nicht neu begründet. Die Aufstellung, Verteilung und Erläuterung der Gesamtkosten, die Berechnung der Kostenanteile, die Verrechnung der geleisteten Vorauszahlungen und gegebenenfalls die Neuberechnung der monatlichen Vorauszahlungen entnehmen Sie bitte den folgenden Seiten."; diff --git a/Deeplex.Saverwalter.WebAPI.Tests/Services/Betriebskostenabrechnung.Tests.cs b/Deeplex.Saverwalter.WebAPI.Tests/Services/Betriebskostenabrechnung.Tests.cs index 381eb310..4418cfe5 100644 --- a/Deeplex.Saverwalter.WebAPI.Tests/Services/Betriebskostenabrechnung.Tests.cs +++ b/Deeplex.Saverwalter.WebAPI.Tests/Services/Betriebskostenabrechnung.Tests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023-2024 Kai Lawrence +// Copyright (c) 2023-2025 Kai Lawrence // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -22,39 +22,39 @@ namespace Deeplex.Saverwalter.WebAPI.Tests public class BetriebskostenabrechnungHandlerTests { [Fact] - public void GetTest() + public async Task GetTest() { var ctx = TestUtils.GetContext(); var vertrag = TestUtils.GetVertragForAbrechnung(ctx); var handler = new BetriebskostenabrechnungHandler(ctx); - var result = handler.Get(vertrag.VertragId, 2021); + var result = await handler.Get(vertrag.VertragId, 2021); result.Should().NotBeNull(); result.Value.Should().NotBeNull(); } [Fact] - public void GetWordDocumentTest() + public async Task GetWordDocumentTest() { var ctx = TestUtils.GetContext(); var vertrag = TestUtils.GetVertragForAbrechnung(ctx); var handler = new BetriebskostenabrechnungHandler(ctx); - var result = handler.GetWordDocument(vertrag.VertragId, 2021); + var result = await handler.GetWordDocument(vertrag.VertragId, 2021); result.Should().NotBeNull(); result.Value.Should().NotBeNull(); } [Fact(Skip = "PDF is TODO")] - public void GetPdfDocumentTest() + public async Task GetPdfDocumentTest() { var ctx = TestUtils.GetContext(); var vertrag = TestUtils.GetVertragForAbrechnung(ctx); var handler = new BetriebskostenabrechnungHandler(ctx); - var result = handler.GetPdfDocument(vertrag.VertragId, 2021); + var result = await handler.GetPdfDocument(vertrag.VertragId, 2021); result.Should().NotBeNull(); result.Value.Should().NotBeNull(); diff --git a/Deeplex.Saverwalter.WebAPI/Controllers/Utils/BetriebskostenabrechnungController.cs b/Deeplex.Saverwalter.WebAPI/Controllers/Utils/BetriebskostenabrechnungController.cs index 17e275db..4ec7d91e 100644 --- a/Deeplex.Saverwalter.WebAPI/Controllers/Utils/BetriebskostenabrechnungController.cs +++ b/Deeplex.Saverwalter.WebAPI/Controllers/Utils/BetriebskostenabrechnungController.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023-2024 Kai Lawrence +// Copyright (c) 2023-2025 Kai Lawrence // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -114,6 +114,17 @@ public RechnungEntry(KeyValuePair rechnung, Abr } } + public class AbrechnungsresultatEntry(Abrechnungsresultat result) + { + public int Jahr { get; } = result.Jahr; + public double Kaltmiete { get; } = result.Kaltmiete; + public double Vorauszahlung { get; } = result.Vorauszahlung; + public double Rechnungsbetrag { get; } = result.Rechnungsbetrag; + public double Minderung { get; } = result.Minderung; + public bool Abgesendet { get; } = result.Abgesendet; + public bool IstBeglichen { get; } = result.IstBeglichen; + } + public class AbrechnungseinheitEntry { public List? Rechnungen { get; } @@ -182,8 +193,9 @@ public class BetriebskostenabrechnungEntry public List Vertraege { get; } public List Zaehler { get; } public List Mieten { get; } + public AbrechnungsresultatEntry? Resultat { get; } - public BetriebskostenabrechnungEntry(Betriebskostenabrechnung abrechnung) + public BetriebskostenabrechnungEntry(Betriebskostenabrechnung abrechnung, Abrechnungsresultat? resultat) { Notes = abrechnung.Notes; Vermieter = new SelectionEntry(abrechnung.Vermieter.KontaktId, abrechnung.Vermieter.Bezeichnung); @@ -225,6 +237,12 @@ public BetriebskostenabrechnungEntry(Betriebskostenabrechnung abrechnung) miete.BetreffenderMonat <= abrechnung.Zeitraum.Abrechnungsende) .Select(miete => new MieteEntryBase(miete, new())) .ToList(); + + if (resultat != null) + { + Resultat = new AbrechnungsresultatEntry(resultat); + } + } } @@ -236,21 +254,21 @@ public BetriebskostenabrechnungController(ILogger GetBetriebskostenabrechnung(int vertrag_id, int jahr) + public Task> GetBetriebskostenabrechnung(int vertrag_id, int jahr) { return Service.Get(vertrag_id, jahr); } [HttpGet] [Route("api/betriebskostenabrechnung/{vertrag_id}/{jahr}/word_document")] - public ActionResult GetBetriebskostenabrechnungWordDocument(int vertrag_id, int jahr) + public Task> GetBetriebskostenabrechnungWordDocument(int vertrag_id, int jahr) { return Service.GetWordDocument(vertrag_id, jahr); } [HttpGet] [Route("api/betriebskostenabrechnung/{vertrag_id}/{jahr}/pdf_document")] - public ActionResult GetBetriebskostenabrechnungPdfDocument(int vertrag_id, int jahr) + public Task> GetBetriebskostenabrechnungPdfDocument(int vertrag_id, int jahr) { return Service.GetPdfDocument(vertrag_id, jahr); } diff --git a/Deeplex.Saverwalter.WebAPI/Controllers/VertragController.cs b/Deeplex.Saverwalter.WebAPI/Controllers/VertragController.cs index eb1ea795..fc7c1aa5 100644 --- a/Deeplex.Saverwalter.WebAPI/Controllers/VertragController.cs +++ b/Deeplex.Saverwalter.WebAPI/Controllers/VertragController.cs @@ -21,6 +21,7 @@ using static Deeplex.Saverwalter.WebAPI.Controllers.MieteController; using static Deeplex.Saverwalter.WebAPI.Controllers.MietminderungController; using static Deeplex.Saverwalter.WebAPI.Controllers.Services.SelectionListController; +using static Deeplex.Saverwalter.WebAPI.Controllers.Utils.BetriebskostenabrechnungController; using static Deeplex.Saverwalter.WebAPI.Controllers.VertragController; using static Deeplex.Saverwalter.WebAPI.Controllers.VertragVersionController; using static Deeplex.Saverwalter.WebAPI.Services.Utils; @@ -78,6 +79,8 @@ public class VertragEntry : VertragEntryBase public IEnumerable Betriebskostenrechnungen { get; set; } = []; public IEnumerable Mietminderungen { get; set; } = []; public IEnumerable Mieter { get; set; } = []; + + public IEnumerable Abrechnungsresultate { get; set; } = []; // TODO Garagen public VertragEntry() : base() { } @@ -99,6 +102,7 @@ public VertragEntry(Vertrag entity, Permissions permissions) : base(entity, perm .Select(e => new BetriebskostenrechnungEntryBase(e, permissions)); Mietminderungen = entity.Mietminderungen.ToList().Select(e => new MietminderungEntryBase(e, permissions)); Mieter = entity.Mieter.Select(e => new KontaktEntryBase(e, permissions)); + Abrechnungsresultate = entity.Abrechnungsresultate.Select(e => new AbrechnungsresultatEntry(e)); CreatedAt = entity.CreatedAt; LastModified = entity.LastModified; diff --git a/Deeplex.Saverwalter.WebAPI/Services/Betriebskostenabrechnung.cs b/Deeplex.Saverwalter.WebAPI/Services/Betriebskostenabrechnung.cs index 3b6a2dc1..f70d35d8 100644 --- a/Deeplex.Saverwalter.WebAPI/Services/Betriebskostenabrechnung.cs +++ b/Deeplex.Saverwalter.WebAPI/Services/Betriebskostenabrechnung.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023-2024 Kai Lawrence +// Copyright (c) 2023-2025 Kai Lawrence // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -17,28 +17,53 @@ using Deeplex.Saverwalter.Model; using Deeplex.Saverwalter.PrintService; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; using static Deeplex.Saverwalter.WebAPI.Controllers.Utils.BetriebskostenabrechnungController; namespace Deeplex.Saverwalter.WebAPI { public sealed class BetriebskostenabrechnungHandler { - private static Betriebskostenabrechnung CreateAbrechnung(Vertrag vertrag, int Jahr) + private static Betriebskostenabrechnung CreateAbrechnung(Vertrag vertrag, int jahr) { - var beginn = new DateOnly(Jahr, 1, 1); - var ende = new DateOnly(Jahr, 12, 31); + var beginn = new DateOnly(jahr, 1, 1); + var ende = new DateOnly(jahr, 12, 31); - return new Betriebskostenabrechnung(vertrag, Jahr, beginn, ende); + return new Betriebskostenabrechnung(vertrag, jahr, beginn, ende); } - public ActionResult Get(int vertrag_id, int Jahr) + private async Task SaveAbrechnungsresultat(Betriebskostenabrechnung abrechnung) + { + var resultate = Ctx.Abrechnungsresultate.Where(e => + e.Vertrag == abrechnung.Vertrag && + e.Jahr == abrechnung.Zeitraum.Jahr); + Ctx.Abrechnungsresultate.RemoveRange(resultate); + + var resultat = new Abrechnungsresultat + { + Vertrag = abrechnung.Vertrag, + Jahr = abrechnung.Zeitraum.Jahr, + Kaltmiete = abrechnung.KaltMiete, + Vorauszahlung = abrechnung.GezahlteMiete, + Rechnungsbetrag = abrechnung.BetragNebenkosten, + Minderung = abrechnung.Mietminderung, + IstBeglichen = false, + }; + + Ctx.Abrechnungsresultate.Add(resultat); + await Ctx.SaveChangesAsync(); + } + + public async Task> Get(int vertrag_id, int jahr) { try { var vertrag = Ctx.Vertraege.Find(vertrag_id)!; - var abrechnung = CreateAbrechnung(vertrag, Jahr); - var controller = new BetriebskostenabrechnungEntry(abrechnung); + var abrechnung = CreateAbrechnung(vertrag, jahr); + var resultat = await Ctx.Abrechnungsresultate + .FirstOrDefaultAsync(e => e.Vertrag == vertrag && e.Jahr == jahr); + var controller = new BetriebskostenabrechnungEntry(abrechnung, resultat); return controller; } @@ -48,13 +73,14 @@ public ActionResult Get(int vertrag_id, int Jahr) } } - public ActionResult GetWordDocument(int vertrag_id, int Jahr) + public async Task> GetWordDocument(int vertrag_id, int jahr) { try { var vertrag = Ctx.Vertraege.Find(vertrag_id)!; var stream = new MemoryStream(); - var abrechnung = CreateAbrechnung(vertrag, Jahr); + var abrechnung = CreateAbrechnung(vertrag, jahr); + await SaveAbrechnungsresultat(abrechnung); abrechnung.SaveAsDocx(stream); stream.Position = 0; @@ -66,13 +92,14 @@ public ActionResult GetWordDocument(int vertrag_id, int Jahr) } } - public ActionResult GetPdfDocument(int vertrag_id, int Jahr) + public async Task> GetPdfDocument(int vertrag_id, int Jahr) { try { var vertrag = Ctx.Vertraege.Find(vertrag_id)!; var stream = new MemoryStream(); var abrechnung = CreateAbrechnung(vertrag, Jahr); + await SaveAbrechnungsresultat(abrechnung); abrechnung.SaveAsPdf(stream); stream.Position = 0; diff --git a/Deeplex.Saverwalter.WebAPI/Services/DbServices/UmlageDbService.cs b/Deeplex.Saverwalter.WebAPI/Services/DbServices/UmlageDbService.cs index a5611424..4326f05d 100644 --- a/Deeplex.Saverwalter.WebAPI/Services/DbServices/UmlageDbService.cs +++ b/Deeplex.Saverwalter.WebAPI/Services/DbServices/UmlageDbService.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023-2024 Kai Lawrence +// Copyright (c) 2023-2025 Kai Lawrence // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -179,7 +179,7 @@ private void SetOptionalValues(Umlage entity, UmlageEntry entry) (Umlageschluessel)entry.Schluessel.Id == Umlageschluessel.NachVerbrauch && entry.HKVO is HKVOEntryBase hkvo) { - if (hkvo.Id == 0) + if (hkvo.Id == 0 && entity.HKVO == null) { var newHKVO = new HKVO( ((double)hkvo.HKVO_P7) / 100, diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/components/abrechnung/WalterAbrechnung.svelte b/Deeplex.Saverwalter.WebAPI/svelte/src/components/abrechnung/WalterAbrechnung.svelte index df3e9b56..f34276a9 100644 --- a/Deeplex.Saverwalter.WebAPI/svelte/src/components/abrechnung/WalterAbrechnung.svelte +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/components/abrechnung/WalterAbrechnung.svelte @@ -1,4 +1,4 @@ - + + + + + +{#if resultat} + +

Letzter Stand dieser Abrechnung:

+
+ + + + + Vorauszahlung Gesamt + Kaltmiete + Vorauszahlung Nebenkosten + Nebenkosten + Saldo + Ist versendet + Ist beglichen + + + + + + {convertEuro(resultat.vorauszahlung)} + + + {convertEuro(resultat.kaltmiete)} + + + {convertEuro( + resultat.vorauszahlung - resultat.kaltmiete + )} + + + {convertEuro(resultat.rechnungsbetrag)} + + + {convertEuro( + resultat.vorauszahlung - + resultat.kaltmiete - + resultat.rechnungsbetrag + )} + + + {resultat.abgesendet ? 'Ja' : 'Nein'} + + + {resultat.istBeglichen ? 'Ja' : 'Nein'} + + + + + +{:else} + Bisher keine Abrechnung erstellt +{/if} diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/components/details/WalterUmlage.svelte b/Deeplex.Saverwalter.WebAPI/svelte/src/components/details/WalterUmlage.svelte index 9466c16f..68830a90 100644 --- a/Deeplex.Saverwalter.WebAPI/svelte/src/components/details/WalterUmlage.svelte +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/components/details/WalterUmlage.svelte @@ -1,4 +1,4 @@ - + + + + + + + diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/components/subdetails/WalterAnhaenge.ts b/Deeplex.Saverwalter.WebAPI/svelte/src/components/subdetails/WalterAnhaenge.ts index afbaa871..da8c7b70 100644 --- a/Deeplex.Saverwalter.WebAPI/svelte/src/components/subdetails/WalterAnhaenge.ts +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/components/subdetails/WalterAnhaenge.ts @@ -1,4 +1,4 @@ -// Copyright (c) 2023-2024 Kai Lawrence +// Copyright (c) 2023-2025 Kai Lawrence // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -13,7 +13,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import type { WalterFileHandle, WalterFileWrapper } from '$walter/lib'; +import type { WalterFileHandle } from '$walter/lib'; import { walter_file_post } from '$walter/services/files'; import { openModal } from '$walter/store'; import { WalterFile } from '$walter/lib/WalterFile'; diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterBetriebskostenrechnung.ts b/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterBetriebskostenrechnung.ts index afb43a26..a6163029 100644 --- a/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterBetriebskostenrechnung.ts +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterBetriebskostenrechnung.ts @@ -1,4 +1,4 @@ -// Copyright (c) 2023-2024 Kai Lawrence +// Copyright (c) 2023-2025 Kai Lawrence // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by @@ -33,7 +33,7 @@ export class WalterBetriebskostenrechnungEntry extends WalterApiHandler { public umlage: WalterSelectionEntry, public wohnungen: WalterWohnungEntry[], public betriebskostenrechnungen: WalterBetriebskostenrechnungEntry[], - public permissions: WalterPermissions + public permissions: WalterPermissions, ) { super(); } @@ -63,7 +63,6 @@ export class WalterBetriebskostenrechnungEntry extends WalterApiHandler { umlage, wohnungen, betriebskostenrechnungen, - permissions - ); + permissions); } } diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterVertrag.ts b/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterVertrag.ts index 39e9e6bc..0ff1b3c8 100644 --- a/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterVertrag.ts +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterVertrag.ts @@ -13,6 +13,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +import type { WalterBetriebskostenabrechnungResultatEntry } from '$walter/types'; import { WalterApiHandler } from './WalterApiHandler'; import { WalterBetriebskostenrechnungEntry } from './WalterBetriebskostenrechnung'; import { WalterKontaktEntry } from './WalterKontakt'; @@ -41,6 +42,7 @@ export class WalterVertragEntry extends WalterApiHandler { public mieten: WalterMieteEntry[], public mietminderungen: WalterMietminderungEntry[], public betriebskostenrechnungen: WalterBetriebskostenrechnungEntry[], + public abrechnungsresultate: WalterBetriebskostenabrechnungResultatEntry[], public permissions: WalterPermissions ) { super(); @@ -69,6 +71,8 @@ export class WalterVertragEntry extends WalterApiHandler { const permissions = json.permissions && WalterPermissions.fromJson(json.permissions); + const abrechnungsresultate = json.abrechnungsresultate; + return new WalterVertragEntry( json.id, json.beginn, @@ -85,6 +89,7 @@ export class WalterVertragEntry extends WalterApiHandler { mieten, mietminderungen, betriebskostenrechnungen, + abrechnungsresultate, permissions ); } diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/routes/(app)/abrechnung/+page.svelte b/Deeplex.Saverwalter.WebAPI/svelte/src/routes/(app)/abrechnung/+page.svelte index 57157a14..0e49ebea 100644 --- a/Deeplex.Saverwalter.WebAPI/svelte/src/routes/(app)/abrechnung/+page.svelte +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/routes/(app)/abrechnung/+page.svelte @@ -1,4 +1,4 @@ - + {#if resultat} - +

Letzter Stand dieser Abrechnung:

-
- - - - - Vorauszahlung Gesamt - Kaltmiete - Vorauszahlung Nebenkosten - Nebenkosten - Saldo - Ist versendet - Ist beglichen - - - - - - {convertEuro(resultat.vorauszahlung)} - - - {convertEuro(resultat.kaltmiete)} - - - {convertEuro( - resultat.vorauszahlung - resultat.kaltmiete - )} - - - {convertEuro(resultat.rechnungsbetrag)} - - - {convertEuro( - resultat.vorauszahlung - - resultat.kaltmiete - - resultat.rechnungsbetrag - )} - - - {resultat.abgesendet ? 'Ja' : 'Nein'} - - - {resultat.istBeglichen ? 'Ja' : 'Nein'} - - - - - + + + + + Vorauszahlung Gesamt + Kaltmiete + Vorauszahlung Nebenkosten + Nebenkosten + Saldo + Ist versendet + Ist beglichen + + + + + + {convertEuro(resultat.vorauszahlung)} + + + {convertEuro(resultat.kaltmiete)} + + + {convertEuro( + resultat.vorauszahlung - resultat.kaltmiete + )} + + + {convertEuro(resultat.rechnungsbetrag)} + + + {convertEuro( + resultat.vorauszahlung - + resultat.kaltmiete - + resultat.rechnungsbetrag + )} + + + {resultat.abgesendet ? 'Ja' : 'Nein'} + + + {resultat.istBeglichen ? 'Ja' : 'Nein'} + + + + + + {:else} Bisher keine Abrechnung erstellt {/if} diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/components/details/WalterAbrechnungsResultat.svelte b/Deeplex.Saverwalter.WebAPI/svelte/src/components/details/WalterAbrechnungsResultat.svelte new file mode 100644 index 00000000..ad9a9895 --- /dev/null +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/components/details/WalterAbrechnungsResultat.svelte @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + +
+ abgesendet(e)} + /> +
+

+ Ist diese Abrechnung an den Mieter versendet? +

+
+ + +
+ istBeglichen(e)} + /> +
+

+ Ist diese Abrechnung beglichen? +

+
+ + + + + + + + + + Abrechnung ansehen + + diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/components/lists/WalterAbrechnungsresultate.svelte b/Deeplex.Saverwalter.WebAPI/svelte/src/components/lists/WalterAbrechnungsresultate.svelte index 2645d8c2..14943c97 100644 --- a/Deeplex.Saverwalter.WebAPI/svelte/src/components/lists/WalterAbrechnungsresultate.svelte +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/components/lists/WalterAbrechnungsresultate.svelte @@ -16,7 +16,9 @@ along with this program. If not, see . - diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterAbrechnungsresultat.ts b/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterAbrechnungsresultat.ts new file mode 100644 index 00000000..5295f359 --- /dev/null +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterAbrechnungsresultat.ts @@ -0,0 +1,64 @@ +// Copyright (c) 2023-2025 Kai Lawrence +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import { WalterApiHandler } from "./WalterApiHandler"; +import { WalterPermissions } from "./WalterPermissions"; +import { WalterSelectionEntry } from "./WalterSelection"; + +export class WalterAbrechnungsresultatEntry extends WalterApiHandler { + + public static ApiURL = `/api/abrechnungsresultate`; + public static ApiURLId(id: string) { + return `${WalterAbrechnungsresultatEntry.ApiURL}/${id}`; + } + constructor( + public id: string, + public vertrag: WalterSelectionEntry, + public jahr: number, + public kaltmiete: number, + public vorauszahlung: number, + public rechnungsbetrag: number, + public minderung: number, + public abgesendet: boolean, + public istBeglichen: boolean, + public notiz: string, + public createdAt: Date, + public lastModified: Date, + public permissions: WalterPermissions + ) { + super(); + } + + static fromJson(json: WalterAbrechnungsresultatEntry) { + const vertrag = json.vertrag && WalterSelectionEntry.fromJson(json.vertrag); + const permissions = json.permissions && WalterPermissions.fromJson(json.permissions); + + return new WalterAbrechnungsresultatEntry( + json.id, + vertrag, + json.jahr, + json.kaltmiete, + json.vorauszahlung, + json.rechnungsbetrag, + json.minderung, + json.abgesendet, + json.istBeglichen, + json.notiz, + json.createdAt, + json.lastModified, + permissions + ); + } +} \ No newline at end of file diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterPermissions.ts b/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterPermissions.ts index 3a13accd..f8f37236 100644 --- a/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterPermissions.ts +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterPermissions.ts @@ -13,15 +13,12 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import { WalterApiHandler } from './WalterApiHandler'; -import { WalterMieteEntry } from './WalterMiete'; - export class WalterPermissions { constructor( public read: boolean, public update: boolean, public remove: boolean - ) {} + ) { } static fromJson(json: WalterPermissions) { return new WalterPermissions(json.read, json.update, json.remove); diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterVertrag.ts b/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterVertrag.ts index 0ff1b3c8..e9c00106 100644 --- a/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterVertrag.ts +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/lib/WalterVertrag.ts @@ -13,7 +13,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import type { WalterBetriebskostenabrechnungResultatEntry } from '$walter/types'; +import { WalterAbrechnungsresultatEntry } from './WalterAbrechnungsresultat'; import { WalterApiHandler } from './WalterApiHandler'; import { WalterBetriebskostenrechnungEntry } from './WalterBetriebskostenrechnung'; import { WalterKontaktEntry } from './WalterKontakt'; @@ -42,7 +42,7 @@ export class WalterVertragEntry extends WalterApiHandler { public mieten: WalterMieteEntry[], public mietminderungen: WalterMietminderungEntry[], public betriebskostenrechnungen: WalterBetriebskostenrechnungEntry[], - public abrechnungsresultate: WalterBetriebskostenabrechnungResultatEntry[], + public abrechnungsresultate: WalterAbrechnungsresultatEntry[], public permissions: WalterPermissions ) { super(); diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/lib/index.ts b/Deeplex.Saverwalter.WebAPI/svelte/src/lib/index.ts index bd3ae437..423842b1 100644 --- a/Deeplex.Saverwalter.WebAPI/svelte/src/lib/index.ts +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/lib/index.ts @@ -17,6 +17,7 @@ export { WalterToastContent } from './WalterToastContent'; export { WalterAccountEntry } from './WalterAccount'; export { WalterAdresseEntry } from './WalterAdresse'; export { WalterBetriebskostenrechnungEntry } from './WalterBetriebskostenrechnung'; +export { WalterAbrechnungsresultatEntry } from './WalterAbrechnungsresultat'; export { WalterErhaltungsaufwendungEntry } from './WalterErhaltungsaufwendung'; export { WalterHKVOEntry } from './WalterHKVO'; export { WalterMieteEntry } from './WalterMiete'; diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/routes/(app)/abrechnungsresultate/[id]/+page.svelte b/Deeplex.Saverwalter.WebAPI/svelte/src/routes/(app)/abrechnungsresultate/[id]/+page.svelte new file mode 100644 index 00000000..b4a17d69 --- /dev/null +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/routes/(app)/abrechnungsresultate/[id]/+page.svelte @@ -0,0 +1,28 @@ + + + + + + + + + diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/routes/(app)/abrechnungsresultate/[id]/+page.ts b/Deeplex.Saverwalter.WebAPI/svelte/src/routes/(app)/abrechnungsresultate/[id]/+page.ts new file mode 100644 index 00000000..faee17ee --- /dev/null +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/routes/(app)/abrechnungsresultate/[id]/+page.ts @@ -0,0 +1,28 @@ +// Copyright (c) 2023-2025 Kai Lawrence +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import { WalterAbrechnungsresultatEntry } from '$walter/lib'; +import type { PageLoad } from './$types'; + +export const load: PageLoad = async ({ params, fetch }) => { + const apiURL = `${WalterAbrechnungsresultatEntry.ApiURL}/${params.id}`; + return { + fetchImpl: fetch, + id: params.id, + apiURL: apiURL, + entry: WalterAbrechnungsresultatEntry.GetOne(params.id, fetch) + }; +}; + diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/services/navigation.ts b/Deeplex.Saverwalter.WebAPI/svelte/src/services/navigation.ts index db72f49a..4dc15b85 100644 --- a/Deeplex.Saverwalter.WebAPI/svelte/src/services/navigation.ts +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/services/navigation.ts @@ -16,6 +16,7 @@ import { walter_goto } from './utils'; export const navigation = { + abrechnungsresultat: (id: string) => walter_goto(`/abrechnungsresultate/${id}`), account: (id: number) => walter_goto(`/accounts/${id}`), adresse: (id: number) => walter_goto(`/adressen/${id}`), betriebskostenrechnung: (id: number) => diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/types/WalterBetriebskostenabrechnung.type.ts b/Deeplex.Saverwalter.WebAPI/svelte/src/types/WalterBetriebskostenabrechnung.type.ts index 28578b7d..9d94aa6f 100644 --- a/Deeplex.Saverwalter.WebAPI/svelte/src/types/WalterBetriebskostenabrechnung.type.ts +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/types/WalterBetriebskostenabrechnung.type.ts @@ -20,16 +20,7 @@ import type { WalterWohnungEntry, WalterZaehlerEntry } from '$walter/lib'; - -export type WalterBetriebskostenabrechnungResultatEntry = { - jahr: number; - kaltmiete: number; - vorauszahlung: number; - rechnungsbetrag: number; - minderung: number; - abgesendet: boolean; - istBeglichen: boolean; -} +import { WalterAbrechnungsresultatEntry } from '$walter/lib'; export type WalterBetriebskostenabrechnungEntry = { notes: WalterBetriebskostenabrechnungNote[]; @@ -51,7 +42,7 @@ export type WalterBetriebskostenabrechnungEntry = { wohnungen: WalterWohnungEntry[]; vertraege: WalterVertragEntry[]; mieten: WalterMieteEntry[]; - resultat?: WalterBetriebskostenabrechnungResultatEntry; + resultat?: WalterAbrechnungsresultatEntry; }; export type WalterBetriebskostenabrechnungNote = { diff --git a/Deeplex.Saverwalter.WebAPI/svelte/src/types/index.ts b/Deeplex.Saverwalter.WebAPI/svelte/src/types/index.ts index 321a019b..b902a8fc 100644 --- a/Deeplex.Saverwalter.WebAPI/svelte/src/types/index.ts +++ b/Deeplex.Saverwalter.WebAPI/svelte/src/types/index.ts @@ -17,7 +17,6 @@ export { type WalterBetriebskostenabrechnungEntry, type WalterRechnungEntry, type WalterAbrechnungseinheit, - type WalterBetriebskostenabrechnungResultatEntry } from './WalterBetriebskostenabrechnung.type'; export { type WalterToast } from './WalterToast.type'; export { type WalterModalControl } from './WalterModalControl';