Add Verpflegungsmehraufwand (VMA) as fixed facility condition field

Adds MealAllowanceRate as a flat, nullable EUR amount on Facility, following
the same pattern as the existing TravelCostRate/BillingRate fields — a fixed
per-facility rate, not the statutory day-based VMA tiers, per explicit
request.

Both generated API clients are regenerated/rebuilt as required after any
Contract/Controller change (see omsorgCore/CLAUDE.md, "Generierte API-
Clients"). The PHP client regen also picks up the DELETE /api/roles/{id}
endpoint added in a previous backend change but never synced to this client
until now.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Felix Kemmler
2026-08-10 20:45:40 +02:00
co-authored by Claude Sonnet 5
parent 99b5e07390
commit 95b675261e
23 changed files with 1820 additions and 138 deletions
+5 -5
View File
@@ -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.
@@ -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);
@@ -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);
@@ -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);
@@ -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;
@@ -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; }
@@ -31,8 +31,8 @@ public class FacilityConfiguration : IEntityTypeConfiguration<Facility>
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);
@@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace OmsorgCore.Infrastructure.Persistence.Migrations
{
/// <inheritdoc />
public partial class AddFacilityMealAllowanceRate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<decimal>(
name: "MealAllowanceRate",
table: "facilities",
type: "numeric(10,2)",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MealAllowanceRate",
table: "facilities");
}
}
}
@@ -426,10 +426,6 @@ namespace OmsorgCore.Infrastructure.Persistence.Migrations
.HasMaxLength(200)
.HasColumnType("character varying(200)");
b.Property<string>("BreakPolicy")
.HasMaxLength(1000)
.HasColumnType("character varying(1000)");
b.Property<string>("City")
.HasMaxLength(100)
.HasColumnType("character varying(100)");
@@ -466,6 +462,9 @@ namespace OmsorgCore.Infrastructure.Persistence.Migrations
b.Property<bool>("IsDeleted")
.HasColumnType("boolean");
b.Property<decimal?>("MealAllowanceRate")
.HasColumnType("decimal(10,2)");
b.Property<decimal?>("MinimumHours")
.HasColumnType("decimal(5,2)");
@@ -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);
@@ -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
@@ -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 |
@@ -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
<?php
require_once(__DIR__ . '/vendor/autoload.php');
// Configure Bearer (JWT) authorization: Bearer
$config = OmsorgCoreClient\Configuration::getDefaultConfiguration()->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
@@ -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]
@@ -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]
@@ -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
*
@@ -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
*
@@ -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
*
@@ -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'],
@@ -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'],
@@ -151,13 +151,13 @@ export default function FacilityDetailPanel({ facility, onUpdated }) {
</div>
<div>
<strong>Mindeststunden</strong>
<p>{facility.minimumHours ?? "—"}</p>
<strong>Verpflegungsmehraufwand</strong>
<p>{facility.mealAllowanceRate != null ? `${facility.mealAllowanceRate} EUR (Pauschale je Einsatz)` : "—"}</p>
</div>
<div>
<strong>Pausenregelung</strong>
<p>{facility.breakPolicy ?? "—"}</p>
<strong>Mindeststunden</strong>
<p>{facility.minimumHours ?? "—"}</p>
</div>
<div>
@@ -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,
)}
</div>
<div className="form-row">
<label className="form-field">
<span>Pausenregelung</span>
<input value={form.breakPolicy} onChange={updateField("breakPolicy")} />
<span>Verpflegungsmehraufwand (EUR, Pauschale je Einsatz)</span>
<input type="number" min="0" step="0.01" value={form.mealAllowanceRate} onChange={updateField("mealAllowanceRate")} />
</label>
</div>
<div className="form-row">
<label className="form-field">