feat(planning): implement constraint-first leave planner

This commit is contained in:
nessar committed 2026-08-28 22:44:14 +02:00
1 parent ba8dbe92d9
commit 7ceaf1a57a
32 files changed
+4842 -880

No files matched your search

+31 -1
View File
@@ -9,10 +9,22 @@
"calculate": "Berechnen",
"remainingDaysWarning": "{count} nicht platziert:",
"remainingDaysManualPlace": "Bitte manuell platzieren.",
"deleteEntry": "Eintrag löschen",
"chooseDate": "Datum auswählen",
"availableDate": "Verfügbar ab",
"daySuffix": "Tag",
"daysSuffix": "Tage",
"expires": "abl."
"expires": "abl.",
"remainingClassification": {
"unavoidableExpiry": "Unvermeidbarer Ablauf",
"atRisk": "Gefährdet",
"deferred": "Aufgeschoben"
},
"remainingReason": {
"unavoidableExpiry": "vor dem Planungshorizont abgelaufen",
"atRisk": "läuft im Planungshorizont ab",
"deferred": "nach dem Planungshorizont verfügbar"
}
},
"dayTypes": {
"weekend": "Wochenende",
@@ -37,6 +49,7 @@
"ifThenTemplate": "Wenn {type} dann {placement}",
"timeWindowTemplate": "Zeitfenster {startDate} bis {endDate}",
"editRule": "Regel bearbeiten",
"deleteRule": "Regel löschen",
"addRule": "Regel hinzufügen",
"place": "platzieren",
"ruleName": "Regelname",
@@ -45,6 +58,9 @@
"type": "Typ",
"position": "Position",
"getBonus": "Bonus erhalten",
"force": "Regelverbindlichkeit",
"obligation": "Verpflichtung",
"preference": "Präferenz",
"startDate": "Startdatum",
"endDate": "Enddatum",
"cancel": "Abbrechen",
@@ -71,6 +87,20 @@
"auto": "automatisch"
}
},
"planning": {
"invalidInput": "Die Planungsdaten sind ungültig.",
"conflict": "Die Verpflichtungen können nicht gemeinsam erfüllt werden.",
"incomplete": "Die Berechnung wurde vor Abschluss aller Qualitätsstufen beendet.",
"error": "Bei der Planung ist ein unerwarteter Fehler aufgetreten.",
"complete": "Plan berechnet."
},
"benchmark": {
"title": "Benchmark der Urlaubsplanung",
"instructions": "Führen Sie die fünf festen Szenarien aus und kopieren Sie den Bericht.",
"run": "Benchmark starten",
"running": "Läuft…",
"copy": "Bericht kopieren"
},
"loading": "Wird geladen...",
"weekdaysShort": ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"]
}
+31 -1
View File
@@ -9,10 +9,22 @@
"calculate": "Calculate",
"remainingDaysWarning": "{count} vacation day{plural} not placed:",
"remainingDaysManualPlace": "Please place them manually.",
"deleteEntry": "Delete entry",
"chooseDate": "Choose a date",
"availableDate": "Available from",
"daySuffix": "day",
"daysSuffix": "days",
"expires": "exp."
"expires": "exp.",
"remainingClassification": {
"unavoidableExpiry": "Unavoidable expiry",
"atRisk": "At risk",
"deferred": "Deferred"
},
"remainingReason": {
"unavoidableExpiry": "expired before the horizon",
"atRisk": "expires within the horizon",
"deferred": "available after the horizon"
}
},
"dayTypes": {
"weekend": "Weekend",
@@ -37,6 +49,7 @@
"ifThenTemplate": "If a holiday falls on a <strong>{day}</strong>, place <strong>{placeDays}</strong> day(s) <strong>{placeType}</strong> <strong>{placement}</strong> and get <strong>{rewardDays}</strong> day(s) <strong>{rewardType}</strong> as a bonus.",
"timeWindowTemplate": "Place <strong>{placeDays}</strong> day(s) <strong>{placeType}</strong> between <strong>{startDate}</strong> and <strong>{endDate}</strong>.",
"editRule": "Edit rule",
"deleteRule": "Delete rule",
"addRule": "Add a rule",
"place": "Place",
"ruleName": "Rule name",
@@ -45,6 +58,9 @@
"type": "Type",
"position": "Position",
"getBonus": "Get as bonus",
"force": "Rule force",
"obligation": "Obligation",
"preference": "Preference",
"startDate": "Start date",
"endDate": "End date",
"cancel": "Cancel",
@@ -71,6 +87,20 @@
"auto": "Auto (Best choice)"
}
},
"planning": {
"invalidInput": "The planning input is invalid.",
"conflict": "The obligations cannot be satisfied together.",
"incomplete": "Calculation stopped before all quality stages completed.",
"error": "The planner encountered an unexpected error.",
"complete": "Plan calculated."
},
"benchmark": {
"title": "Leave planner benchmark",
"instructions": "Run the five fixed scenarios and copy the resulting report.",
"run": "Run benchmark",
"running": "Running…",
"copy": "Copy report"
},
"loading": "Calculating...",
"weekdaysShort": ["M", "T", "W", "T", "F", "S", "S"]
}
+31 -1
View File
@@ -9,10 +9,22 @@
"calculate": "Calcular",
"remainingDaysWarning": "{count} día{plural} de vacaciones no colocado{plural}:",
"remainingDaysManualPlace": "Por favor, colóquelos manualmente.",
"deleteEntry": "Eliminar entrada",
"chooseDate": "Elija una fecha",
"availableDate": "Disponible desde",
"daySuffix": "día",
"daysSuffix": "días",
"expires": "exp."
"expires": "exp.",
"remainingClassification": {
"unavoidableExpiry": "Vencimiento inevitable",
"atRisk": "En riesgo",
"deferred": "Aplazado"
},
"remainingReason": {
"unavoidableExpiry": "caducó antes del horizonte",
"atRisk": "caduca dentro del horizonte",
"deferred": "disponible después del horizonte"
}
},
"dayTypes": {
"weekend": "Fin de semana",
@@ -37,6 +49,7 @@
"ifThenTemplate": "Si un día festivo cae en <strong>{day}</strong>, colocar <strong>{placeDays}</strong> día(s) <strong>{placeType}</strong> <strong>{placement}</strong> y obtener <strong>{rewardDays}</strong> día(s) <strong>{rewardType}</strong> de bonificación.",
"timeWindowTemplate": "Colocar <strong>{placeDays}</strong> día(s) <strong>{placeType}</strong> entre el <strong>{startDate}</strong> y el <strong>{endDate}</strong>.",
"editRule": "Editar regla",
"deleteRule": "Eliminar regla",
"addRule": "Añadir una regla",
"place": "Colocar",
"ruleName": "Nombre de la regla",
@@ -45,6 +58,9 @@
"type": "Tipo",
"position": "Posición",
"getBonus": "Obtener en bonificación",
"force": "Fuerza de la regla",
"obligation": "Obligación",
"preference": "Preferencia",
"startDate": "Fecha de inicio",
"endDate": "Fecha de fin",
"cancel": "Cancelar",
@@ -71,6 +87,20 @@
"auto": "Auto (Mejor opción)"
}
},
"planning": {
"invalidInput": "Los datos de planificación no son válidos.",
"conflict": "Las obligaciones no se pueden satisfacer juntas.",
"incomplete": "El cálculo se detuvo antes de completar todas las etapas de calidad.",
"error": "El planificador encontró un error inesperado.",
"complete": "Plan calculado."
},
"benchmark": {
"title": "Prueba del planificador de vacaciones",
"instructions": "Ejecuta los cinco escenarios fijos y copia el informe resultante.",
"run": "Ejecutar prueba",
"running": "En curso…",
"copy": "Copiar informe"
},
"loading": "Calculando...",
"weekdaysShort": ["L", "M", "M", "J", "V", "S", "D"]
}
+31 -1
View File
@@ -9,10 +9,22 @@
"calculate": "Calculer",
"remainingDaysWarning": "{count} jour{plural} de vacances non placé{plural}:",
"remainingDaysManualPlace": "Veuillez les placer manuellement.",
"deleteEntry": "Supprimer l’entrée",
"chooseDate": "Choisissez une date",
"availableDate": "Disponible à partir du",
"daySuffix": "jour",
"daysSuffix": "jours",
"expires": "exp."
"expires": "exp.",
"remainingClassification": {
"unavoidableExpiry": "Expiration inévitable",
"atRisk": "À risque",
"deferred": "Différé"
},
"remainingReason": {
"unavoidableExpiry": "expiré avant l’horizon",
"atRisk": "expire pendant l’horizon",
"deferred": "disponible après l’horizon"
}
},
"dayTypes": {
"weekend": "Weekend",
@@ -37,6 +49,7 @@
"ifThenTemplate": "Si un jour férié tombe un <strong>{day}</strong>, placer <strong>{placeDays}</strong> jour(s) <strong>{placeType}</strong> <strong>{placement}</strong> et obtenir <strong>{rewardDays}</strong> jour(s) <strong>{rewardType}</strong> en bonus.",
"timeWindowTemplate": "Placer <strong>{placeDays}</strong> jour(s) <strong>{placeType}</strong> entre le <strong>{startDate}</strong> et le <strong>{endDate}</strong>.",
"editRule": "Modifier la règle",
"deleteRule": "Supprimer la règle",
"addRule": "Ajouter une règle",
"place": "Placer",
"ruleName": "Nom de la règle",
@@ -45,6 +58,9 @@
"type": "Type",
"position": "Position",
"getBonus": "Obtenir en bonus",
"force": "Force de la règle",
"obligation": "Obligation",
"preference": "Préférence",
"startDate": "Date de début",
"endDate": "Date de fin",
"cancel": "Annuler",
@@ -71,6 +87,20 @@
"auto": "Auto (Meilleur choix)"
}
},
"planning": {
"invalidInput": "Les données de planification sont invalides.",
"conflict": "Les obligations ne peuvent pas être satisfaites ensemble.",
"incomplete": "Le calcul s’est arrêté avant la fin des critères de qualité.",
"error": "Le planificateur a rencontré une erreur inattendue.",
"complete": "Plan calculé."
},
"benchmark": {
"title": "Benchmark du planificateur de congés",
"instructions": "Lancez les cinq scénarios fixes et copiez le rapport obtenu.",
"run": "Lancer le benchmark",
"running": "En cours…",
"copy": "Copier le rapport"
},
"loading": "Calcul en cours...",
"weekdaysShort": ["L", "M", "M", "J", "V", "S", "D"]
}