diff --git a/omsorgCore/CLAUDE.md b/omsorgCore/CLAUDE.md index c364fd1..93e418c 100644 --- a/omsorgCore/CLAUDE.md +++ b/omsorgCore/CLAUDE.md @@ -164,7 +164,7 @@ Vollständig implementiert: `PasswordResetCode`-Entity + `PasswordResetService` - Connection-String-Key: `ConnectionStrings:OmsorgCore` (Format `Host=...;Port=5432;Database=omsorg_core;Username=...;Password=...`). - `dotnet-ef` ist als lokales Tool eingerichtet (`.config/dotnet-tools.json`) — vor erster Nutzung `dotnet tool restore`. Wird nur noch zum **Erzeugen** neuer Migrationen gebraucht (`dotnet ef migrations add ...`), nicht mehr zum Anwenden. - **`Program.cs` ruft bei jedem Start `db.Database.MigrateAsync()` auf, in jeder Umgebung** (nicht nur Development) — ausstehende Migrationen werden automatisch angewendet, bevor der Server Requests annimmt. Ein manuelles `dotnet ef database update` ist dadurch nur noch zum gezielten Vorab-Prüfen/Debuggen einer Migration nötig, nicht mehr für den normalen Start/Deploy. Schlägt die Migration fehl, crasht der Start bewusst fatal (fail-fast) statt mit einem veralteten Schema weiterzulaufen. -- Migrationen `InitialCreate`, `AddRefreshTokens`, `AddUserSecurityStamp`, `AddEmployeeContactFieldConstraints` und `AddAuditableSoftDelete` existieren (`src/OmsorgCore.Infrastructure/Persistence/Migrations/`) und wurden erfolgreich gegen eine echte PostgreSQL-Instanz angewendet. `AddContractDetailsAndQueryFilter` ist erzeugt, aber noch nicht gegen eine echte Instanz verifiziert (wird beim nächsten API-Start automatisch angewendet). `AddPermissionScope` (fügt `Scope` auf `role_permissions`/`user_permission_overrides` hinzu, siehe "Rechtesystem") wurde per `dotnet ef database update` erfolgreich gegen die echte Instanz angewendet. `AddFacilityConditionsAndQualificationRates` (Konditionen-Felder auf `Facility` + Tabelle `facility_qualification_rates`, FR-EIN-4), `AddAbsences` (Tabelle `absences`, FR-CON-1/FR-EM-3) und `AddTimeEntryStatusAndSurchargeHours` (`TimeEntry.StatusId`+Zuschlagsstunden, `ValueListItem.IsEditableByOwner`, `ValueListItemTransition.RequiresApproval`, FR-ZE-1/FR-ZE-2) wurden beim automatischen API-Start erfolgreich gegen die echte Instanz angewendet. `AddTravelCostModeAndEmployeeFacilityDistances` (`Facility.TravelCostMode`/`TravelCostPerKm` + Tabelle `employee_facility_distances`, siehe "Konditionen einer Einrichtung") ist erzeugt (`dotnet build`/`dotnet test` grün), aber noch nicht gegen eine echte Instanz verifiziert. +- Migrationen `InitialCreate`, `AddRefreshTokens`, `AddUserSecurityStamp`, `AddEmployeeContactFieldConstraints` und `AddAuditableSoftDelete` existieren (`src/OmsorgCore.Infrastructure/Persistence/Migrations/`) und wurden erfolgreich gegen eine echte PostgreSQL-Instanz angewendet. `AddContractDetailsAndQueryFilter` ist erzeugt, aber noch nicht gegen eine echte Instanz verifiziert (wird beim nächsten API-Start automatisch angewendet). `AddPermissionScope` (fügt `Scope` auf `role_permissions`/`user_permission_overrides` hinzu, siehe "Rechtesystem") wurde per `dotnet ef database update` erfolgreich gegen die echte Instanz angewendet. `AddFacilityConditionsAndQualificationRates` (Konditionen-Felder auf `Facility` + Tabelle `facility_qualification_rates`, FR-EIN-4), `AddAbsences` (Tabelle `absences`, FR-CON-1/FR-EM-3) und `AddTimeEntryStatusAndSurchargeHours` (`TimeEntry.StatusId`+Zuschlagsstunden, `ValueListItem.IsEditableByOwner`, `ValueListItemTransition.RequiresApproval`, FR-ZE-1/FR-ZE-2) wurden beim automatischen API-Start erfolgreich gegen die echte Instanz angewendet. `AddTravelCostModeAndEmployeeFacilityDistances` (`Facility.TravelCostMode`/`TravelCostPerKm` + Tabelle `employee_facility_distances`, siehe "Konditionen einer Einrichtung") und `RemoveFacilityBreakPolicy` (löscht die Spalte `BreakPolicy` von `facilities` wieder) sind erzeugt (`dotnet build`/`dotnet test` grün), aber noch nicht gegen eine echte Instanz verifiziert. ## Build- und Run-Befehle @@ -233,14 +233,14 @@ Dropdown-Werte, die früher als hartcodierte Arrays im `omsorgapp`-Frontend lebt ## Konditionen einer Einrichtung (FR-EIN-4) -Elf der zwölf Blueprint-19.2-Konditionsfelder (Verrechnungssatz, vier Zuschläge, Fahrtkosten, Mindeststunden, Pausenregelung, Abrechnungsintervall, Zahlungsziel, individuelle Vereinbarungen) sind flache, nullable Felder direkt auf `Facility` — kein `OwnsOne`/keine eigene Tabelle, analog zu Adresse/Rechnungsadresse auf `Facility` selbst und den Finanzfeldern auf `Contract`: +Zehn der zwölf Blueprint-19.2-Konditionsfelder (Verrechnungssatz, vier Zuschläge, Fahrtkosten, Mindeststunden, Abrechnungsintervall, Zahlungsziel, individuelle Vereinbarungen) sind flache, nullable Felder direkt auf `Facility` — kein `OwnsOne`/keine eigene Tabelle, analog zu Adresse/Rechnungsadresse auf `Facility` selbst und den Finanzfeldern auf `Contract`. **Pausenregelung wurde am 2026-08-10 wieder entfernt** (fachlich nicht gebraucht, `BreakPolicy` auf `Facility`/`UpdateFacilityRequest`/`FacilityResponse` gelöscht, Migration `RemoveFacilityBreakPolicy`, beide generierten Clients neu erzeugt, `FacilityForm.jsx`/`FacilityDetailPanel.jsx` bereinigt) — falls sie doch wieder gebraucht wird, ist das ein Neuanlegen, kein Wiederherstellen (Hard-Delete der Spalte, kein Soft-Delete-Konzept für Schema-Felder): -- `BillingRate` (Verrechnungssatz, EUR/Std.), `NightSurchargePercent`/`SaturdaySurchargePercent`/`SundaySurchargePercent`/`HolidaySurchargePercent` (Zuschläge als **Prozent** auf den Verrechnungssatz, nicht als EUR-Betrag), `MinimumHours` (Mindeststunden je Einsatz), `BreakPolicy` (Pausenregelung, Freitext), `PaymentTermDays` (Zahlungsziel in Tagen), `IndividualAgreements` (Freitext). +- `BillingRate` (Verrechnungssatz, EUR/Std.), `NightSurchargePercent`/`SaturdaySurchargePercent`/`SundaySurchargePercent`/`HolidaySurchargePercent` (Zuschläge als **Prozent** auf den Verrechnungssatz, nicht als EUR-Betrag), `MealAllowanceRate` (Verpflegungsmehraufwand, EUR-Pauschale je Einsatz — bewusst kein tageweises/gesetzliches Stufenmodell wie beim echten VMA, sondern wie `TravelCostRate` ein einziger fixer Betrag je Einrichtung), `MinimumHours` (Mindeststunden je Einsatz), `PaymentTermDays` (Zahlungsziel in Tagen), `IndividualAgreements` (Freitext). - **Fahrtkosten (seit 2026-08-10 zwei Modi statt nur Pauschale):** `TravelCostMode` (`"Pauschale"` oder `"ProKilometer"`, Default `"Pauschale"`, im Controller gegen ein festes Literal-Array geprüft — **bewusst keine `ValueList`**, da die Rechnungserstellung später hart zwischen genau diesen zwei Fällen unterscheiden muss, ein dritter admin-hinzufügbarer Wert würde die künftige `FR-RE-1`-Berechnungslogik lautlos brechen, analog zur Begründung bei `AbsenceStatus.IsInitial`) entscheidet, welches Feld gilt: `TravelCostRate` (Pauschale je Einsatz, EUR) oder `TravelCostPerKm` (EUR/km) × `EmployeeFacilityDistance.DistanceKm`. Eine feste Facility-Distanz reicht nicht, weil jeder Mitarbeiter von einem anderen Wohnort anfährt — daher `EmployeeFacilityDistance` (`Facility`×`Employee` → `DistanceKm`, `AuditableEntity`) als **zweite** 1:n-Unterressource von Facility, exakt nach dem `FacilityQualificationRate`-Muster: `GET/POST/PUT/DELETE /api/facilities/{facilityId}/employee-distances[/...]` (`EmployeeFacilityDistancesController`), gegated über dieselben `Facilities`-Rechte, kein eigener `ModuleType`. `Create` validiert zusätzlich, dass `EmployeeId` auf einen existierenden Mitarbeiter zeigt (`IEmployeeService.GetByIdAsync`) und dass für das Facility/Employee-Paar noch keine (nicht gelöschte) Distanz existiert. Soft-Delete, über `TrashController` (`api/trash/employee-facility-distances/...`) wiederherstellbar. - **Selbstbedienung durch den Außendienst (seit 2026-08-10, `MyFacilityDistancesController`, Route `api/me/facility-distances`):** Mitarbeiter sollen ihre eigene Fahrtstrecke selbst über `omsorgWeb/mitarbeiter-app` pflegen können, statt dass das Büro jede Kilometerangabe manuell einträgt. Dafür bewusst **kein** `Facilities`-Recht (das würde Konditionen/CRM-Daten offenlegen, die dem Außendienst laut Rechtematrix nicht zustehen), sondern ein neuer, eigenständiger `ModuleType.EmployeeFacilityDistances` (siehe "Rechtesystem" oben) — `GET /api/me/facility-distances` (eigene Distanzen inkl. `FacilityName`), `GET /api/me/facility-distances/facilities` (minimale Einrichtungsauswahl, nur `Id`/`Name` über `FacilityOptionResponse`, für das Formular-Dropdown), `POST`/`PUT` (Anlegen/Bearbeiten). `EmployeeId` kommt bei jeder Aktion ausschließlich aus `ICurrentUserService.EmployeeId` (JWT-Claim), nie vom Client — bei fehlender Verknüpfung `400` statt eines FK-Fehlers, analog zum `AbsenceService.CreateAsync`-Fallback. Bewusst **kein** `DELETE` hier (Löschen bleibt Büro-Aufgabe über den Papierkorb). Nutzt intern denselben `IEmployeeFacilityDistanceService`/dieselbe Tabelle wie `EmployeeFacilityDistancesController` — zwei Controller auf demselben Application-Service, unterschiedliche Zugriffsrechte, kein Datenmodell-Unterschied. -- **Zugleich behobener Bestandsfehler:** `FacilityService.UpdateAsync` kopierte die elf Konditionsfelder bislang gar nicht auf die getrackte Entität — der Controller validierte sie korrekt, aber `PUT /api/facilities/{id}` verwarf sie stillschweigend (kein Fehler, kein Log, das Feld blieb einfach `null`/unverändert). Betraf `BillingRate`/alle vier Zuschläge/`TravelCostRate`/`MinimumHours`/`BreakPolicy`/`BillingInterval`/`PaymentTermDays`/`IndividualAgreements` seit deren Einführung. Jetzt behoben, Regressionstest: `FacilityServiceTests.UpdateAsync_PersistsKonditionenFields`. +- **Zugleich behobener Bestandsfehler:** `FacilityService.UpdateAsync` kopierte die elf Konditionsfelder bislang gar nicht auf die getrackte Entität — der Controller validierte sie korrekt, aber `PUT /api/facilities/{id}` verwarf sie stillschweigend (kein Fehler, kein Log, das Feld blieb einfach `null`/unverändert). Betraf `BillingRate`/alle vier Zuschläge/`TravelCostRate`/`MinimumHours`/`BillingInterval`/`PaymentTermDays`/`IndividualAgreements` seit deren Einführung (damals inkl. `BreakPolicy`, seit 2026-08-10 entfernt, siehe oben). Jetzt behoben, Regressionstest: `FacilityServiceTests.UpdateAsync_PersistsKonditionenFields`. - `BillingInterval` wird wie `FacilityType`/`ContractType` gegen die admin-editierbare `ValueList` `"BillingInterval"` (Wöchentlich/Monatlich/Quartalsweise) validiert — siehe "Konfigurierbare Auswahllisten". -- Alle elf Felder sind nur über `PUT /api/facilities/{id}` (`UpdateFacilityRequest`) setzbar, nicht beim Anlegen (`CreateFacilityRequest`) — analog zu `CrmStatus`, der ebenfalls erst nach dem Anlegen über "Bearbeiten" gepflegt wird. +- Alle zwölf Felder sind nur über `PUT /api/facilities/{id}` (`UpdateFacilityRequest`) setzbar, nicht beim Anlegen (`CreateFacilityRequest`) — analog zu `CrmStatus`, der ebenfalls erst nach dem Anlegen über "Bearbeiten" gepflegt wird. **Ausnahme "Qualifikationsabhängige Preise":** eine variable Liste (ein Satz je Qualifikationsstufe) lässt sich nicht als feste Spaltengruppe abbilden — dafür die neue Entität `FacilityQualificationRate` (1:n zu `Facility`, `Qualification` gegen die ValueList `"Qualification"` validiert — dieselbe Liste wie `Employee.Qualification`/`Order.RequiredQualification`, siehe "Wo welches Feld referenziert wird" oben) als 1:n-Unterressource unter `GET/POST/PUT/DELETE /api/facilities/{facilityId}/qualification-rates[/...]` (`FacilityQualificationRatesController`) — exakt nach dem Muster von `FacilityContact`, kein eigener `ModuleType`, gegated über dieselben `Facilities`-Rechte. Löschen ist Soft-Delete, über `TrashController` (`api/trash/facility-qualification-rates/...`) wiederherstellbar. diff --git a/omsorgCore/src/OmsorgCore.Api/Contracts/FacilityResponse.cs b/omsorgCore/src/OmsorgCore.Api/Contracts/FacilityResponse.cs index e06e2cc..dd31ae5 100644 --- a/omsorgCore/src/OmsorgCore.Api/Contracts/FacilityResponse.cs +++ b/omsorgCore/src/OmsorgCore.Api/Contracts/FacilityResponse.cs @@ -23,8 +23,8 @@ public record FacilityResponse( decimal? TravelCostRate, string TravelCostMode, decimal? TravelCostPerKm, + decimal? MealAllowanceRate, decimal? MinimumHours, - string? BreakPolicy, string? BillingInterval, int? PaymentTermDays, string? IndividualAgreements); diff --git a/omsorgCore/src/OmsorgCore.Api/Contracts/UpdateFacilityRequest.cs b/omsorgCore/src/OmsorgCore.Api/Contracts/UpdateFacilityRequest.cs index 3918e9e..e73f260 100644 --- a/omsorgCore/src/OmsorgCore.Api/Contracts/UpdateFacilityRequest.cs +++ b/omsorgCore/src/OmsorgCore.Api/Contracts/UpdateFacilityRequest.cs @@ -22,8 +22,8 @@ public record UpdateFacilityRequest( decimal? TravelCostRate, string TravelCostMode, decimal? TravelCostPerKm, + decimal? MealAllowanceRate, decimal? MinimumHours, - string? BreakPolicy, string? BillingInterval, int? PaymentTermDays, string? IndividualAgreements); diff --git a/omsorgCore/src/OmsorgCore.Api/Controllers/FacilitiesController.cs b/omsorgCore/src/OmsorgCore.Api/Controllers/FacilitiesController.cs index e6aeb22..1ba2fcd 100644 --- a/omsorgCore/src/OmsorgCore.Api/Controllers/FacilitiesController.cs +++ b/omsorgCore/src/OmsorgCore.Api/Controllers/FacilitiesController.cs @@ -202,11 +202,6 @@ public class FacilitiesController : ControllerBase return BadRequest(billingAddressError); } - if (request.BreakPolicy is { Length: > 1000 }) - { - return BadRequest("BreakPolicy darf maximal 1000 Zeichen lang sein."); - } - if (request.IndividualAgreements is { Length: > 2000 }) { return BadRequest("IndividualAgreements darf maximal 2000 Zeichen lang sein."); @@ -224,6 +219,7 @@ public class FacilitiesController : ControllerBase if (request.BillingRate is < 0 || request.TravelCostRate is < 0 || request.TravelCostPerKm is < 0 + || request.MealAllowanceRate is < 0 || request.MinimumHours is < 0 || request.NightSurchargePercent is < 0 || request.SaturdaySurchargePercent is < 0 @@ -252,8 +248,8 @@ public class FacilitiesController : ControllerBase TravelCostRate = request.TravelCostRate, TravelCostMode = request.TravelCostMode, TravelCostPerKm = request.TravelCostPerKm, + MealAllowanceRate = request.MealAllowanceRate, MinimumHours = request.MinimumHours, - BreakPolicy = request.BreakPolicy, BillingInterval = request.BillingInterval, PaymentTermDays = request.PaymentTermDays, IndividualAgreements = request.IndividualAgreements, @@ -330,8 +326,8 @@ public class FacilitiesController : ControllerBase facility.TravelCostRate, facility.TravelCostMode, facility.TravelCostPerKm, + facility.MealAllowanceRate, facility.MinimumHours, - facility.BreakPolicy, facility.BillingInterval, facility.PaymentTermDays, facility.IndividualAgreements); diff --git a/omsorgCore/src/OmsorgCore.Application/Services/FacilityService.cs b/omsorgCore/src/OmsorgCore.Application/Services/FacilityService.cs index f2e3842..8ffa14b 100644 --- a/omsorgCore/src/OmsorgCore.Application/Services/FacilityService.cs +++ b/omsorgCore/src/OmsorgCore.Application/Services/FacilityService.cs @@ -63,8 +63,8 @@ public class FacilityService : IFacilityService facility.TravelCostRate = updates.TravelCostRate; facility.TravelCostMode = updates.TravelCostMode; facility.TravelCostPerKm = updates.TravelCostPerKm; + facility.MealAllowanceRate = updates.MealAllowanceRate; facility.MinimumHours = updates.MinimumHours; - facility.BreakPolicy = updates.BreakPolicy; facility.BillingInterval = updates.BillingInterval; facility.PaymentTermDays = updates.PaymentTermDays; facility.IndividualAgreements = updates.IndividualAgreements; diff --git a/omsorgCore/src/OmsorgCore.Domain/Entities/Facility.cs b/omsorgCore/src/OmsorgCore.Domain/Entities/Facility.cs index ae85fe3..e4f5e40 100644 --- a/omsorgCore/src/OmsorgCore.Domain/Entities/Facility.cs +++ b/omsorgCore/src/OmsorgCore.Domain/Entities/Facility.cs @@ -39,8 +39,8 @@ public class Facility : AuditableEntity public string TravelCostMode { get; set; } = "Pauschale"; public decimal? TravelCostRate { get; set; } public decimal? TravelCostPerKm { get; set; } + public decimal? MealAllowanceRate { get; set; } public decimal? MinimumHours { get; set; } - public string? BreakPolicy { get; set; } public string? BillingInterval { get; set; } public int? PaymentTermDays { get; set; } public string? IndividualAgreements { get; set; } diff --git a/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Configurations/FacilityConfiguration.cs b/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Configurations/FacilityConfiguration.cs index 69ba559..6ff5fa8 100644 --- a/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Configurations/FacilityConfiguration.cs +++ b/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Configurations/FacilityConfiguration.cs @@ -31,8 +31,8 @@ public class FacilityConfiguration : IEntityTypeConfiguration builder.Property(f => f.TravelCostRate).HasColumnType("decimal(10,2)"); builder.Property(f => f.TravelCostMode).IsRequired().HasMaxLength(20); builder.Property(f => f.TravelCostPerKm).HasColumnType("decimal(10,2)"); + builder.Property(f => f.MealAllowanceRate).HasColumnType("decimal(10,2)"); builder.Property(f => f.MinimumHours).HasColumnType("decimal(5,2)"); - builder.Property(f => f.BreakPolicy).HasMaxLength(1000); builder.Property(f => f.BillingInterval).HasMaxLength(50); builder.Property(f => f.IndividualAgreements).HasMaxLength(2000); diff --git a/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Migrations/20260810183932_AddFacilityMealAllowanceRate.Designer.cs b/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Migrations/20260810183932_AddFacilityMealAllowanceRate.Designer.cs new file mode 100644 index 0000000..a2e9743 --- /dev/null +++ b/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Migrations/20260810183932_AddFacilityMealAllowanceRate.Designer.cs @@ -0,0 +1,1391 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using OmsorgCore.Infrastructure.Persistence; + +#nullable disable + +namespace OmsorgCore.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(OmsorgCoreDbContext))] + [Migration("20260810183932_AddFacilityMealAllowanceRate")] + partial class AddFacilityMealAllowanceRate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.10") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Absence", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdminNote") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EmployeeId") + .HasColumnType("uuid"); + + b.Property("EndDate") + .HasColumnType("date"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("Note") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Reason") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("StartDate") + .HasColumnType("date"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Substitute") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.ToTable("absences", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.AuditLogEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Action") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ActorUserId") + .HasColumnType("uuid"); + + b.Property("ActorUsername") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Category") + .HasColumnType("integer"); + + b.Property("Details") + .HasColumnType("jsonb"); + + b.Property("EntityId") + .HasColumnType("uuid"); + + b.Property("EntityType") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("IpAddress") + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("OccurredAtUtc") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("ActorUserId"); + + b.HasIndex("OccurredAtUtc"); + + b.HasIndex("EntityType", "EntityId"); + + b.ToTable("audit_log_entries", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Contract", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AllowancesDescription") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("ContractType") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EmployeeId") + .HasColumnType("uuid"); + + b.Property("EndDate") + .HasColumnType("date"); + + b.Property("FacilityId") + .HasColumnType("uuid"); + + b.Property("HourlyWage") + .HasPrecision(10, 2) + .HasColumnType("numeric(10,2)"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("OvertimeRules") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("ProbationPeriodMonths") + .HasColumnType("integer"); + + b.Property("StartDate") + .HasColumnType("date"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("VacationDaysPerYear") + .HasColumnType("integer"); + + b.Property("WeeklyHours") + .HasPrecision(10, 2) + .HasColumnType("numeric(10,2)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("FacilityId"); + + b.ToTable("contracts", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Document", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Category") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ContentType") + .IsRequired() + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("EntityId") + .HasColumnType("uuid"); + + b.Property("EntityType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(260) + .HasColumnType("character varying(260)"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("SizeBytes") + .HasColumnType("bigint"); + + b.Property("StorageKey") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UploadedByUserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UploadedByUserId"); + + b.HasIndex("EntityType", "EntityId"); + + b.ToTable("documents", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Employee", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AvatarFileName") + .HasColumnType("text"); + + b.Property("City") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Country") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DateOfBirth") + .HasColumnType("date"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("EmergencyContactName") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("EmergencyContactPhone") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("EmergencyContactRelation") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("EmploymentType") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("EntryDate") + .HasColumnType("date"); + + b.Property("ExitDate") + .HasColumnType("date"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("PhoneNumber") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Qualification") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Street") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("employees", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.EmployeeFacilityDistance", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DistanceKm") + .HasColumnType("decimal(10,2)"); + + b.Property("EmployeeId") + .HasColumnType("uuid"); + + b.Property("FacilityId") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("FacilityId"); + + b.ToTable("employee_facility_distances", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Facility", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BillingCity") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("BillingCountry") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("BillingInterval") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BillingPostalCode") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("BillingRate") + .HasColumnType("decimal(10,2)"); + + b.Property("BillingStreet") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("City") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Country") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CrmStatus") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FacilityType") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("FollowUpDueDate") + .HasColumnType("timestamp with time zone"); + + b.Property("HolidaySurchargePercent") + .HasColumnType("decimal(5,2)"); + + b.Property("IndividualAgreements") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("MealAllowanceRate") + .HasColumnType("decimal(10,2)"); + + b.Property("MinimumHours") + .HasColumnType("decimal(5,2)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("NightSurchargePercent") + .HasColumnType("decimal(5,2)"); + + b.Property("PaymentTermDays") + .HasColumnType("integer"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("SaturdaySurchargePercent") + .HasColumnType("decimal(5,2)"); + + b.Property("Street") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("SundaySurchargePercent") + .HasColumnType("decimal(5,2)"); + + b.Property("TravelCostMode") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.Property("TravelCostPerKm") + .HasColumnType("decimal(10,2)"); + + b.Property("TravelCostRate") + .HasColumnType("decimal(10,2)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Website") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.HasKey("Id"); + + b.ToTable("facilities", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.FacilityContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Department") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Email") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("FacilityId") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Notes") + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("PhoneNumber") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Role") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("FacilityId"); + + b.ToTable("facility_contacts", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.FacilityQualificationRate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("FacilityId") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("Qualification") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Rate") + .HasColumnType("decimal(10,2)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("FacilityId"); + + b.ToTable("facility_qualification_rates", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Invoice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("BillingPeriodEnd") + .HasColumnType("date"); + + b.Property("BillingPeriodStart") + .HasColumnType("date"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DueDate") + .HasColumnType("date"); + + b.Property("FacilityId") + .HasColumnType("uuid"); + + b.Property("GrossAmount") + .HasColumnType("numeric(12,2)"); + + b.Property("InvoiceNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("NetAmount") + .HasColumnType("numeric(12,2)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("FacilityId"); + + b.HasIndex("InvoiceNumber") + .IsUnique(); + + b.ToTable("invoices", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.LoginAttempt", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttemptedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IpAddress") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("character varying(64)"); + + b.Property("Succeeded") + .HasColumnType("boolean"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("IpAddress", "AttemptedAt"); + + b.ToTable("login_attempts", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Conditions") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EndDate") + .HasColumnType("date"); + + b.Property("FacilityContactId") + .HasColumnType("uuid"); + + b.Property("FacilityId") + .HasColumnType("uuid"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("Priority") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("RequiredHeadcount") + .HasColumnType("integer"); + + b.Property("RequiredQualification") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ShiftType") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("StartDate") + .HasColumnType("date"); + + b.Property("StatusId") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("FacilityContactId"); + + b.HasIndex("FacilityId"); + + b.HasIndex("StatusId"); + + b.ToTable("orders", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.PasswordResetCode", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttemptCount") + .HasColumnType("integer"); + + b.Property("CodeHash") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ConsumedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("InvalidatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ResetTokenExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ResetTokenHash") + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("ResetTokenUsedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ResetTokenHash"); + + b.HasIndex("UserId"); + + b.ToTable("password_reset_codes", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ReplacedByTokenId") + .HasColumnType("uuid"); + + b.Property("RevokedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("TokenHash") + .IsRequired() + .HasMaxLength(128) + .HasColumnType("character varying(128)"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ReplacedByTokenId"); + + b.HasIndex("TokenHash") + .IsUnique(); + + b.HasIndex("UserId"); + + b.ToTable("refresh_tokens", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("roles", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.RolePermission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Action") + .HasColumnType("integer"); + + b.Property("Module") + .HasColumnType("integer"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("Scope") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("RoleId", "Module", "Action") + .IsUnique(); + + b.ToTable("role_permissions", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.TimeEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AdminNote") + .HasMaxLength(500) + .HasColumnType("character varying(500)"); + + b.Property("BreakDuration") + .HasColumnType("interval"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Date") + .HasColumnType("date"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EmployeeId") + .HasColumnType("uuid"); + + b.Property("End") + .HasColumnType("time without time zone"); + + b.Property("HolidayHours") + .HasColumnType("numeric(6,2)"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("NightHours") + .HasColumnType("numeric(6,2)"); + + b.Property("OrderId") + .HasColumnType("uuid"); + + b.Property("SaturdayHours") + .HasColumnType("numeric(6,2)"); + + b.Property("Start") + .HasColumnType("time without time zone"); + + b.Property("StatusId") + .HasColumnType("uuid"); + + b.Property("SundayHours") + .HasColumnType("numeric(6,2)"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("OrderId"); + + b.HasIndex("StatusId"); + + b.ToTable("time_entries", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("EmployeeId") + .HasColumnType("uuid"); + + b.Property("IsActive") + .HasColumnType("boolean"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("MustChangePassword") + .HasColumnType("boolean"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("SecurityStamp") + .HasColumnType("uuid"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("Id"); + + b.HasIndex("EmployeeId"); + + b.HasIndex("RoleId"); + + b.HasIndex("Username") + .IsUnique(); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.UserPermissionOverride", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Action") + .HasColumnType("integer"); + + b.Property("Effect") + .HasColumnType("integer"); + + b.Property("Module") + .HasColumnType("integer"); + + b.Property("Scope") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId", "Module", "Action") + .IsUnique(); + + b.ToTable("user_permission_overrides", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.ValueList", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DisplayName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("Key") + .IsUnique(); + + b.ToTable("value_lists", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.ValueListItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsDefault") + .HasColumnType("boolean"); + + b.Property("IsEditableByOwner") + .HasColumnType("boolean"); + + b.Property("IsInitial") + .HasColumnType("boolean"); + + b.Property("IsTerminal") + .HasColumnType("boolean"); + + b.Property("SortOrder") + .HasColumnType("integer"); + + b.Property("TriggersFollowUp") + .HasColumnType("boolean"); + + b.Property("Value") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ValueListId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ValueListId", "Value") + .IsUnique(); + + b.ToTable("value_list_items", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.ValueListItemTransition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("FromItemId") + .HasColumnType("uuid"); + + b.Property("RequiresApproval") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true); + + b.Property("ToItemId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ToItemId"); + + b.HasIndex("FromItemId", "ToItemId") + .IsUnique(); + + b.ToTable("value_list_item_transitions", (string)null); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Absence", b => + { + b.HasOne("OmsorgCore.Domain.Entities.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Employee"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Contract", b => + { + b.HasOne("OmsorgCore.Domain.Entities.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("OmsorgCore.Domain.Entities.Facility", "Facility") + .WithMany() + .HasForeignKey("FacilityId") + .OnDelete(DeleteBehavior.Restrict); + + b.Navigation("Employee"); + + b.Navigation("Facility"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Document", b => + { + b.HasOne("OmsorgCore.Domain.Entities.User", "UploadedByUser") + .WithMany() + .HasForeignKey("UploadedByUserId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("UploadedByUser"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.EmployeeFacilityDistance", b => + { + b.HasOne("OmsorgCore.Domain.Entities.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("OmsorgCore.Domain.Entities.Facility", "Facility") + .WithMany() + .HasForeignKey("FacilityId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Facility"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.FacilityContact", b => + { + b.HasOne("OmsorgCore.Domain.Entities.Facility", "Facility") + .WithMany() + .HasForeignKey("FacilityId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Facility"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.FacilityQualificationRate", b => + { + b.HasOne("OmsorgCore.Domain.Entities.Facility", "Facility") + .WithMany() + .HasForeignKey("FacilityId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Facility"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Invoice", b => + { + b.HasOne("OmsorgCore.Domain.Entities.Facility", "Facility") + .WithMany() + .HasForeignKey("FacilityId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Facility"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Order", b => + { + b.HasOne("OmsorgCore.Domain.Entities.FacilityContact", "FacilityContact") + .WithMany() + .HasForeignKey("FacilityContactId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("OmsorgCore.Domain.Entities.Facility", "Facility") + .WithMany() + .HasForeignKey("FacilityId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("OmsorgCore.Domain.Entities.ValueListItem", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Facility"); + + b.Navigation("FacilityContact"); + + b.Navigation("Status"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.PasswordResetCode", b => + { + b.HasOne("OmsorgCore.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.RefreshToken", b => + { + b.HasOne("OmsorgCore.Domain.Entities.RefreshToken", null) + .WithMany() + .HasForeignKey("ReplacedByTokenId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("OmsorgCore.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.RolePermission", b => + { + b.HasOne("OmsorgCore.Domain.Entities.Role", "Role") + .WithMany("RolePermissions") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.TimeEntry", b => + { + b.HasOne("OmsorgCore.Domain.Entities.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("OmsorgCore.Domain.Entities.Order", "Order") + .WithMany() + .HasForeignKey("OrderId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("OmsorgCore.Domain.Entities.ValueListItem", "Status") + .WithMany() + .HasForeignKey("StatusId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Order"); + + b.Navigation("Status"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.User", b => + { + b.HasOne("OmsorgCore.Domain.Entities.Employee", "Employee") + .WithMany() + .HasForeignKey("EmployeeId") + .OnDelete(DeleteBehavior.SetNull); + + b.HasOne("OmsorgCore.Domain.Entities.Role", "Role") + .WithMany("Users") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("Employee"); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.UserPermissionOverride", b => + { + b.HasOne("OmsorgCore.Domain.Entities.User", "User") + .WithMany("PermissionOverrides") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.ValueListItem", b => + { + b.HasOne("OmsorgCore.Domain.Entities.ValueList", "ValueList") + .WithMany("Items") + .HasForeignKey("ValueListId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("ValueList"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.ValueListItemTransition", b => + { + b.HasOne("OmsorgCore.Domain.Entities.ValueListItem", "FromItem") + .WithMany() + .HasForeignKey("FromItemId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.HasOne("OmsorgCore.Domain.Entities.ValueListItem", "ToItem") + .WithMany() + .HasForeignKey("ToItemId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("FromItem"); + + b.Navigation("ToItem"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.Role", b => + { + b.Navigation("RolePermissions"); + + b.Navigation("Users"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.User", b => + { + b.Navigation("PermissionOverrides"); + }); + + modelBuilder.Entity("OmsorgCore.Domain.Entities.ValueList", b => + { + b.Navigation("Items"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Migrations/20260810183932_AddFacilityMealAllowanceRate.cs b/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Migrations/20260810183932_AddFacilityMealAllowanceRate.cs new file mode 100644 index 0000000..21c7bf9 --- /dev/null +++ b/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Migrations/20260810183932_AddFacilityMealAllowanceRate.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace OmsorgCore.Infrastructure.Persistence.Migrations +{ + /// + public partial class AddFacilityMealAllowanceRate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "MealAllowanceRate", + table: "facilities", + type: "numeric(10,2)", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "MealAllowanceRate", + table: "facilities"); + } + } +} diff --git a/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Migrations/OmsorgCoreDbContextModelSnapshot.cs b/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Migrations/OmsorgCoreDbContextModelSnapshot.cs index 5adfb65..12c457f 100644 --- a/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Migrations/OmsorgCoreDbContextModelSnapshot.cs +++ b/omsorgCore/src/OmsorgCore.Infrastructure/Persistence/Migrations/OmsorgCoreDbContextModelSnapshot.cs @@ -426,10 +426,6 @@ namespace OmsorgCore.Infrastructure.Persistence.Migrations .HasMaxLength(200) .HasColumnType("character varying(200)"); - b.Property("BreakPolicy") - .HasMaxLength(1000) - .HasColumnType("character varying(1000)"); - b.Property("City") .HasMaxLength(100) .HasColumnType("character varying(100)"); @@ -466,6 +462,9 @@ namespace OmsorgCore.Infrastructure.Persistence.Migrations b.Property("IsDeleted") .HasColumnType("boolean"); + b.Property("MealAllowanceRate") + .HasColumnType("decimal(10,2)"); + b.Property("MinimumHours") .HasColumnType("decimal(5,2)"); diff --git a/omsorgCore/tests/OmsorgCore.Tests/Services/FacilityServiceTests.cs b/omsorgCore/tests/OmsorgCore.Tests/Services/FacilityServiceTests.cs index 4d73433..ed1ea00 100644 --- a/omsorgCore/tests/OmsorgCore.Tests/Services/FacilityServiceTests.cs +++ b/omsorgCore/tests/OmsorgCore.Tests/Services/FacilityServiceTests.cs @@ -103,8 +103,8 @@ public class FacilityServiceTests TravelCostMode = "ProKilometer", TravelCostRate = 10, TravelCostPerKm = 0.42m, + MealAllowanceRate = 14, MinimumHours = 4, - BreakPolicy = "30 Min. ab 6 Std.", BillingInterval = "Monatlich", PaymentTermDays = 14, IndividualAgreements = "Sonderkonditionen Wochenende" @@ -121,8 +121,8 @@ public class FacilityServiceTests Assert.Equal("ProKilometer", updated.TravelCostMode); Assert.Equal(10, updated.TravelCostRate); Assert.Equal(0.42m, updated.TravelCostPerKm); + Assert.Equal(14, updated.MealAllowanceRate); Assert.Equal(4, updated.MinimumHours); - Assert.Equal("30 Min. ab 6 Std.", updated.BreakPolicy); Assert.Equal("Monatlich", updated.BillingInterval); Assert.Equal(14, updated.PaymentTermDays); Assert.Equal("Sonderkonditionen Wochenende", updated.IndividualAgreements); diff --git a/omsorgWeb/mitarbeiter-app/api-client-php/.openapi-generator/FILES b/omsorgWeb/mitarbeiter-app/api-client-php/.openapi-generator/FILES index 23e10bd..20ecec1 100644 --- a/omsorgWeb/mitarbeiter-app/api-client-php/.openapi-generator/FILES +++ b/omsorgWeb/mitarbeiter-app/api-client-php/.openapi-generator/FILES @@ -231,13 +231,3 @@ lib/Model/ValueListTransitionResponse.php lib/Model/ValueListUsageResponse.php lib/ObjectSerializer.php phpunit.xml.dist -test/Api/EmployeeFacilityDistancesApiTest.php -test/Api/MyFacilityDistancesApiTest.php -test/Model/CreateEmployeeFacilityDistanceRequestTest.php -test/Model/CreateMyFacilityDistanceRequestTest.php -test/Model/EmployeeFacilityDistanceResponseTest.php -test/Model/FacilityOptionResponseTest.php -test/Model/MyFacilityDistanceResponseTest.php -test/Model/TrashEmployeeFacilityDistanceResponseTest.php -test/Model/UpdateEmployeeFacilityDistanceRequestTest.php -test/Model/UpdateMyFacilityDistanceRequestTest.php diff --git a/omsorgWeb/mitarbeiter-app/api-client-php/README.md b/omsorgWeb/mitarbeiter-app/api-client-php/README.md index c0e18ae..a93f6be 100644 --- a/omsorgWeb/mitarbeiter-app/api-client-php/README.md +++ b/omsorgWeb/mitarbeiter-app/api-client-php/README.md @@ -143,6 +143,7 @@ Class | Method | HTTP request | Description *OrdersApi* | [**apiOrdersIdPut**](docs/Api/OrdersApi.md#apiordersidput) | **PUT** /api/orders/{id} | *OrdersApi* | [**apiOrdersPost**](docs/Api/OrdersApi.md#apiorderspost) | **POST** /api/orders | *RolesApi* | [**apiRolesGet**](docs/Api/RolesApi.md#apirolesget) | **GET** /api/roles | +*RolesApi* | [**apiRolesIdDelete**](docs/Api/RolesApi.md#apirolesiddelete) | **DELETE** /api/roles/{id} | *RolesApi* | [**apiRolesIdGet**](docs/Api/RolesApi.md#apirolesidget) | **GET** /api/roles/{id} | *RolesApi* | [**apiRolesIdPermissionsPut**](docs/Api/RolesApi.md#apirolesidpermissionsput) | **PUT** /api/roles/{id}/permissions | *RolesApi* | [**apiRolesPost**](docs/Api/RolesApi.md#apirolespost) | **POST** /api/roles | diff --git a/omsorgWeb/mitarbeiter-app/api-client-php/docs/Api/RolesApi.md b/omsorgWeb/mitarbeiter-app/api-client-php/docs/Api/RolesApi.md index 8300b9e..f6b27a4 100644 --- a/omsorgWeb/mitarbeiter-app/api-client-php/docs/Api/RolesApi.md +++ b/omsorgWeb/mitarbeiter-app/api-client-php/docs/Api/RolesApi.md @@ -5,6 +5,7 @@ All URIs are relative to http://localhost, except if the operation defines anoth | Method | HTTP request | Description | | ------------- | ------------- | ------------- | | [**apiRolesGet()**](RolesApi.md#apiRolesGet) | **GET** /api/roles | | +| [**apiRolesIdDelete()**](RolesApi.md#apiRolesIdDelete) | **DELETE** /api/roles/{id} | | | [**apiRolesIdGet()**](RolesApi.md#apiRolesIdGet) | **GET** /api/roles/{id} | | | [**apiRolesIdPermissionsPut()**](RolesApi.md#apiRolesIdPermissionsPut) | **PUT** /api/roles/{id}/permissions | | | [**apiRolesPost()**](RolesApi.md#apiRolesPost) | **POST** /api/roles | | @@ -65,6 +66,63 @@ This endpoint does not need any parameter. [[Back to Model list]](../../README.md#models) [[Back to README]](../../README.md) +## `apiRolesIdDelete()` + +```php +apiRolesIdDelete($id) +``` + + + +### Example + +```php +setAccessToken('YOUR_ACCESS_TOKEN'); + + +$apiInstance = new OmsorgCoreClient\Api\RolesApi( + // If you want use custom http client, pass your client which implements `GuzzleHttp\ClientInterface`. + // This is optional, `GuzzleHttp\Client` will be used as default. + new GuzzleHttp\Client(), + $config +); +$id = 'id_example'; // string + +try { + $apiInstance->apiRolesIdDelete($id); +} catch (Exception $e) { + echo 'Exception when calling RolesApi->apiRolesIdDelete: ', $e->getMessage(), PHP_EOL; +} +``` + +### Parameters + +| Name | Type | Description | Notes | +| ------------- | ------------- | ------------- | ------------- | +| **id** | **string**| | | + +### Return type + +void (empty response body) + +### Authorization + +[Bearer](../../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../../README.md#endpoints) +[[Back to Model list]](../../README.md#models) +[[Back to README]](../../README.md) + ## `apiRolesIdGet()` ```php diff --git a/omsorgWeb/mitarbeiter-app/api-client-php/docs/Model/FacilityResponse.md b/omsorgWeb/mitarbeiter-app/api-client-php/docs/Model/FacilityResponse.md index ccaf2f9..5946cb0 100644 --- a/omsorgWeb/mitarbeiter-app/api-client-php/docs/Model/FacilityResponse.md +++ b/omsorgWeb/mitarbeiter-app/api-client-php/docs/Model/FacilityResponse.md @@ -26,8 +26,8 @@ Name | Type | Description | Notes **travel_cost_rate** | **float** | | [optional] **travel_cost_mode** | **string** | | [optional] **travel_cost_per_km** | **float** | | [optional] +**meal_allowance_rate** | **float** | | [optional] **minimum_hours** | **float** | | [optional] -**break_policy** | **string** | | [optional] **billing_interval** | **string** | | [optional] **payment_term_days** | **int** | | [optional] **individual_agreements** | **string** | | [optional] diff --git a/omsorgWeb/mitarbeiter-app/api-client-php/docs/Model/UpdateFacilityRequest.md b/omsorgWeb/mitarbeiter-app/api-client-php/docs/Model/UpdateFacilityRequest.md index eac394e..a0f298d 100644 --- a/omsorgWeb/mitarbeiter-app/api-client-php/docs/Model/UpdateFacilityRequest.md +++ b/omsorgWeb/mitarbeiter-app/api-client-php/docs/Model/UpdateFacilityRequest.md @@ -25,8 +25,8 @@ Name | Type | Description | Notes **travel_cost_rate** | **float** | | [optional] **travel_cost_mode** | **string** | | [optional] **travel_cost_per_km** | **float** | | [optional] +**meal_allowance_rate** | **float** | | [optional] **minimum_hours** | **float** | | [optional] -**break_policy** | **string** | | [optional] **billing_interval** | **string** | | [optional] **payment_term_days** | **int** | | [optional] **individual_agreements** | **string** | | [optional] diff --git a/omsorgWeb/mitarbeiter-app/api-client-php/lib/Api/RolesApi.php b/omsorgWeb/mitarbeiter-app/api-client-php/lib/Api/RolesApi.php index 3cab386..ca68293 100644 --- a/omsorgWeb/mitarbeiter-app/api-client-php/lib/Api/RolesApi.php +++ b/omsorgWeb/mitarbeiter-app/api-client-php/lib/Api/RolesApi.php @@ -77,6 +77,9 @@ class RolesApi 'apiRolesGet' => [ 'application/json', ], + 'apiRolesIdDelete' => [ + 'application/json', + ], 'apiRolesIdGet' => [ 'application/json', ], @@ -382,6 +385,220 @@ class RolesApi ); } + /** + * Operation apiRolesIdDelete + * + * @param string $id id (required) + * @param string $contentType The value for the Content-Type header. Check self::contentTypes['apiRolesIdDelete'] to see the possible values for this operation + * + * @throws \OmsorgCoreClient\ApiException on non-2xx response or if the response body is not in the expected format + * @throws \InvalidArgumentException + * @return void + */ + public function apiRolesIdDelete($id, string $contentType = self::contentTypes['apiRolesIdDelete'][0]) + { + $this->apiRolesIdDeleteWithHttpInfo($id, $contentType); + } + + /** + * Operation apiRolesIdDeleteWithHttpInfo + * + * @param string $id (required) + * @param string $contentType The value for the Content-Type header. Check self::contentTypes['apiRolesIdDelete'] to see the possible values for this operation + * + * @throws \OmsorgCoreClient\ApiException on non-2xx response or if the response body is not in the expected format + * @throws \InvalidArgumentException + * @return array of null, HTTP status code, HTTP response headers (array of strings) + */ + public function apiRolesIdDeleteWithHttpInfo($id, string $contentType = self::contentTypes['apiRolesIdDelete'][0]) + { + $request = $this->apiRolesIdDeleteRequest($id, $contentType); + + try { + $options = $this->createHttpClientOption(); + try { + $response = $this->client->send($request, $options); + } catch (RequestException $e) { + throw new ApiException( + "[{$e->getCode()}] {$e->getMessage()}", + (int) $e->getCode(), + $e->getResponse() ? $e->getResponse()->getHeaders() : null, + $e->getResponse() ? (string) $e->getResponse()->getBody() : null + ); + } catch (ConnectException $e) { + throw new ApiException( + "[{$e->getCode()}] {$e->getMessage()}", + (int) $e->getCode(), + null, + null + ); + } + + $statusCode = $response->getStatusCode(); + + + return [null, $statusCode, $response->getHeaders()]; + } catch (ApiException $e) { + switch ($e->getCode()) { + } + + + throw $e; + } + } + + /** + * Operation apiRolesIdDeleteAsync + * + * @param string $id (required) + * @param string $contentType The value for the Content-Type header. Check self::contentTypes['apiRolesIdDelete'] to see the possible values for this operation + * + * @throws \InvalidArgumentException + * @return \GuzzleHttp\Promise\PromiseInterface + */ + public function apiRolesIdDeleteAsync($id, string $contentType = self::contentTypes['apiRolesIdDelete'][0]) + { + return $this->apiRolesIdDeleteAsyncWithHttpInfo($id, $contentType) + ->then( + function ($response) { + return $response[0]; + } + ); + } + + /** + * Operation apiRolesIdDeleteAsyncWithHttpInfo + * + * @param string $id (required) + * @param string $contentType The value for the Content-Type header. Check self::contentTypes['apiRolesIdDelete'] to see the possible values for this operation + * + * @throws \InvalidArgumentException + * @return \GuzzleHttp\Promise\PromiseInterface + */ + public function apiRolesIdDeleteAsyncWithHttpInfo($id, string $contentType = self::contentTypes['apiRolesIdDelete'][0]) + { + $returnType = ''; + $request = $this->apiRolesIdDeleteRequest($id, $contentType); + + return $this->client + ->sendAsync($request, $this->createHttpClientOption()) + ->then( + function ($response) use ($returnType) { + return [null, $response->getStatusCode(), $response->getHeaders()]; + }, + function ($exception) { + $response = $exception->getResponse(); + $statusCode = $response->getStatusCode(); + throw new ApiException( + sprintf( + '[%d] Error connecting to the API (%s)', + $statusCode, + $exception->getRequest()->getUri() + ), + $statusCode, + $response->getHeaders(), + (string) $response->getBody() + ); + } + ); + } + + /** + * Create request for operation 'apiRolesIdDelete' + * + * @param string $id (required) + * @param string $contentType The value for the Content-Type header. Check self::contentTypes['apiRolesIdDelete'] to see the possible values for this operation + * + * @throws \InvalidArgumentException + * @return \GuzzleHttp\Psr7\Request + */ + public function apiRolesIdDeleteRequest($id, string $contentType = self::contentTypes['apiRolesIdDelete'][0]) + { + + // verify the required parameter 'id' is set + if ($id === null || (is_array($id) && count($id) === 0)) { + throw new \InvalidArgumentException( + 'Missing the required parameter $id when calling apiRolesIdDelete' + ); + } + + + $resourcePath = '/api/roles/{id}'; + $formParams = []; + $queryParams = []; + $headerParams = []; + $httpBody = ''; + $multipart = false; + + + + // path params + if ($id !== null) { + $resourcePath = str_replace( + '{' . 'id' . '}', + ObjectSerializer::toPathValue($id), + $resourcePath + ); + } + + + $headers = $this->headerSelector->selectHeaders( + [], + $contentType, + $multipart + ); + + // for model (json/xml) + if (count($formParams) > 0) { + if ($multipart) { + $multipartContents = []; + foreach ($formParams as $formParamName => $formParamValue) { + $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue]; + foreach ($formParamValueItems as $formParamValueItem) { + $multipartContents[] = [ + 'name' => $formParamName, + 'contents' => $formParamValueItem + ]; + } + } + // for HTTP post (form) + $httpBody = new MultipartStream($multipartContents); + + } elseif (stripos($headers['Content-Type'], 'application/json') !== false) { + # if Content-Type contains "application/json", json_encode the form parameters + $httpBody = \GuzzleHttp\Utils::jsonEncode($formParams); + } else { + // for HTTP post (form) + $httpBody = ObjectSerializer::buildQuery($formParams); + } + } + + // this endpoint requires Bearer (JWT) authentication (access token) + if (!empty($this->config->getAccessToken())) { + $headers['Authorization'] = 'Bearer ' . $this->config->getAccessToken(); + } + + $defaultHeaders = []; + if ($this->config->getUserAgent()) { + $defaultHeaders['User-Agent'] = $this->config->getUserAgent(); + } + + $headers = array_merge( + $defaultHeaders, + $headerParams, + $headers + ); + + $operationHost = $this->config->getHost(); + $query = ObjectSerializer::buildQuery($queryParams); + return new Request( + 'DELETE', + $operationHost . $resourcePath . ($query ? "?{$query}" : ''), + $headers, + $httpBody + ); + } + /** * Operation apiRolesIdGet * diff --git a/omsorgWeb/mitarbeiter-app/api-client-php/lib/Model/FacilityResponse.php b/omsorgWeb/mitarbeiter-app/api-client-php/lib/Model/FacilityResponse.php index 8812490..e045af2 100644 --- a/omsorgWeb/mitarbeiter-app/api-client-php/lib/Model/FacilityResponse.php +++ b/omsorgWeb/mitarbeiter-app/api-client-php/lib/Model/FacilityResponse.php @@ -79,8 +79,8 @@ class FacilityResponse implements ModelInterface, ArrayAccess, \JsonSerializable 'travel_cost_rate' => 'float', 'travel_cost_mode' => 'string', 'travel_cost_per_km' => 'float', + 'meal_allowance_rate' => 'float', 'minimum_hours' => 'float', - 'break_policy' => 'string', 'billing_interval' => 'string', 'payment_term_days' => 'int', 'individual_agreements' => 'string' @@ -116,8 +116,8 @@ class FacilityResponse implements ModelInterface, ArrayAccess, \JsonSerializable 'travel_cost_rate' => 'double', 'travel_cost_mode' => null, 'travel_cost_per_km' => 'double', + 'meal_allowance_rate' => 'double', 'minimum_hours' => 'double', - 'break_policy' => null, 'billing_interval' => null, 'payment_term_days' => 'int32', 'individual_agreements' => null @@ -151,8 +151,8 @@ class FacilityResponse implements ModelInterface, ArrayAccess, \JsonSerializable 'travel_cost_rate' => true, 'travel_cost_mode' => true, 'travel_cost_per_km' => true, + 'meal_allowance_rate' => true, 'minimum_hours' => true, - 'break_policy' => true, 'billing_interval' => true, 'payment_term_days' => true, 'individual_agreements' => true @@ -266,8 +266,8 @@ class FacilityResponse implements ModelInterface, ArrayAccess, \JsonSerializable 'travel_cost_rate' => 'travelCostRate', 'travel_cost_mode' => 'travelCostMode', 'travel_cost_per_km' => 'travelCostPerKm', + 'meal_allowance_rate' => 'mealAllowanceRate', 'minimum_hours' => 'minimumHours', - 'break_policy' => 'breakPolicy', 'billing_interval' => 'billingInterval', 'payment_term_days' => 'paymentTermDays', 'individual_agreements' => 'individualAgreements' @@ -301,8 +301,8 @@ class FacilityResponse implements ModelInterface, ArrayAccess, \JsonSerializable 'travel_cost_rate' => 'setTravelCostRate', 'travel_cost_mode' => 'setTravelCostMode', 'travel_cost_per_km' => 'setTravelCostPerKm', + 'meal_allowance_rate' => 'setMealAllowanceRate', 'minimum_hours' => 'setMinimumHours', - 'break_policy' => 'setBreakPolicy', 'billing_interval' => 'setBillingInterval', 'payment_term_days' => 'setPaymentTermDays', 'individual_agreements' => 'setIndividualAgreements' @@ -336,8 +336,8 @@ class FacilityResponse implements ModelInterface, ArrayAccess, \JsonSerializable 'travel_cost_rate' => 'getTravelCostRate', 'travel_cost_mode' => 'getTravelCostMode', 'travel_cost_per_km' => 'getTravelCostPerKm', + 'meal_allowance_rate' => 'getMealAllowanceRate', 'minimum_hours' => 'getMinimumHours', - 'break_policy' => 'getBreakPolicy', 'billing_interval' => 'getBillingInterval', 'payment_term_days' => 'getPaymentTermDays', 'individual_agreements' => 'getIndividualAgreements' @@ -422,8 +422,8 @@ class FacilityResponse implements ModelInterface, ArrayAccess, \JsonSerializable $this->setIfExists('travel_cost_rate', $data ?? [], null); $this->setIfExists('travel_cost_mode', $data ?? [], null); $this->setIfExists('travel_cost_per_km', $data ?? [], null); + $this->setIfExists('meal_allowance_rate', $data ?? [], null); $this->setIfExists('minimum_hours', $data ?? [], null); - $this->setIfExists('break_policy', $data ?? [], null); $this->setIfExists('billing_interval', $data ?? [], null); $this->setIfExists('payment_term_days', $data ?? [], null); $this->setIfExists('individual_agreements', $data ?? [], null); @@ -1212,6 +1212,40 @@ class FacilityResponse implements ModelInterface, ArrayAccess, \JsonSerializable return $this; } + /** + * Gets meal_allowance_rate + * + * @return float|null + */ + public function getMealAllowanceRate() + { + return $this->container['meal_allowance_rate']; + } + + /** + * Sets meal_allowance_rate + * + * @param float|null $meal_allowance_rate meal_allowance_rate + * + * @return self + */ + public function setMealAllowanceRate($meal_allowance_rate) + { + if (is_null($meal_allowance_rate)) { + array_push($this->openAPINullablesSetToNull, 'meal_allowance_rate'); + } else { + $nullablesSetToNull = $this->getOpenAPINullablesSetToNull(); + $index = array_search('meal_allowance_rate', $nullablesSetToNull); + if ($index !== FALSE) { + unset($nullablesSetToNull[$index]); + $this->setOpenAPINullablesSetToNull($nullablesSetToNull); + } + } + $this->container['meal_allowance_rate'] = $meal_allowance_rate; + + return $this; + } + /** * Gets minimum_hours * @@ -1246,40 +1280,6 @@ class FacilityResponse implements ModelInterface, ArrayAccess, \JsonSerializable return $this; } - /** - * Gets break_policy - * - * @return string|null - */ - public function getBreakPolicy() - { - return $this->container['break_policy']; - } - - /** - * Sets break_policy - * - * @param string|null $break_policy break_policy - * - * @return self - */ - public function setBreakPolicy($break_policy) - { - if (is_null($break_policy)) { - array_push($this->openAPINullablesSetToNull, 'break_policy'); - } else { - $nullablesSetToNull = $this->getOpenAPINullablesSetToNull(); - $index = array_search('break_policy', $nullablesSetToNull); - if ($index !== FALSE) { - unset($nullablesSetToNull[$index]); - $this->setOpenAPINullablesSetToNull($nullablesSetToNull); - } - } - $this->container['break_policy'] = $break_policy; - - return $this; - } - /** * Gets billing_interval * diff --git a/omsorgWeb/mitarbeiter-app/api-client-php/lib/Model/UpdateFacilityRequest.php b/omsorgWeb/mitarbeiter-app/api-client-php/lib/Model/UpdateFacilityRequest.php index d22f636..a5d01c7 100644 --- a/omsorgWeb/mitarbeiter-app/api-client-php/lib/Model/UpdateFacilityRequest.php +++ b/omsorgWeb/mitarbeiter-app/api-client-php/lib/Model/UpdateFacilityRequest.php @@ -78,8 +78,8 @@ class UpdateFacilityRequest implements ModelInterface, ArrayAccess, \JsonSeriali 'travel_cost_rate' => 'float', 'travel_cost_mode' => 'string', 'travel_cost_per_km' => 'float', + 'meal_allowance_rate' => 'float', 'minimum_hours' => 'float', - 'break_policy' => 'string', 'billing_interval' => 'string', 'payment_term_days' => 'int', 'individual_agreements' => 'string' @@ -114,8 +114,8 @@ class UpdateFacilityRequest implements ModelInterface, ArrayAccess, \JsonSeriali 'travel_cost_rate' => 'double', 'travel_cost_mode' => null, 'travel_cost_per_km' => 'double', + 'meal_allowance_rate' => 'double', 'minimum_hours' => 'double', - 'break_policy' => null, 'billing_interval' => null, 'payment_term_days' => 'int32', 'individual_agreements' => null @@ -148,8 +148,8 @@ class UpdateFacilityRequest implements ModelInterface, ArrayAccess, \JsonSeriali 'travel_cost_rate' => true, 'travel_cost_mode' => true, 'travel_cost_per_km' => true, + 'meal_allowance_rate' => true, 'minimum_hours' => true, - 'break_policy' => true, 'billing_interval' => true, 'payment_term_days' => true, 'individual_agreements' => true @@ -262,8 +262,8 @@ class UpdateFacilityRequest implements ModelInterface, ArrayAccess, \JsonSeriali 'travel_cost_rate' => 'travelCostRate', 'travel_cost_mode' => 'travelCostMode', 'travel_cost_per_km' => 'travelCostPerKm', + 'meal_allowance_rate' => 'mealAllowanceRate', 'minimum_hours' => 'minimumHours', - 'break_policy' => 'breakPolicy', 'billing_interval' => 'billingInterval', 'payment_term_days' => 'paymentTermDays', 'individual_agreements' => 'individualAgreements' @@ -296,8 +296,8 @@ class UpdateFacilityRequest implements ModelInterface, ArrayAccess, \JsonSeriali 'travel_cost_rate' => 'setTravelCostRate', 'travel_cost_mode' => 'setTravelCostMode', 'travel_cost_per_km' => 'setTravelCostPerKm', + 'meal_allowance_rate' => 'setMealAllowanceRate', 'minimum_hours' => 'setMinimumHours', - 'break_policy' => 'setBreakPolicy', 'billing_interval' => 'setBillingInterval', 'payment_term_days' => 'setPaymentTermDays', 'individual_agreements' => 'setIndividualAgreements' @@ -330,8 +330,8 @@ class UpdateFacilityRequest implements ModelInterface, ArrayAccess, \JsonSeriali 'travel_cost_rate' => 'getTravelCostRate', 'travel_cost_mode' => 'getTravelCostMode', 'travel_cost_per_km' => 'getTravelCostPerKm', + 'meal_allowance_rate' => 'getMealAllowanceRate', 'minimum_hours' => 'getMinimumHours', - 'break_policy' => 'getBreakPolicy', 'billing_interval' => 'getBillingInterval', 'payment_term_days' => 'getPaymentTermDays', 'individual_agreements' => 'getIndividualAgreements' @@ -415,8 +415,8 @@ class UpdateFacilityRequest implements ModelInterface, ArrayAccess, \JsonSeriali $this->setIfExists('travel_cost_rate', $data ?? [], null); $this->setIfExists('travel_cost_mode', $data ?? [], null); $this->setIfExists('travel_cost_per_km', $data ?? [], null); + $this->setIfExists('meal_allowance_rate', $data ?? [], null); $this->setIfExists('minimum_hours', $data ?? [], null); - $this->setIfExists('break_policy', $data ?? [], null); $this->setIfExists('billing_interval', $data ?? [], null); $this->setIfExists('payment_term_days', $data ?? [], null); $this->setIfExists('individual_agreements', $data ?? [], null); @@ -1178,6 +1178,40 @@ class UpdateFacilityRequest implements ModelInterface, ArrayAccess, \JsonSeriali return $this; } + /** + * Gets meal_allowance_rate + * + * @return float|null + */ + public function getMealAllowanceRate() + { + return $this->container['meal_allowance_rate']; + } + + /** + * Sets meal_allowance_rate + * + * @param float|null $meal_allowance_rate meal_allowance_rate + * + * @return self + */ + public function setMealAllowanceRate($meal_allowance_rate) + { + if (is_null($meal_allowance_rate)) { + array_push($this->openAPINullablesSetToNull, 'meal_allowance_rate'); + } else { + $nullablesSetToNull = $this->getOpenAPINullablesSetToNull(); + $index = array_search('meal_allowance_rate', $nullablesSetToNull); + if ($index !== FALSE) { + unset($nullablesSetToNull[$index]); + $this->setOpenAPINullablesSetToNull($nullablesSetToNull); + } + } + $this->container['meal_allowance_rate'] = $meal_allowance_rate; + + return $this; + } + /** * Gets minimum_hours * @@ -1212,40 +1246,6 @@ class UpdateFacilityRequest implements ModelInterface, ArrayAccess, \JsonSeriali return $this; } - /** - * Gets break_policy - * - * @return string|null - */ - public function getBreakPolicy() - { - return $this->container['break_policy']; - } - - /** - * Sets break_policy - * - * @param string|null $break_policy break_policy - * - * @return self - */ - public function setBreakPolicy($break_policy) - { - if (is_null($break_policy)) { - array_push($this->openAPINullablesSetToNull, 'break_policy'); - } else { - $nullablesSetToNull = $this->getOpenAPINullablesSetToNull(); - $index = array_search('break_policy', $nullablesSetToNull); - if ($index !== FALSE) { - unset($nullablesSetToNull[$index]); - $this->setOpenAPINullablesSetToNull($nullablesSetToNull); - } - } - $this->container['break_policy'] = $break_policy; - - return $this; - } - /** * Gets billing_interval * diff --git a/omsorgapp/api-client-ts/src/models/FacilityResponse.ts b/omsorgapp/api-client-ts/src/models/FacilityResponse.ts index 7005629..d0527a5 100644 --- a/omsorgapp/api-client-ts/src/models/FacilityResponse.ts +++ b/omsorgapp/api-client-ts/src/models/FacilityResponse.ts @@ -156,13 +156,13 @@ export interface FacilityResponse { * @type {number} * @memberof FacilityResponse */ - minimumHours?: number | null; + mealAllowanceRate?: number | null; /** * - * @type {string} + * @type {number} * @memberof FacilityResponse */ - breakPolicy?: string | null; + minimumHours?: number | null; /** * * @type {string} @@ -222,8 +222,8 @@ export function FacilityResponseFromJSONTyped(json: any, ignoreDiscriminator: bo 'travelCostRate': json['travelCostRate'] == null ? undefined : json['travelCostRate'], 'travelCostMode': json['travelCostMode'] == null ? undefined : json['travelCostMode'], 'travelCostPerKm': json['travelCostPerKm'] == null ? undefined : json['travelCostPerKm'], + 'mealAllowanceRate': json['mealAllowanceRate'] == null ? undefined : json['mealAllowanceRate'], 'minimumHours': json['minimumHours'] == null ? undefined : json['minimumHours'], - 'breakPolicy': json['breakPolicy'] == null ? undefined : json['breakPolicy'], 'billingInterval': json['billingInterval'] == null ? undefined : json['billingInterval'], 'paymentTermDays': json['paymentTermDays'] == null ? undefined : json['paymentTermDays'], 'individualAgreements': json['individualAgreements'] == null ? undefined : json['individualAgreements'], @@ -263,8 +263,8 @@ export function FacilityResponseToJSONTyped(value?: FacilityResponse | null, ign 'travelCostRate': value['travelCostRate'], 'travelCostMode': value['travelCostMode'], 'travelCostPerKm': value['travelCostPerKm'], + 'mealAllowanceRate': value['mealAllowanceRate'], 'minimumHours': value['minimumHours'], - 'breakPolicy': value['breakPolicy'], 'billingInterval': value['billingInterval'], 'paymentTermDays': value['paymentTermDays'], 'individualAgreements': value['individualAgreements'], diff --git a/omsorgapp/api-client-ts/src/models/UpdateFacilityRequest.ts b/omsorgapp/api-client-ts/src/models/UpdateFacilityRequest.ts index b5dfe2c..c06f6ea 100644 --- a/omsorgapp/api-client-ts/src/models/UpdateFacilityRequest.ts +++ b/omsorgapp/api-client-ts/src/models/UpdateFacilityRequest.ts @@ -150,13 +150,13 @@ export interface UpdateFacilityRequest { * @type {number} * @memberof UpdateFacilityRequest */ - minimumHours?: number | null; + mealAllowanceRate?: number | null; /** * - * @type {string} + * @type {number} * @memberof UpdateFacilityRequest */ - breakPolicy?: string | null; + minimumHours?: number | null; /** * * @type {string} @@ -215,8 +215,8 @@ export function UpdateFacilityRequestFromJSONTyped(json: any, ignoreDiscriminato 'travelCostRate': json['travelCostRate'] == null ? undefined : json['travelCostRate'], 'travelCostMode': json['travelCostMode'] == null ? undefined : json['travelCostMode'], 'travelCostPerKm': json['travelCostPerKm'] == null ? undefined : json['travelCostPerKm'], + 'mealAllowanceRate': json['mealAllowanceRate'] == null ? undefined : json['mealAllowanceRate'], 'minimumHours': json['minimumHours'] == null ? undefined : json['minimumHours'], - 'breakPolicy': json['breakPolicy'] == null ? undefined : json['breakPolicy'], 'billingInterval': json['billingInterval'] == null ? undefined : json['billingInterval'], 'paymentTermDays': json['paymentTermDays'] == null ? undefined : json['paymentTermDays'], 'individualAgreements': json['individualAgreements'] == null ? undefined : json['individualAgreements'], @@ -255,8 +255,8 @@ export function UpdateFacilityRequestToJSONTyped(value?: UpdateFacilityRequest | 'travelCostRate': value['travelCostRate'], 'travelCostMode': value['travelCostMode'], 'travelCostPerKm': value['travelCostPerKm'], + 'mealAllowanceRate': value['mealAllowanceRate'], 'minimumHours': value['minimumHours'], - 'breakPolicy': value['breakPolicy'], 'billingInterval': value['billingInterval'], 'paymentTermDays': value['paymentTermDays'], 'individualAgreements': value['individualAgreements'], diff --git a/omsorgapp/src/modules/facilities/FacilityDetailPanel.jsx b/omsorgapp/src/modules/facilities/FacilityDetailPanel.jsx index 1123065..850f5dc 100644 --- a/omsorgapp/src/modules/facilities/FacilityDetailPanel.jsx +++ b/omsorgapp/src/modules/facilities/FacilityDetailPanel.jsx @@ -151,13 +151,13 @@ export default function FacilityDetailPanel({ facility, onUpdated }) {
- Mindeststunden -

