a lot of changes
This commit is contained in:
@@ -227,3 +227,50 @@ def test_cons_rota2(cons_rota):
|
||||
# Check that days worked is now more than oncall count
|
||||
days_worked = Rota.get_worker_days_worked(worker)
|
||||
assert days_worked > oncall_count, f"{worker.name} worked {days_worked} days, more than oncall shifts {oncall_count}"
|
||||
|
||||
def test_cons_rota3(cons_rota):
|
||||
Rota = cons_rota
|
||||
|
||||
Rota.terminate_on_warning.remove("Worker/no valid shifts")
|
||||
Rota.add_shifts(
|
||||
#SingleShift(sites=["a"], name="oncall weekday", length=8, days=days[:4], workers_required=1,
|
||||
# constraint=[
|
||||
# {"name": "pre", "options": 2},
|
||||
# {"name": "post", "options": 2},
|
||||
# ],
|
||||
# ),
|
||||
##SingleShift(sites=["a"], name="oncall weekend", length=8, days=days[4:], workers_required=1),
|
||||
#SingleShift(sites=["a", "b"], name="evening", length=8, days=days[:4], workers_required=1,
|
||||
# constraint=[
|
||||
# {"name": "pre", "options": 2},
|
||||
# {"name": "post", "options": 2},
|
||||
# ],
|
||||
# ),
|
||||
SingleShift(sites=["a"], name="help", length=8, days=days[4:], workers_required=1,
|
||||
#assign_as_block=True,
|
||||
#force_as_block=True
|
||||
#constraint=[
|
||||
# {"name": "pre", "options": 2},
|
||||
# {"name": "post", "options": 2},
|
||||
#],
|
||||
) ,
|
||||
SingleShift(sites=["b"], name="weekend b", length=8, days=days[5:], workers_required=1,
|
||||
#constraint=[
|
||||
# {"name": "pre", "options": 2},
|
||||
# {"name": "post", "options": 2},
|
||||
#],
|
||||
),
|
||||
)
|
||||
#print("Adding shifts")
|
||||
#for worker in Rota.get_workers_by_site("a"):
|
||||
# print(worker.name)
|
||||
## worker.allow_shifts_together("oncall weekday", "evening")
|
||||
## #worker.allow_shifts_together("oncall weekend", "weekend")
|
||||
## worker.prefer_multi_shift_together = 1
|
||||
|
||||
# worker.assign_as_block_preferences = {"help":10}
|
||||
#for worker in Rota.get_workers_by_site("b"):
|
||||
# worker.assign_as_block_preferences = {"weekend b":-10}
|
||||
Rota.build_and_solve()
|
||||
Rota.export_rota_to_html("test_cons_rota", folder="tests")
|
||||
assert Rota.results.solver.status == "ok"
|
||||
|
||||
+303
-1
@@ -867,4 +867,306 @@ def test_locums():
|
||||
|
||||
Rota.export_rota_to_html("test_locums", timestamp_filename=False)
|
||||
|
||||
assert Rota.results.solver.status == "ok"
|
||||
assert Rota.results.solver.status == "ok"
|
||||
|
||||
def test_worker_assign_as_block_preference():
|
||||
"""Test that a worker's assign_as_block preference is respected over the global setting."""
|
||||
Rota = generate_basic_rota(workers=4, weeks_to_rota=12)
|
||||
|
||||
# Worker 1 prefers to have shift 'a' assigned as a block, worker 2 does not
|
||||
workers = Rota.get_workers()
|
||||
worker1 = workers[0]
|
||||
worker2 = workers[1]
|
||||
worker3 = workers[2]
|
||||
worker4 = workers[3]
|
||||
|
||||
# Set a strong preference for worker1 to have 'a' as a block
|
||||
worker1.assign_as_block_preferences = {"a":1}
|
||||
worker2.assign_as_block_preferences = {"a":-1} # Worker 2 does not want 'a' as a block
|
||||
|
||||
# Add a shift 'a' that is NOT globally set as assign_as_block
|
||||
Rota.add_shifts(
|
||||
SingleShift(
|
||||
sites=("group1",),
|
||||
name="a",
|
||||
length=8,
|
||||
days=days[:4],
|
||||
workers_required=1,
|
||||
assign_as_block=False, # global setting is off
|
||||
),
|
||||
)
|
||||
|
||||
Rota.build_and_solve(options={"ratio": 0.0})
|
||||
Rota.export_rota_to_html("test_worker_assign_as_block_preference", folder="tests")
|
||||
|
||||
# Worker 1 should have their 'a' shifts grouped together (block), worker 2 may not
|
||||
shift_list_1 = Rota.get_worker_shift_list_string(worker1)
|
||||
assert shift_list_1.count("aaaa") == 3, "Worker 1 should have all 'a' shifts grouped together (block)"
|
||||
|
||||
shift_list_2 = Rota.get_worker_shift_list_string(worker2)
|
||||
assert shift_list_2.count("a") == 12, "Worker 2 should have at 12 'a' shift, but may not be grouped together"
|
||||
|
||||
shift_list_3 = Rota.get_worker_shift_list_string(worker3)
|
||||
assert shift_list_3.count("a") == 12, "Worker 3 should have at least 12 'a' shifts, but may not be grouped together"
|
||||
|
||||
shift_list_4 = Rota.get_worker_shift_list_string(worker4)
|
||||
assert shift_list_4.count("a") == 12, "Worker 4 should have at least 12 'a' shifts, but may not be grouped together"
|
||||
|
||||
# Modify worker1's preference to prevent block 'a' shifts
|
||||
worker1.assign_as_block_preferences = {"a":-1}
|
||||
Rota.build_and_solve(options={"ratio": 0.0})
|
||||
shift_list_1 = Rota.get_worker_shift_list_string(worker1)
|
||||
assert shift_list_1.count("aaaa") == 0, "Worker 1 should have all 'a' shifts grouped together (block)"
|
||||
|
||||
worker1.assign_as_block_preferences = {"a":0}
|
||||
|
||||
a_shift = Rota.get_shift_by_name("a")
|
||||
a_shift.assign_as_block = True # Set the shift 'a' to be assigned as a block globally
|
||||
Rota.build_and_solve(options={"ratio": 0.0})
|
||||
|
||||
for worker in Rota.get_workers():
|
||||
shift_list = Rota.get_worker_shift_list_string(worker)
|
||||
# All workers should have 'a' shifts grouped together (block)
|
||||
assert shift_list.count("aaaa") == 3, f"Worker {worker.name} should have all 'a' shifts grouped together (block)"
|
||||
|
||||
def test_worker_assign_as_block_preference_multiple_shifts():
|
||||
"""Test that a worker's assign_as_block preference is respected over the global setting."""
|
||||
Rota = generate_basic_rota(workers=4, weeks_to_rota=12)
|
||||
|
||||
# Worker 1 prefers to have shift 'a' assigned as a block, worker 2 does not
|
||||
workers = Rota.get_workers()
|
||||
worker1 = workers[0]
|
||||
worker2 = workers[1]
|
||||
worker3 = workers[2]
|
||||
worker4 = workers[3]
|
||||
|
||||
# Set a strong preference for worker1 to have 'a' as a block
|
||||
worker1.assign_as_block_preferences = {"a":100}
|
||||
worker2.assign_as_block_preferences = {"b":-10000} # Worker 2 does not want 'a' as a block
|
||||
|
||||
# Add a shift 'a' that is NOT globally set as assign_as_block
|
||||
Rota.add_shifts(
|
||||
SingleShift(
|
||||
sites=("group1",),
|
||||
name="a",
|
||||
length=8,
|
||||
days=days[:4],
|
||||
workers_required=1,
|
||||
assign_as_block=False, # global setting is off
|
||||
),
|
||||
SingleShift(
|
||||
sites=("group1",),
|
||||
name="b",
|
||||
length=8,
|
||||
days=days[4:],
|
||||
workers_required=1,
|
||||
assign_as_block=False, # global setting is off
|
||||
),
|
||||
)
|
||||
|
||||
shift_list_1 = Rota.get_worker_shift_list_string(worker1)
|
||||
assert shift_list_1.count("aaaa") == 3, "Worker 1 should have all 'a' shifts grouped together (block)"
|
||||
|
||||
Rota.build_and_solve(options={"ratio": 0.0})
|
||||
Rota.export_rota_to_html("test_worker_assign_as_block_preference", folder="tests")
|
||||
|
||||
def test_worker_assign_as_block_preference_multiple_sites():
|
||||
"""Test that a worker's assign_as_block preference is respected over the global setting."""
|
||||
Rota = generate_basic_rota(workers=6, weeks_to_rota=12)
|
||||
|
||||
# Worker 1 prefers to have shift 'a' assigned as a block, worker 2 does not
|
||||
workers = Rota.get_workers()
|
||||
worker1 = workers[0]
|
||||
worker2 = workers[1]
|
||||
worker3 = workers[2]
|
||||
worker4 = workers[3]
|
||||
worker5 = workers[4]
|
||||
worker6 = workers[5]
|
||||
|
||||
# Set a strong preference for worker1 to have 'a' as a block
|
||||
worker1.assign_as_block_preferences = {"a":1}
|
||||
|
||||
worker4.site = "group2"
|
||||
worker5.site = "group2"
|
||||
worker6.site = "group2"
|
||||
worker4.assign_as_block_preferences = {"b":-10000} # Worker 2 does not want 'a' as a block
|
||||
|
||||
# Add a shift 'a' that is NOT globally set as assign_as_block
|
||||
Rota.add_shifts(
|
||||
SingleShift(
|
||||
sites=("group1",),
|
||||
name="a",
|
||||
length=8,
|
||||
days=days[:4],
|
||||
workers_required=1,
|
||||
assign_as_block=False, # global setting is off
|
||||
),
|
||||
SingleShift(
|
||||
sites=("group2",),
|
||||
name="b",
|
||||
length=8,
|
||||
days=days[4:],
|
||||
workers_required=1,
|
||||
assign_as_block=False, # global setting is off
|
||||
),
|
||||
)
|
||||
|
||||
Rota.build_and_solve(options={"ratio": 0.0})
|
||||
Rota.export_rota_to_html("test_worker_assign_as_block_preference", folder="tests")
|
||||
|
||||
def test_worker_hard_day_dependency():
|
||||
Rota = generate_basic_rota(workers=6, weeks_to_rota=16)
|
||||
|
||||
workers = Rota.get_workers()
|
||||
|
||||
worker1 = workers[0]
|
||||
worker2 = workers[1]
|
||||
worker3 = workers[2]
|
||||
|
||||
worker1.add_hard_day_dependency("Mon", "Tue")
|
||||
worker2.add_hard_day_dependency("Mon", "Wed")
|
||||
worker3.add_hard_day_dependency("Mon", "Thu")
|
||||
|
||||
Rota.add_shifts(
|
||||
SingleShift(
|
||||
sites=("group1",),
|
||||
name="a",
|
||||
length=8,
|
||||
days=days,
|
||||
workers_required=2,
|
||||
assign_as_block=False, # global setting is off
|
||||
),
|
||||
)
|
||||
|
||||
Rota.build_and_solve(options={"ratio": 0.0})
|
||||
Rota.export_rota_to_html("test_worker_hard_day_depend", folder="tests")
|
||||
|
||||
for worker in Rota.get_workers():
|
||||
shift_list = Rota.get_worker_shift_list_string(worker)
|
||||
|
||||
if worker.name == "worker1":
|
||||
# Check that every time 'a' is assigned on Monday, it is also assigned on Tuesday
|
||||
for week in range(12):
|
||||
mon_idx = week * 7 + days.index("Mon")
|
||||
tue_idx = week * 7 + days.index("Tue")
|
||||
if shift_list[mon_idx] == "a":
|
||||
assert shift_list[tue_idx] == "a", f"Worker1 assigned 'a' on Mon (week {week}) but not on Tue"
|
||||
|
||||
if worker.name == "worker2":
|
||||
# Check that every time 'a' is assigned on Monday, it is also assigned on Wednesday
|
||||
for week in range(12):
|
||||
mon_idx = week * 7 + days.index("Mon")
|
||||
wed_idx = week * 7 + days.index("Wed")
|
||||
if shift_list[mon_idx] == "a":
|
||||
assert shift_list[wed_idx] == "a", f"Worker2 assigned 'a' on Mon (week {week}) but not on Wed"
|
||||
|
||||
if worker.name == "worker3":
|
||||
# Check that every time 'a' is assigned on Monday, it is also assigned on Thursday
|
||||
for week in range(12):
|
||||
mon_idx = week * 7 + days.index("Mon")
|
||||
thu_idx = week * 7 + days.index("Thu")
|
||||
if shift_list[mon_idx] == "a":
|
||||
assert shift_list[thu_idx] == "a", f"Worker3 assigned 'a' on Mon (week {week}) but not on Thu"
|
||||
|
||||
|
||||
def test_worker_hard_day_dependency_weekend():
|
||||
Rota = generate_basic_rota(workers=4, weeks_to_rota=16)
|
||||
|
||||
workers = Rota.get_workers()
|
||||
|
||||
worker1 = workers[0]
|
||||
worker2 = workers[1]
|
||||
worker3 = workers[2]
|
||||
worker4 = workers[3]
|
||||
|
||||
worker1.add_hard_day_dependency("Fri", "Sun")
|
||||
worker2.add_hard_day_dependency("Fri", "Sun")
|
||||
worker3.add_hard_day_dependency("Fri", "Sun")
|
||||
worker4.add_hard_day_dependency("Fri", "Sun")
|
||||
|
||||
worker1.add_hard_day_exclusion("Fri", "Sat")
|
||||
worker2.add_hard_day_exclusion("Fri", "Sat")
|
||||
worker3.add_hard_day_exclusion("Fri", "Sat")
|
||||
worker4.add_hard_day_exclusion("Fri", "Sat")
|
||||
|
||||
Rota.add_shifts(
|
||||
SingleShift(
|
||||
sites=("group1",),
|
||||
name="a",
|
||||
length=8,
|
||||
days=days[4:],
|
||||
workers_required=1,
|
||||
assign_as_block=False, # global setting is off
|
||||
),
|
||||
)
|
||||
|
||||
Rota.build_and_solve(options={"ratio": 0.0})
|
||||
Rota.export_rota_to_html("test_worker_hard_day_depend", folder="tests")
|
||||
|
||||
for worker in Rota.get_workers():
|
||||
shift_list = Rota.get_worker_shift_list_string(worker)
|
||||
|
||||
# Check that every time 'a' is assigned on Monday, it is also assigned on Tuesday
|
||||
for week in range(16):
|
||||
fri_idx = week * 7 + days.index("Fri")
|
||||
sat_idx = week * 7 + days.index("Sat")
|
||||
sun_idx = week * 7 + days.index("Sun")
|
||||
if shift_list[fri_idx] == "a":
|
||||
assert shift_list[sun_idx] == "a", f"Worker1 assigned 'a' on Fri (week {week}) but not on Sun"
|
||||
|
||||
assert shift_list[sat_idx] != "a", f"Worker1 assigned 'a' on Fri (week {week}) but also on Sat, which should not happen due to hard day exclusion"
|
||||
|
||||
|
||||
def test_worker_hard_day_dependency_weekend2():
|
||||
Rota = generate_basic_rota(workers=4, weeks_to_rota=16)
|
||||
|
||||
workers = Rota.get_workers()
|
||||
|
||||
worker1 = workers[0]
|
||||
worker2 = workers[1]
|
||||
worker3 = workers[2]
|
||||
worker4 = workers[3]
|
||||
|
||||
worker1.add_hard_day_dependency("Fri", "Sun")
|
||||
worker2.add_hard_day_dependency("Fri", "Sun")
|
||||
worker3.add_hard_day_dependency("Fri", "Sun")
|
||||
worker4.add_hard_day_dependency("Fri", "Sun")
|
||||
worker4.add_hard_day_dependency("Fri", "Sat")
|
||||
|
||||
worker1.add_hard_day_exclusion("Fri", "Sat")
|
||||
worker2.add_hard_day_exclusion("Fri", "Sat")
|
||||
worker3.add_hard_day_exclusion("Fri", "Sat")
|
||||
|
||||
Rota.add_shifts(
|
||||
SingleShift(
|
||||
sites=("group1",),
|
||||
name="a",
|
||||
length=8,
|
||||
days=days[4:],
|
||||
workers_required=1,
|
||||
assign_as_block=False, # global setting is off
|
||||
),
|
||||
)
|
||||
|
||||
Rota.build_and_solve(options={"ratio": 0.0})
|
||||
Rota.export_rota_to_html("test_worker_hard_day_depend", folder="tests")
|
||||
|
||||
for worker in Rota.get_workers():
|
||||
shift_list = Rota.get_worker_shift_list_string(worker)
|
||||
|
||||
# Check that every time 'a' is assigned on Monday, it is also assigned on Tuesday
|
||||
for week in range(16):
|
||||
fri_idx = week * 7 + days.index("Fri")
|
||||
sat_idx = week * 7 + days.index("Sat")
|
||||
sun_idx = week * 7 + days.index("Sun")
|
||||
if worker != worker4 and shift_list[fri_idx] == "a":
|
||||
assert shift_list[sun_idx] == "a", f"Worker1 assigned 'a' on Fri (week {week}) but not on Sun"
|
||||
|
||||
assert shift_list[sat_idx] != "a", f"Worker1 assigned 'a' on Fri (week {week}) but also on Sat, which should not happen due to hard day exclusion"
|
||||
|
||||
if worker == worker4 and shift_list[fri_idx] == "a":
|
||||
assert shift_list[sun_idx] == "a", f"Worker4 assigned 'a' on Fri (week {week}) but not on Sun"
|
||||
assert shift_list[sat_idx] == "a", f"Worker4 assigned 'a' on Fri (week {week}) but not on Sun"
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user