Add support for avoiding shifts on specific dates with reasons

This commit is contained in:
Ross
2026-01-05 22:07:23 +00:00
parent e6bdd4a09e
commit d66ddf29ad
5 changed files with 200 additions and 6 deletions
+90 -2
View File
@@ -1,5 +1,5 @@
import csv
from datetime import datetime
from datetime import datetime, timedelta
import re
import sys
from requests import Session
@@ -264,4 +264,92 @@ def load_academy(Rota):
"""
Some trainees spend month blocks in the academy. This function loads that information from a google sheet that published it as a csv file.
"""
url = "https://docs.google.com/spreadsheets/d/e/2PACX-1vQtNrp9F1fjtAh8vFX-W_R3RlD9H-2P_vCLMoHrVKR0e24yabbsdrD65VjwxoHlV1Qnatmw1NeghQHG/pub?gid=1113837782&single=true&output=csv"
url = "https://docs.google.com/spreadsheets/d/e/2PACX-1vQtNrp9F1fjtAh8vFX-W_R3RlD9H-2P_vCLMoHrVKR0e24yabbsdrD65VjwxoHlV1Qnatmw1NeghQHG/pub?gid=1113837782&single=true&output=csv"
with Session() as s:
headers = {"Cache-Control": "no-cache", "Pragma": "no-cache"}
download = s.get(url, headers=headers)
decoded = download.content.decode("utf-8")
reader = csv.reader(decoded.splitlines(), delimiter=',')
n = 0
names = []
# collect date rows (these are the month start boundaries) and their cells
date_rows: list[datetime.date] = []
date_row_cells: list[list[str]] = []
for row in reader:
n += 1
if n == 1:
# header row: first cell is column title, remaining are worker names
names = [c.strip() for c in row[1:]]
continue
if not row:
continue
row_title = row[0].strip()
cells = row[1:]
# If this row is a date row like '02/03/2026' then treat it as a month-start boundary
if re.match(date_re, row_title):
try:
try:
d = datetime.strptime(row_title, "%d/%m/%Y").date()
except ValueError:
d = datetime.strptime(row_title, "%d/%m/%y").date()
except Exception:
continue
date_rows.append(d)
# normalize cells length to match names
row_cells = [ (cells[i] if i < len(cells) else "").strip() for i in range(len(names)) ]
date_row_cells.append(row_cells)
# If no date rows found, nothing to do
if not date_rows:
return
# Identify twilight shift names available in the rota
twilight_shift_names = [s.name for s in Rota.get_shifts() if "twilight" in s.name]
# For each date boundary, compute its end (next boundary - 1 day) and register avoids where cell=='academy'
for idx, start_date in enumerate(date_rows):
if idx + 1 < len(date_rows):
end_date = date_rows[idx + 1] - timedelta(days=1)
else:
end_date = Rota.rota_end_date
cells = date_row_cells[idx]
for i, cell in enumerate(cells):
if i >= len(names):
break
v = (cell or "").lower()
if "academy" in v:
worker_name = names[i]
matching_workers = [w for w in Rota.workers if w.name.strip() == worker_name.strip()]
if not matching_workers:
logger.warning(f"Academy data: worker '{worker_name}' not found in rota, skipping")
continue
worker = matching_workers[0]
# choose twilight shifts relevant to the worker's site
candidate_shifts = []
for sh_name in twilight_shift_names:
try:
sh = Rota.get_shift_by_name(sh_name)
except Exception:
continue
if hasattr(worker, "site") and worker.site in sh.sites:
candidate_shifts.append(sh_name)
elif sh_name.startswith(f"{worker.site}_"):
candidate_shifts.append(sh_name)
if not candidate_shifts:
candidate_shifts = twilight_shift_names.copy()
# register as a date range with a reason 'academy'
Rota.add_avoid_shifts_for_workers_on_dates(
names=[worker.name], shifts=candidate_shifts, start_date=start_date, end_date=end_date, reason="academy"
)