add prtial shifts

This commit is contained in:
Ross
2026-07-14 21:38:59 +01:00
parent 96e6a0d625
commit 6ca3db86cb
6 changed files with 374 additions and 6 deletions
+136 -2
View File
@@ -3,7 +3,7 @@ from rota_generator.shifts import InvalidShift, MaxShiftsPerWeekConstraint, NoWo
from pydantic import ValidationError
import datetime
from rota_generator.workers import NonWorkingDays, NotAvailableToWork, Worker, generate_not_available_to_works
from rota_generator.workers import NonWorkingDays, NotAvailableToWork, Worker, generate_not_available_to_works, ShiftStartDate, ShiftEndDate
from rota_generator.workers import WorkRequests
from rota_generator.shifts import PreShiftConstraint
@@ -1984,4 +1984,138 @@ def test_shift_group_availability_exclusion():
worker_shift_counts[worker.name] += 1
assert worker_shift_counts["worker1"] == 2
assert worker_shift_counts["worker2"] == 0
assert worker_shift_counts["worker2"] == 0
def test_shift_dependent_active_dates_constraints():
weeks_to_rota = 10
start_date = datetime.date(2022, 3, 7) # Mon
Rota = RotaBuilder(
start_date,
weeks_to_rota=weeks_to_rota,
)
worker1 = Worker(name="worker1", site="group1", grade=1, fte=100)
worker2 = Worker(
name="worker2", site="group1", grade=1, fte=100,
shift_start_dates={"a": datetime.date(2022, 3, 28)},
shift_end_dates={"a": datetime.date(2022, 4, 25)},
)
Rota.add_workers([worker1, worker2])
Rota.add_shifts(
SingleShift(
sites=("group1",),
name="a",
length=12.5,
days=("Mon",),
workers_required=1,
),
)
Rota.build_and_solve(options={"ratio": 0.0})
assert Rota.results.solver.status == "ok"
# Verify assignments for worker2
for week in range(1, weeks_to_rota + 1):
val = Rota.model.works[worker2.id, week, "Mon", "a"].value
assigned = val is not None and val > 0.5
if week < 4 or week >= 8:
assert not assigned, f"Worker 2 should not be assigned 'a' in week {week}"
def test_shift_dependent_fte_target_scaling():
weeks_to_rota = 10
start_date = datetime.date(2022, 3, 7) # Mon
Rota = RotaBuilder(
start_date,
weeks_to_rota=weeks_to_rota,
)
worker1 = Worker(name="worker1", site="group1", grade=1, fte=100)
worker2 = Worker(
name="worker2", site="group1", grade=1, fte=100,
shift_start_dates={"a": datetime.date(2022, 3, 28)},
shift_end_dates={"a": datetime.date(2022, 4, 25)},
)
Rota.add_workers([worker1, worker2])
Rota.add_shifts(
SingleShift(
sites=("group1",),
name="a",
length=12.5,
days=("Mon",),
workers_required=1,
),
)
Rota.build_and_solve(options={"ratio": 0.0})
assert Rota.results.solver.status == "ok"
# Targets check
assert abs(worker1.shift_target_number["a"] - 7.14) < 0.1
assert abs(worker2.shift_target_number["a"] - 2.86) < 0.1
def test_shift_dependent_dates_validation_invalid_shift():
weeks_to_rota = 2
start_date = datetime.date(2022, 3, 7)
Rota = RotaBuilder(start_date, weeks_to_rota=weeks_to_rota)
worker = Worker(
name="worker1", site="group1", grade=1, fte=100,
shift_start_dates=[ShiftStartDate(shift="non_existent", start_date=datetime.date(2022, 3, 7))]
)
Rota.add_worker(worker)
Rota.add_shifts(
SingleShift(
sites=("group1",),
name="a",
length=12.5,
days=("Mon",),
workers_required=1,
)
)
with pytest.raises(InvalidShift):
Rota.build_workers()
def test_shift_dependent_dates_validation_ineligible_warning():
weeks_to_rota = 2
start_date = datetime.date(2022, 3, 7)
Rota = RotaBuilder(start_date, weeks_to_rota=weeks_to_rota)
worker = Worker(
name="worker1", site="group1", grade=1, fte=100,
shift_start_dates=[ShiftStartDate(shift="a", start_date=datetime.date(2022, 3, 7))]
)
Rota.add_worker(worker)
Rota.add_shifts(
SingleShift(
sites=("group2",),
name="a",
length=12.5,
days=("Mon",),
workers_required=1,
)
)
Rota.terminate_on_warning.remove("Worker/no valid shifts")
Rota.build_workers()
warnings = Rota.get_warnings("Worker/ineligible shift date constraint")
assert len(warnings) == 1
assert "is not eligible to work it" in warnings[0][1]
def test_shift_dependent_dates_model_definition():
worker = Worker(
name="worker1", site="group1", grade=1, fte=100,
shift_start_dates=[{"shift": "a", "start_date": "2022-03-07"}],
shift_end_dates=[{"shift": "a", "end_date": "2022-04-07"}]
)
assert len(worker.shift_start_dates) == 1
assert isinstance(worker.shift_start_dates[0], ShiftStartDate)
assert worker.shift_start_dates[0].shift == "a"
assert worker.shift_start_dates[0].start_date == datetime.date(2022, 3, 7)
assert len(worker.shift_end_dates) == 1
assert isinstance(worker.shift_end_dates[0], ShiftEndDate)
assert worker.shift_end_dates[0].shift == "a"
assert worker.shift_end_dates[0].end_date == datetime.date(2022, 4, 7)