Enhance weekend shift handling by adding per-day adjustments and improving prior allocation parsing

This commit is contained in:
Ross
2025-12-17 12:13:56 +00:00
parent 710a2aa7c8
commit 0851b992fb
3 changed files with 99 additions and 15 deletions
+62 -14
View File
@@ -4967,27 +4967,72 @@ class RotaBuilder(object):
prev = getattr(worker, "previous_shifts", {}) or {}
if shift.name in prev:
entry = prev[shift.name]
# entry may be a tuple (worked, allocated) or a dict with per-day entries
# entry may be:
# - a tuple/list: (worked, allocated)
# - a dict with per-day entries (e.g., {'Sat': (w,a), 'Sun': (w,a)})
# - a dict with an '__all__' key or other buckets
if isinstance(entry, dict):
# prefer a day-specific entry if available (variable `d` holds the day name in scope)
if d in entry:
worked, allocated = entry[d]
elif "__all__" in entry:
worked, allocated = entry["__all__"]
# If the dict already contains per-day keys (Sat/Sun) or an explicit
# '__all__' bucket, preserve the dict as-is so downstream code
# can render per-day adjustments. Otherwise, attempt to aggregate
# any tuple-like values found in the dict into totals.
if any(k in entry for k in ("Sat", "Sun")) or "__all__" in entry:
prior_map[shift.name] = entry
# also compute an overall adjustment for the adjustments list
try:
# compute totals by summing tuple/list values where present
worked = sum(v[0] for v in entry.values() if isinstance(v, (list, tuple)))
allocated = sum(v[1] for v in entry.values() if isinstance(v, (list, tuple)))
adj = float(allocated) - float(worked)
except Exception:
adj = 0
else:
# fallback: sum any tuple values found in the dict
worked = sum(v[0] for v in entry.values() if isinstance(v, (list, tuple)))
allocated = sum(v[1] for v in entry.values() if isinstance(v, (list, tuple)))
try:
worked = sum(v[0] for v in entry.values() if isinstance(v, (list, tuple)))
allocated = sum(v[1] for v in entry.values() if isinstance(v, (list, tuple)))
adj = float(allocated) - float(worked)
except Exception:
worked = 0
allocated = 0
adj = 0
prior_map[shift.name] = dict(worked=worked, allocated=allocated, adjustment=adj)
else:
worked, allocated = entry
try:
adj = float(allocated) - float(worked)
except Exception:
adj = 0
prior_map[shift.name] = dict(worked=worked, allocated=allocated, adjustment=adj)
# tuple/list style entry
try:
worked, allocated = entry
adj = float(allocated) - float(worked)
except Exception:
worked = 0
allocated = 0
adj = 0
prior_map[shift.name] = dict(worked=worked, allocated=allocated, adjustment=adj)
if adj != 0:
adjustments_list.append(f"{shift.name}:{adj:+g}")
# If weekend prior is present as a top-level worked/allocated dict (not per-day),
# expand it into per-day entries so Sat/Sun adjustments are always available.
if 'weekend' in prior_map:
w = prior_map['weekend']
# detect the simple dict shape produced earlier: {'worked': x, 'allocated': y, 'adjustment': z}
if isinstance(w, dict) and 'worked' in w and 'allocated' in w and not ('Sat' in w or 'Sun' in w or '__all__' in w):
try:
worked = float(w.get('worked', 0))
allocated = float(w.get('allocated', 0))
# split evenly across Sat and Sun
sat_worked = worked / 2.0
sun_worked = worked - sat_worked
sat_alloc = allocated / 2.0
sun_alloc = allocated - sat_alloc
prior_map['weekend'] = {
'Sat': (sat_worked, sat_alloc),
'Sun': (sun_worked, sun_alloc),
}
except Exception:
# leave as-is if parsing fails
pass
adjustments_html = ""
if adjustments_list:
adjustments_html = (
@@ -5039,6 +5084,9 @@ class RotaBuilder(object):
sign_text = f"{adjf:+.2f}"
# colour intensity scaled by magnitude (cap divisor at 3.0 to avoid overpowering)
mag = min(1.0, abs(adjf) / 3.0)
# ensure a minimum alpha so small adjustments remain visible
if mag < 0.12:
mag = 0.12
if adjf > 0:
bg = f"rgba(0,128,0,{mag:.2f})"
color = "#fff"