add workers check

This commit is contained in:
Ross
2026-06-03 20:38:10 +01:00
parent 2949327d39
commit 09c8124cdd
+73 -3
View File
@@ -31,6 +31,44 @@ ROTA_START_DATE = "2026-08-03"
sites = ("rota a", "rota b", "rota c")
def _normalize_worker_key(value):
text = str(value or "").strip()
if not text:
return ""
return re.sub(r"\s+", " ", text).lower()
def _validate_worker_alignment(base_workers, other_workers, base_label, other_label):
"""Validate that two worker collections contain the same members.
Comparison is case-insensitive and whitespace-normalized.
Raises ValueError with a clear diff when the sets do not match.
"""
base_clean = [str(w).strip() for w in base_workers if str(w).strip()]
other_clean = [str(w).strip() for w in other_workers if str(w).strip()]
base_norm_to_raw = {_normalize_worker_key(w): w for w in base_clean}
other_norm_to_raw = {_normalize_worker_key(w): w for w in other_clean}
base_norm = set(base_norm_to_raw.keys())
other_norm = set(other_norm_to_raw.keys())
only_in_base_norm = sorted(base_norm - other_norm)
only_in_other_norm = sorted(other_norm - base_norm)
if not only_in_base_norm and not only_in_other_norm:
return
only_in_base = [base_norm_to_raw[k] for k in only_in_base_norm]
only_in_other = [other_norm_to_raw[k] for k in only_in_other_norm]
raise ValueError(
"Worker mismatch detected between sources. "
f"{base_label} only: {only_in_base}. "
f"{other_label} only: {only_in_other}."
)
def _parse_sheet_date(value):
if pd.isna(value):
return None
@@ -185,7 +223,7 @@ def extract_leave_and_rota_from_calender(calender_df):
#print(leave_requests)
return leave_requests, work_requests#, rota_data
return leave_requests, work_requests, worker_names
def extract_shift_assignments_from_rota(rota_df):
"""
@@ -319,11 +357,43 @@ def load_workers():
workers_days.append({"initial": initial, "name": name, "availability": availability, "requests": requests})
leave_requests, work_requests = extract_leave_and_rota_from_calender(calender_df)
leave_requests, work_requests, calendar_workers = extract_leave_and_rota_from_calender(calender_df)
assignments, assignments_by_worker = extract_shift_assignments_from_rota(rota_df)
print(assignments)
# Validate cross-source worker matching before constructing Worker objects.
days_workers = [w["name"] for w in workers_days]
days_initials = [w["initial"] for w in workers_days]
_validate_worker_alignment(
base_workers=days_workers,
other_workers=calendar_workers,
base_label="Days tab worker names",
other_label="Calendar tab worker names",
)
_validate_worker_alignment(
base_workers=days_initials,
other_workers=list(assignments_by_worker.keys()),
base_label="Days tab worker initials",
other_label="Rota tab assigned initials",
)
_validate_worker_alignment(
base_workers=days_initials,
other_workers=list(rota_b_assignments.keys()),
base_label="Days tab worker initials",
other_label="Rota B assignments initials",
)
_validate_worker_alignment(
base_workers=days_initials,
other_workers=list(priors_map.keys()),
base_label="Days tab worker initials",
other_label="Running totals worker initials",
)
logger.debug("Using Running totals priors for oncall/twilight/weekend A only")
workers = []
@@ -455,7 +525,7 @@ def main(
weeks_to_rota=weeks,
balance_offset_modifier=bom,
use_previous_shifts=True,
name="cons rota 2026 july",
name="cons rota test",
allow_force_assignment_with_leave_conflict=True,
constraint_options=RotaConstraintOptions(
balance_weekends=True,