Add support for requesting shifts
This commit is contained in:
@@ -21,6 +21,14 @@ days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
|
||||
|
||||
# weeks_days_product = list(itertools.product(weeks, days))
|
||||
|
||||
from govuk_bank_holidays.bank_holidays import BankHolidays
|
||||
|
||||
bank_holidays = BankHolidays()
|
||||
bank_holiday_map = {}
|
||||
for bank_holiday in bank_holidays.get_holidays():
|
||||
bank_holiday_map[bank_holiday['date']] = bank_holiday['title']
|
||||
# see BankHolidays source file for more methods and arguments…
|
||||
|
||||
|
||||
class SingleShift(object):
|
||||
"""Class to hold all details for a shift"""
|
||||
@@ -89,6 +97,11 @@ class RotaBuilder(object):
|
||||
|
||||
self.weeks_days_product = list(itertools.product(self.weeks, days))
|
||||
|
||||
if start_date.weekday() != 0:
|
||||
raise ValueError(
|
||||
"Start date {} must be a Mon (not a {})".format(
|
||||
start_date.isoformat(), days[start_date.weekday()]))
|
||||
|
||||
self.start_date = start_date
|
||||
self.rota_days_length = len(self.weeks) * 7
|
||||
self.rota_end_date = self.start_date + datetime.timedelta(
|
||||
@@ -96,6 +109,8 @@ class RotaBuilder(object):
|
||||
|
||||
self.unavailable_to_work = set()
|
||||
self.pref_not_to_work = {}
|
||||
self.work_requests = set()
|
||||
self.work_requests_map = {}
|
||||
|
||||
self.workers = []
|
||||
|
||||
@@ -338,14 +353,25 @@ class RotaBuilder(object):
|
||||
return 0
|
||||
return 1
|
||||
|
||||
#print(self.unavailable_to_work)
|
||||
|
||||
self.model.available = Param(
|
||||
((worker.id, week, day) for worker in self.workers
|
||||
for week, day in self.get_week_day_combinations()),
|
||||
initialize=availability_init,
|
||||
)
|
||||
|
||||
def work_request_init(model, wid, week, day, shift):
|
||||
if (wid, week, day, shift) in self.work_requests:
|
||||
self.work_requests_map[(wid, week, day)] = shift
|
||||
print((wid, week, day))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
self.model.work_requests = Param(
|
||||
((worker.id, week, day, shift) for worker in self.workers
|
||||
for week, day, shift in self.get_all_shiftname_combinations()),
|
||||
initialize=work_request_init,
|
||||
)
|
||||
|
||||
def pref_init(model, wid, week, day):
|
||||
if (wid, week, day) in self.pref_not_to_work:
|
||||
return self.pref_not_to_work[(wid, week, day)]
|
||||
@@ -943,13 +969,21 @@ class RotaBuilder(object):
|
||||
weekend_shift_balancing = 0
|
||||
|
||||
preference_constant = 10
|
||||
# Preferences
|
||||
# Preferences (not to work)
|
||||
preferences = sum(
|
||||
self.model.pref_not_to_work[worker.id, week, day] *
|
||||
self.model.works[worker.id, week, day, shift] *
|
||||
preference_constant for worker in self.workers
|
||||
for week, day, shift in self.get_all_shiftname_combinations())
|
||||
|
||||
# Work requsets
|
||||
work_request_constant = 1000
|
||||
work_requests = sum(
|
||||
self.model.work_requests[worker.id, week, day, shift] *
|
||||
self.model.works[worker.id, week, day, shift] *
|
||||
work_request_constant for worker in self.workers
|
||||
for week, day, shift in self.get_all_shiftname_combinations())
|
||||
|
||||
# # Spread nights
|
||||
|
||||
if self.constraint_options["balance_nights_across_sites"]:
|
||||
@@ -974,7 +1008,7 @@ class RotaBuilder(object):
|
||||
#return weekend_shift_balancing + blocks_balancing
|
||||
#return shift_balancing + preferences + blocks_balancing
|
||||
#return shift_balancing + preferences + nights_site_balancing + blocks_balancing
|
||||
return shift_balancing + night_shift_balancing + preferences + nights_site_balancing + blocks_balancing
|
||||
return shift_balancing + night_shift_balancing + preferences + nights_site_balancing + blocks_balancing - work_requests
|
||||
|
||||
# add objective function to the model. rule (pass function) or expr (pass expression directly)
|
||||
self.model.obj = Objective(rule=obj_rule, sense=minimize)
|
||||
@@ -1406,27 +1440,42 @@ class RotaResults(object):
|
||||
n = 0
|
||||
for week, day in self.rota.get_week_day_combinations():
|
||||
d = self.rota.start_date + datetime.timedelta(n)
|
||||
|
||||
n = n + 1
|
||||
a = "-"
|
||||
shift_name = ""
|
||||
|
||||
title = "{} ({})".format(shift_name, d)
|
||||
for shift in self.rota.get_shift_names_by_day(day):
|
||||
if model.works[worker.id, week, day, shift].value == 1:
|
||||
shifts.append(shift)
|
||||
a = shift[0]
|
||||
shift_name = shift
|
||||
break
|
||||
css_class = ""
|
||||
css_class = day
|
||||
if model.available[worker.id, week, day] > 0:
|
||||
available = True
|
||||
else:
|
||||
available = False
|
||||
css_class = "unavailable"
|
||||
if worker.name == "Delilah Trimmer":
|
||||
pass
|
||||
|
||||
bank_holiday = ""
|
||||
if d in bank_holiday_map:
|
||||
css_class = " ".join((css_class, "bank-holiday"))
|
||||
bank_holiday = " data-bank-holiday='{}'".format(
|
||||
bank_holiday_map[d])
|
||||
|
||||
requests = ""
|
||||
if (worker.id, week, day) in self.rota.work_requests_map:
|
||||
css_class = " ".join((css_class, "shift-requested"))
|
||||
title = " ".join((title, "[REQUESTED]"))
|
||||
requests = " data-shift-request='{}'".format(
|
||||
self.rota.work_requests_map[(worker.id, week, day)])
|
||||
|
||||
w.append(
|
||||
"<td title='{} ({})' class='rota-day {}' data-shift='{}' data-available='{}' data-date='{}' data-week='{}' data-day='{}'>{}</td>"
|
||||
.format(shift_name, d, css_class, shift_name, available, d,
|
||||
week, day, a))
|
||||
"<td title='{}' class='rota-day {}' data-shift='{}' data-available='{}' data-date='{}' data-week='{}' data-day='{}'{}{}>{}</td>"
|
||||
.format(title, css_class, shift_name, available, d, week,
|
||||
day, requests, bank_holiday, a))
|
||||
|
||||
shift_count = ""
|
||||
for s in set(shifts):
|
||||
|
||||
Reference in New Issue
Block a user