{facility.minimumHours ?? "—"}

+ Verpflegungsmehraufwand +

{facility.mealAllowanceRate != null ? `${facility.mealAllowanceRate} EUR (Pauschale je Einsatz)` : "—"}

- Pausenregelung -

{facility.breakPolicy ?? "—"}

+ Mindeststunden +

{facility.minimumHours ?? "—"}

diff --git a/omsorgapp/src/modules/facilities/FacilityForm.jsx b/omsorgapp/src/modules/facilities/FacilityForm.jsx index 932b9b0..bff6ff9 100644 --- a/omsorgapp/src/modules/facilities/FacilityForm.jsx +++ b/omsorgapp/src/modules/facilities/FacilityForm.jsx @@ -24,8 +24,8 @@ export const emptyFacilityForm = { travelCostMode: "Pauschale", travelCostRate: "", travelCostPerKm: "", + mealAllowanceRate: "", minimumHours: "", - breakPolicy: "", billingInterval: "", paymentTermDays: "", individualAgreements: "", @@ -53,8 +53,8 @@ export function facilityToFormValues(facility) { travelCostMode: facility.travelCostMode ?? "Pauschale", travelCostRate: facility.travelCostRate ?? "", travelCostPerKm: facility.travelCostPerKm ?? "", + mealAllowanceRate: facility.mealAllowanceRate ?? "", minimumHours: facility.minimumHours ?? "", - breakPolicy: facility.breakPolicy ?? "", billingInterval: facility.billingInterval ?? "", paymentTermDays: facility.paymentTermDays ?? "", individualAgreements: facility.individualAgreements ?? "", @@ -87,8 +87,8 @@ export function facilityFormToPayload(form, { includeCrmStatus = false, followUp payload.travelCostMode = form.travelCostMode || "Pauschale"; payload.travelCostRate = form.travelCostRate === "" ? null : Number(form.travelCostRate); payload.travelCostPerKm = form.travelCostPerKm === "" ? null : Number(form.travelCostPerKm); + payload.mealAllowanceRate = form.mealAllowanceRate === "" ? null : Number(form.mealAllowanceRate); payload.minimumHours = form.minimumHours === "" ? null : Number(form.minimumHours); - payload.breakPolicy = form.breakPolicy.trim() || null; payload.billingInterval = form.billingInterval || null; payload.paymentTermDays = form.paymentTermDays === "" ? null : Number(form.paymentTermDays); payload.individualAgreements = form.individualAgreements.trim() || null; @@ -282,10 +282,12 @@ export default function FacilityForm({ form, onChange, includeCrmStatus = false, )}
- +
+ +