Add employee-to-order assignments with FR-EM-3 conflict validation
Docker-Images bauen und veröffentlichen / build (, omsorgCore/Dockerfile, omsorgcore) (push) Successful in 17s
Docker-Images bauen und veröffentlichen / build (, omsorgWeb/Dockerfile, omsorgweb) (push) Successful in 6s
Docker-Images bauen und veröffentlichen / build (, omsorgapp/Dockerfile, omsorgapp) (push) Successful in 17s

Adds the Assignment core object (Order x Employee, date range) with full
CRUD, soft-delete/trash integration, and generated API clients.

Layers FR-EM-3 conflict checks onto assignment creation: qualification,
absence/availability, working-hours approximation, cross-order overlap,
and active-contract coverage. Each check's severity (Warning vs. Error)
is configurable at runtime via a new AssignmentValidationSettings
singleton and admin settings panel, instead of being hardcoded - lets
the business tune strictness per check without a redeploy.

Adds a live GET /api/assignments/check endpoint so the create-assignment
dialog can preview conflicts as the user picks employee/dates, before
they hit save, rather than only finding out after submitting.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Felix Kemmler
2026-08-11 00:44:14 +02:00
co-authored by Claude Sonnet 5
parent fcbf27db3c
commit dfeb37cf33
104 changed files with 15846 additions and 7 deletions
@@ -25,6 +25,12 @@ export interface CreateFacilityRequest {
* @memberof CreateFacilityRequest
*/
name?: string | null;
/**
*
* @type {string}
* @memberof CreateFacilityRequest
*/
crmStatus?: string | null;
/**
*
* @type {string}
@@ -85,6 +91,90 @@ export interface CreateFacilityRequest {
* @memberof CreateFacilityRequest
*/
billingCountry?: string | null;
/**
*
* @type {number}
* @memberof CreateFacilityRequest
*/
followUpDays?: number | null;
/**
*
* @type {number}
* @memberof CreateFacilityRequest
*/
billingRate?: number | null;
/**
*
* @type {number}
* @memberof CreateFacilityRequest
*/
nightSurchargePercent?: number | null;
/**
*
* @type {number}
* @memberof CreateFacilityRequest
*/
saturdaySurchargePercent?: number | null;
/**
*
* @type {number}
* @memberof CreateFacilityRequest
*/
sundaySurchargePercent?: number | null;
/**
*
* @type {number}
* @memberof CreateFacilityRequest
*/
holidaySurchargePercent?: number | null;
/**
*
* @type {number}
* @memberof CreateFacilityRequest
*/
travelCostRate?: number | null;
/**
*
* @type {string}
* @memberof CreateFacilityRequest
*/
travelCostMode?: string | null;
/**
*
* @type {number}
* @memberof CreateFacilityRequest
*/
travelCostPerKm?: number | null;
/**
*
* @type {number}
* @memberof CreateFacilityRequest
*/
mealAllowanceRate?: number | null;
/**
*
* @type {number}
* @memberof CreateFacilityRequest
*/
minimumHours?: number | null;
/**
*
* @type {string}
* @memberof CreateFacilityRequest
*/
billingInterval?: string | null;
/**
*
* @type {number}
* @memberof CreateFacilityRequest
*/
paymentTermDays?: number | null;
/**
*
* @type {string}
* @memberof CreateFacilityRequest
*/
individualAgreements?: string | null;
}
/**
@@ -105,6 +195,7 @@ export function CreateFacilityRequestFromJSONTyped(json: any, ignoreDiscriminato
return {
'name': json['name'] == null ? undefined : json['name'],
'crmStatus': json['crmStatus'] == null ? undefined : json['crmStatus'],
'facilityType': json['facilityType'] == null ? undefined : json['facilityType'],
'website': json['website'] == null ? undefined : json['website'],
'street': json['street'] == null ? undefined : json['street'],
@@ -115,6 +206,20 @@ export function CreateFacilityRequestFromJSONTyped(json: any, ignoreDiscriminato
'billingPostalCode': json['billingPostalCode'] == null ? undefined : json['billingPostalCode'],
'billingCity': json['billingCity'] == null ? undefined : json['billingCity'],
'billingCountry': json['billingCountry'] == null ? undefined : json['billingCountry'],
'followUpDays': json['followUpDays'] == null ? undefined : json['followUpDays'],
'billingRate': json['billingRate'] == null ? undefined : json['billingRate'],
'nightSurchargePercent': json['nightSurchargePercent'] == null ? undefined : json['nightSurchargePercent'],
'saturdaySurchargePercent': json['saturdaySurchargePercent'] == null ? undefined : json['saturdaySurchargePercent'],
'sundaySurchargePercent': json['sundaySurchargePercent'] == null ? undefined : json['sundaySurchargePercent'],
'holidaySurchargePercent': json['holidaySurchargePercent'] == null ? undefined : json['holidaySurchargePercent'],
'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'],
'billingInterval': json['billingInterval'] == null ? undefined : json['billingInterval'],
'paymentTermDays': json['paymentTermDays'] == null ? undefined : json['paymentTermDays'],
'individualAgreements': json['individualAgreements'] == null ? undefined : json['individualAgreements'],
};
}
@@ -130,6 +235,7 @@ export function CreateFacilityRequestToJSONTyped(value?: CreateFacilityRequest |
return {
'name': value['name'],
'crmStatus': value['crmStatus'],
'facilityType': value['facilityType'],
'website': value['website'],
'street': value['street'],
@@ -140,6 +246,20 @@ export function CreateFacilityRequestToJSONTyped(value?: CreateFacilityRequest |
'billingPostalCode': value['billingPostalCode'],
'billingCity': value['billingCity'],
'billingCountry': value['billingCountry'],
'followUpDays': value['followUpDays'],
'billingRate': value['billingRate'],
'nightSurchargePercent': value['nightSurchargePercent'],
'saturdaySurchargePercent': value['saturdaySurchargePercent'],
'sundaySurchargePercent': value['sundaySurchargePercent'],
'holidaySurchargePercent': value['holidaySurchargePercent'],
'travelCostRate': value['travelCostRate'],
'travelCostMode': value['travelCostMode'],
'travelCostPerKm': value['travelCostPerKm'],
'mealAllowanceRate': value['mealAllowanceRate'],
'minimumHours': value['minimumHours'],
'billingInterval': value['billingInterval'],
'paymentTermDays': value['paymentTermDays'],
'individualAgreements': value['individualAgreements'],
};
}