feat(planning): make optimization rules composable

Evaluate explicit, ordered optimization configurations through one shared
planner model. Add six editable presets, durable one-time legacy migration,
and consistent completed and cancelled plan provenance.

Include functional regressions and the agreed trace-removal and benchmark
follow-up specs. Performance acceptance remains in #78 under unchanged gates.

Refs: #70, #71, #72, #73, #74, #75, #76, #77, #78
This commit is contained in:
nessar committed 2026-10-10 16:07:34 +02:00
1 parent 209bf05f36
commit 6811142299
45 files changed
+8795 -3075

No files matched your search

+54 -2
View File
@@ -133,6 +133,51 @@
"after": "Después",
"around": "Alrededor",
"auto": "Auto (Mejor opción)"
},
"optimization": {
"newRule": "Nueva regla de Optimización",
"defaultName": "Prevención de pérdidas",
"elementsLabel": "Elementos del plan",
"conditionsLabel": "Condiciones (deben cumplirse todas)",
"measureLabel": "Medida",
"aggregationLabel": "Agregación",
"directionLabel": "Dirección",
"thresholdLabel": "Umbral de preferencia en días laborables",
"thresholdSummary": "umbral de preferencia: {count} días laborables",
"summary": "{direction} {aggregation}: {measure} — {elements}{conditions}.",
"invalidConfiguration": "Elija elementos, condiciones, medidas y agregaciones compatibles, con un umbral entero positivo cuando sea necesario.",
"nameRequired": "Introduzca un nombre para la regla.",
"elements": {
"leave-balances": "Saldos de vacaciones",
"public-holiday-weeks": "Semanas con festivos",
"time-off-periods": "Períodos sin trabajo",
"work-sequences": "Secuencias de trabajo",
"leave-placements": "Vacaciones colocadas"
},
"conditions": {
"at-risk": "En riesgo de caducar",
"complete": "Completas",
"internal": "Internas",
"non-empty": "No vacías",
"supporting": "De apoyo"
},
"measures": {
"unplaced-quantity": "Cantidad no colocada",
"public-holiday-week-value": "Valor de las semanas festivas",
"non-working-day-gain": "Ganancia de días sin trabajo",
"work-sequence-length": "Longitud de las secuencias de trabajo",
"work-sequence-deficit": "Déficit de las secuencias de trabajo",
"placement-count": "Número de colocaciones"
},
"aggregations": {
"sum": "Suma",
"count": "Cantidad",
"maximum": "Máximo"
},
"directions": {
"minimize": "Minimizar",
"maximize": "Maximizar"
}
}
},
"planning": {
@@ -276,7 +321,7 @@
"withoutDay": "Sin este día",
"withDay": "Con este día",
"noChange": "Estos totales son iguales. Las reglas y los últimos criterios de desempate (vencimiento del saldo y después fecha) aún pueden influir en la elección.",
"priorityHelp": "Los criterios se muestran por prioridad. La primera diferencia prevalece sobre las siguientes.",
"priorityHelp": "Las obligaciones se resuelven conjuntamente. Las preferencias activas se comparan en el orden de sus reglas. Solo esas reglas añaden vacaciones; la caducidad y luego las fechas resuelven los empates.",
"tryDate": "Probar otra fecha",
"plannedDate": "Fecha prevista actualmente:",
"currentPlan": "Plan actual",
@@ -327,6 +372,10 @@
"placement-date": {
"label": "Primero las fechas más tempranas",
"help": "Último desempate cuando los demás criterios son iguales."
},
"optimization": {
"label": "{rule}: {summary}",
"help": "Esta preferencia de optimización evalúa su configuración guardada. Las preferencias activas siguen el orden mostrado; las anteriores tienen prioridad."
}
},
"stages": {
@@ -342,7 +391,9 @@
"unavailable": "Este saldo de permisos no se puede usar en esta fecha.",
"expired": "Esta fecha es posterior al vencimiento del saldo.",
"type-incompatible": "Este tipo de permiso no se puede usar en esta fecha.",
"rule-invalid": "Usar esta fecha incumpliría una regla del plan."
"rule-invalid": "Usar esta fecha incumpliría una regla del plan.",
"invalid-optimization-configuration": "Elija elementos, condiciones, medidas y agregaciones compatibles, con un umbral entero positivo cuando sea necesario.",
"unsupported-optimization-configuration": "Esta regla combina elementos del plan y medidas incompatibles."
},
"preferenceHelp": {
"time_window": "Días de permiso dentro del período preferido. Más es mejor.",
@@ -373,6 +424,7 @@
"no-working-date": "Ningún día laborable está dentro del período planificado y entre sus fechas de disponibilidad y caducidad.",
"all-dates-occupied": "Todos los días laborables en los que puede utilizarse este saldo ya están ocupados por permisos planificados o días ya reservados.",
"preserved": "Guardado para más adelante: caduca después del período planificado y el cálculo no seleccionó ninguna colocación adicional según tus prioridades.",
"active-priorities": "El cálculo conservó este saldo sin utilizar según tus reglas activas. Cambia las reglas o su orden para solicitar otro plan.",
"calculation-incomplete": "El cálculo se interrumpió antes de terminar la planificación. Su falta de uso no es una decisión definitiva.",
"not-established": "Este cálculo no determinó un motivo preciso para dejarlo sin utilizar."
}