diff --git a/output/block_shifts/timetable.js b/output/block_shifts/timetable.js index 112736a..1fd3e23 100644 --- a/output/block_shifts/timetable.js +++ b/output/block_shifts/timetable.js @@ -445,9 +445,19 @@ $("#rota-table tr td:first-child").each((n, td) => { function viewWorker(worker) { ds = worker.dataset; + let exactShiftsText = "(none)"; + if (ds.exactShifts) { + try { + let parsed = JSON.parse(ds.exactShifts); + if (Object.keys(parsed).length > 0) { + exactShiftsText = Object.entries(parsed).map(([s, c]) => `${s}: ${c}`).join(", "); + } + } catch(e) {} + } dlg = $(`
Site: ${ds.site}
FTE: ${ds.fte} (${ds.fte_adj})
+ Exact shifts: ${exactShiftsText}
Start date: ${ds.start_date}
End date: ${ds.end_date}
Non working days: ${ds.nwds}
diff --git a/output/timetable.js b/output/timetable.js index 27e0bde..73a21fe 100644 --- a/output/timetable.js +++ b/output/timetable.js @@ -1783,9 +1783,19 @@ $("#rota-table tr td:first-child").each((n, td) => { function viewWorker(worker) { ds = worker.dataset; + let exactShiftsText = "(none)"; + if (ds.exactShifts) { + try { + let parsed = JSON.parse(ds.exactShifts); + if (Object.keys(parsed).length > 0) { + exactShiftsText = Object.entries(parsed).map(([s, c]) => `${s}: ${c}`).join(", "); + } + } catch(e) {} + } dlg = $(`
Site: ${ds.site}
FTE: ${ds.fte} (${ds.fte_adj})
+ Exact shifts: ${exactShiftsText}
Start date: ${ds.start_date}
End date: ${ds.end_date}
Non working days: ${ds.nwds}
diff --git a/rota_generator/shifts.py b/rota_generator/shifts.py index d73a771..2a571f2 100644 --- a/rota_generator/shifts.py +++ b/rota_generator/shifts.py @@ -5175,6 +5175,10 @@ class RotaBuilder(object): l4.extend([worker.fte for worker in self.workers]) wr.writerow(l4) + l5 = ["Exact Shifts"] + l5.extend([json.dumps(getattr(worker, "exact_shifts", {})) for worker in self.workers]) + wr.writerow(l5) + for week, day in self.get_week_day_combinations(): d = [f"Week {week} Day {day}"] @@ -5504,9 +5508,7 @@ class RotaBuilder(object): # --- Highlight force assigned shifts --- if force_assigned: css_class += " force-assigned" - title = f"{shift_name} ({d}) [FORCE ASSIGNED]" - else: - title = f"{shift_name} ({d})" + title = f"{title} [FORCE ASSIGNED]" bank_holiday = "" if d in self.bank_holidays: @@ -5546,8 +5548,9 @@ class RotaBuilder(object): if shift.has_constraint(NightConstraint): css_class = " ".join((css_class, "night-shift")) + title_escaped = title.replace("'", "'").replace('"', """) shift_tds.append( - f" @@ -5781,6 +5785,7 @@ class RotaBuilder(object): weekend_sun=sun_count, worker_summary_html=worker_summary_html, previous_shifts=json.dumps(prior_map), + exact_shifts=json.dumps(getattr(worker, "exact_shifts", {})), pair=worker.pair, shift_balance_extra=json.dumps(worker.shift_balance_extra), shift_diff=json.dumps(shift_diff_dict), diff --git a/test/test_workers.py b/test/test_workers.py index 2bb50bd..54f66e2 100644 --- a/test/test_workers.py +++ b/test/test_workers.py @@ -1832,4 +1832,40 @@ def test_exact_shifts_exceed_total_warning(): warnings = Rota.get_warnings("Exact shifts exceed total shifts") assert len(warnings) > 0 - assert "total exact shifts (4) exceeds total required shifts" in warnings[0][1] \ No newline at end of file + assert "total exact shifts (4) exceeds total required shifts" in warnings[0][1] + + +def test_html_export_worker_details_and_unavailable_reason(): + weeks_to_rota = 2 + start_date = datetime.date(2022, 3, 7) + + Rota = RotaBuilder( + start_date, + weeks_to_rota=weeks_to_rota, + ) + Rota.add_workers([ + Worker( + name="worker1", + site="group1", + grade=1, + fte=100, + exact_shifts={"a": 1}, + start_date=datetime.date(2022, 3, 14) + ), + ]) + Rota.add_shifts( + SingleShift( + sites=("group1",), + name="a", + length=12.5, + days=("Mon",), + workers_required=1, + ), + ) + Rota.build_workers() + Rota.build_model() + + html = Rota.get_worker_timetable_html() + + assert 'data-exact-shifts=\'{"a": 1}\'' in html + assert 'title=\' (2022-03-07) / START DATE: 2022-03-14\'' in html \ No newline at end of file