Allow spliting forced blocks on nwdsAllow spliting forced blocks on nwds

This commit is contained in:
Ross
2021-06-28 12:02:47 +01:00
parent ab73ead7c1
commit d18c5e8a91
5 changed files with 137 additions and 102 deletions
+71 -21
View File
@@ -49,6 +49,7 @@ class SingleShift(object):
rota_on_nwds=False,
assign_as_block=False,
force_as_block=False,
force_as_block_unless_nwd=False,
hard_constrain_shift=True,
bank_holidays_only=False,
constraints=[],
@@ -71,6 +72,7 @@ class SingleShift(object):
self.rota_on_nwds = rota_on_nwds
self.assign_as_block = assign_as_block
self.force_as_block = force_as_block
self.force_as_block_unless_nwd = force_as_block_unless_nwd
self.constraints = constraints
self.bank_holidays_only = bank_holidays_only
@@ -205,13 +207,13 @@ class RotaBuilder(object):
initialize=0,
)
self.model.worker_block_shift_counts = Var(
((worker.id, week, shift) for week in self.weeks
for shift in self.shifts_to_assign_or_force_as_blocks()
for worker in self.workers),
within=NonNegativeIntegers,
initialize=0,
)
#self.model.worker_block_shift_counts = Var(
# ((worker.id, week, shift) for week in self.weeks
# for shift in self.shifts_to_assign_or_force_as_blocks()
# for worker in self.workers),
# within=NonNegativeIntegers,
# initialize=0,
#)
self.model.blocks_worker_shift_assigned = Var(
((worker.id, week, shift) for worker in self.workers
@@ -592,7 +594,7 @@ class RotaBuilder(object):
for week in self.weeks:
for shift_name in self.shifts_to_assign_or_force_as_blocks():
shift = self.get_shift_by_name(shift_name)
for worker in self.workers:
for worker in self.get_workers_for_shift(shift):
self.model.constraints.add(
8 * self.model.blocks_worker_shift_assigned[
worker.id, week, shift_name] >= sum(
@@ -607,17 +609,62 @@ class RotaBuilder(object):
for worker in self.workers))
if shift.force_as_block:
self.model.constraints.add(
self.model.worker_block_shift_counts[worker.id, week,
shift.name] ==
sum(self.model.works[worker.id, week, day, shift.name]
for day in self.days))
#self.model.constraints.add(
# self.model.worker_block_shift_counts[worker.id, week,
# shift.name] ==
# sum(self.model.works[worker.id, week, day, shift.name]
# for day in self.days))
if shift.force_as_block_unless_nwd:
workers = self.get_workers_for_shift(shift)
# Get workers who have a nwd on the shift
nwd_workers = []
full_workers = []
for w in workers:
if w.nwd is not None:
l = []
# This should take into account dates!
for nwd, d1, d2 in w.nwd:
if nwd in shift.shift_days:
l.append(w)
self.model.constraints.add(
sum(self.model.blocks_worker_shift_assigned[worker.id,
week,
shift.name]
for worker in self.workers) <= 1)
if l:
nwd_workers.append(w)
else:
full_workers.append(w)
else:
full_workers.append(w)
print(shift.name, [n.name for n in nwd_workers])
if not nwd_workers: # Just do the usual
self.model.constraints.add(
sum(self.model.blocks_worker_shift_assigned[worker.id,
week,
shift.name]
for worker in self.workers) <= 1)
else:
print(shift.name)
self.model.constraints.add(
sum(self.model.blocks_worker_shift_assigned[worker.id,
week,
shift.name]
for worker in full_workers) <= 1)
self.model.constraints.add(
sum(self.model.blocks_worker_shift_assigned[worker.id,
week,
shift.name]
for worker in workers) <= 2)
else:
self.model.constraints.add(
sum(self.model.blocks_worker_shift_assigned[worker.id,
week,
shift.name]
for worker in self.workers) <= 1)
# Most of our constraints apply per worker
for worker in self.workers:
@@ -667,7 +714,7 @@ class RotaBuilder(object):
worked, allocated = worker.previous_shifts[shift.name]
target_shifts = target_shifts + float(allocated) - float(worked)
print(worker.name, shift.name, target_shifts)
#print(worker.name, shift.name, target_shifts)
worker.shift_target_number[shift.name] = target_shifts
if shift.hard_constrain_shift:
@@ -848,7 +895,7 @@ class RotaBuilder(object):
for week, day, shift in self.get_all_shiftclass_combinations():
for n, start, end in worker.nwd:
if not shift.rota_on_nwds and day == n:
print(start, self.week_day_date_map[(week, day)], end)
#print(start, self.week_day_date_map[(week, day)], end)
if start <= self.week_day_date_map[(week, day)] <= end:
self.model.constraints.add(
0 == self.model.works[worker.id, week, day,
@@ -1072,7 +1119,7 @@ class RotaBuilder(object):
if worker_pairs[0] == worker:
workers = worker_pairs
print("Workers", workers)
#print("Workers", workers)
self.model.constraints.add(
@@ -1484,6 +1531,9 @@ class RotaBuilder(object):
s = self.shifts_to_assign_as_blocks()
s.extend(self.shifts_to_force_as_blocks())
return s
def get_workers_for_shift(self, shift):
return [worker for worker in self.workers if worker.site in shift.site]
def get_workers_total_fte(self):
return self.full_time_equivalent