diff --git a/.gitignore b/.gitignore index 2a60edd..f23b54e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,8 @@ sample.txt *.csv *.html *.log +current.log +extended proc nights only.log +no nights.log +no twighlights.log +no weekends.log diff --git a/run.py b/run.py index d0c2078..39d5146 100644 --- a/run.py +++ b/run.py @@ -23,7 +23,7 @@ sites = ("truro", "exeter", "torquay", "barnstaple", "plymouth") Rota = RotaBuilder(datetime.date(2020, 9, 7), weeks_to_rota=weeks_to_rota, - balance_offset_modifier=4, + balance_offset_modifier=1, max_weekend_frequency=2, max_night_frequency=2) @@ -259,9 +259,14 @@ rota_collections['nights + proc twighlights + normal weekends'].add_shifts( rota_collections['nights + proc twighlights + proc weekends'].add_shifts( SingleShift((sites), - "proc_twilight_and_weekends", + "proc_twilight", 12.5, - days, + days[:5], + workers_required=3), + SingleShift((sites), + "proc_weekends", + 12.5, + days[5:], workers_required=3), #SingleShift((sites), "night", 12.5, days, balance_weighting=1, workers_required=3, rota_on_nwds=True), SingleShift((sites), diff --git a/s.js b/s.js index a0614f0..a7a5201 100644 --- a/s.js +++ b/s.js @@ -14,86 +14,145 @@ Object.defineProperties(Array.prototype, { } }); -rows = $(".table-div table .worker-row"); -//console.log(trs) +const mean = arr => arr.reduce( ( p, c ) => p + c, 0 ) / arr.length; -workers = {}; +tables = $(".table-div"); -rows.each((n, tr) => { +tables.each((n, table) => { + console.log(table) - //console.log(tr); + rows = $(table).find(".worker-row"); + console.log(rows) - worker_td = $(tr).find("td:first"); + workers = {}; - worker = worker_td.attr("data-worker"); + rows.each((n, tr) => { - shift_tds = $(tr).find(".rota-day"); - shifts = [] + //console.log(tr); - shift_tds.each((n, td) => { - shifts.push($(td).attr("data-shift")); - }) + worker_td = $(tr).find("td:first"); - shifts_unique = new Set(shifts); - shifts_unique.delete(""); - //console.log(shifts_unique); + worker = worker_td.attr("data-worker"); - weekends_worked = 0; + shift_tds = $(tr).find(".rota-day"); + shifts = [] - weeks = shift_tds.length / 7; + shift_tds.each((n, td) => { + shifts.push($(td).attr("data-shift")); + }) - whole_weekends_worked = 0; + shifts_unique = new Set(shifts); + shifts_unique.delete(""); + //console.log(shifts_unique); - for(var i = 1; i <= weeks; i++) { - //console.log($(tr).find(`[data-week='${i}'][data-day='Sat']`)); - if($(tr).find(`[data-week='${i}'][data-day='Sat']`).attr("data-shift") != "" || $(tr).find(`[data-week='${i}'][data-day='Sun']`).attr("data-shift") != "") { weekends_worked = weekends_worked + 1; } - if($(tr).find(`[data-week='${i}'][data-day='Sat']`).attr("data-shift") != "" && $(tr).find(`[data-week='${i}'][data-day='Sun']`).attr("data-shift") != "") { whole_weekends_worked = whole_weekends_worked + 1; } - } + weekends_worked = 0; - shift_counts = {}; + weeks = shift_tds.length / 7; - total_shifts = 0; - days_lost = 0; - shifts_unique.forEach(el => { - //console.log(el); - shift_counts[el] = shifts.count(el); - total_shifts = total_shifts + shifts.count(el); + whole_weekends_worked = 0; - if(el == "night_weekday") { days_lost = days_lost + shifts.count(el) / 4 * 5 } - if(el == "night_weekend") { - days_lost = days_lost + shifts.count(el) / 3 * 4 - whole_weekends_worked = whole_weekends_worked - shifts.count(el) / 3 - } + for(var i = 1; i <= weeks; i++) { + //console.log($(tr).find(`[data-week='${i}'][data-day='Sat']`)); + if($(tr).find(`[data-week='${i}'][data-day='Sat']`).attr("data-shift") != "" || $(tr).find(`[data-week='${i}'][data-day='Sun']`).attr("data-shift") != "") { weekends_worked = weekends_worked + 1; } + if($(tr).find(`[data-week='${i}'][data-day='Sat']`).attr("data-shift") != "" && $(tr).find(`[data-week='${i}'][data-day='Sun']`).attr("data-shift") != "") { whole_weekends_worked = whole_weekends_worked + 1; } + } - }); + shift_counts = {}; - days_lost = days_lost + whole_weekends_worked - console.log(worker, whole_weekends_worked); + total_shifts = 0; + days_lost = 0; + shifts_unique.forEach(el => { + //console.log(el); + shift_counts[el] = shifts.count(el); + total_shifts = total_shifts + shifts.count(el); - //days_lost = days_lost + whole_weekends_worked; - //console.log(shift_counts); + // 5 days for weekday nights + if(el == "night_weekday") { days_lost = days_lost + shifts.count(el) / 4 * 5 } + // 4 days for weekend nights + if(el == "night_weekend") { + days_lost = days_lost + shifts.count(el) / 3 * 4 + whole_weekends_worked = whole_weekends_worked - shifts.count(el) / 3 + } + // 0.5 for twilights + if(el.includes("twilight")) { days_lost = days_lost + shifts.count(el) / 2 } - workers[worker] = { - "site": worker_td.attr("data-site"), - "nwds": worker_td.attr("data-nwds"), - "fte": worker_td.attr("data-fte_adj"), - "end_date": worker_td.attr("data-end_date"), - "shifts": shifts, - "shift_types": shifts_unique, - "weekends_worked": weekends_worked, - "shift_counts": shift_counts, - "days_lost": days_lost, - //"shifts" - } + }); - sc = JSON.stringify(shift_counts); + // Also 1 day for a whole weekend + days_lost = days_lost + whole_weekends_worked + console.log(worker, whole_weekends_worked); - worker_td.after(`
Total shifts: ${total_shifts}, Weekends: ${weekends_worked}, Training days lost: ${days_lost}, ${sc}
`) + //days_lost = days_lost + whole_weekends_worked; + //console.log(shift_counts); -}) + workers[worker] = { + "site": worker_td.attr("data-site"), + "nwds": worker_td.attr("data-nwds"), + "fte": worker_td.attr("data-fte_adj"), + "end_date": worker_td.attr("data-end_date"), + "shifts": shifts, + "shift_types": shifts_unique, + "weekends_worked": weekends_worked, + "shift_counts": shift_counts, + "days_lost": days_lost, + //"shifts" + } -$("th.worker").append($("").click(() => { - $(".rota-day").toggle(); - $(".worker-summary").toggle(); + sc = JSON.stringify(shift_counts); -})) \ No newline at end of file + worker_td.after(`
Total shifts: ${total_shifts}, Weekends: ${weekends_worked}, Training days lost: ${days_lost}, ${sc}
`) + + }) + + sites = {}; + sites_days_lost = {} + for (const worker in workers) { + //console.log(worker, workers[worker]); + w = workers[worker]; + if (w.fte == 100) { + //console.log(w.shift_types); + for (let shift of w.shift_types) { + //console.log(shift); + if (!(w.site in sites)) { + sites[w.site] = {}; + + } + if (!(shift in sites[w.site])) { + sites[w.site][shift] = [w.shift_counts[shift]]; + } else { + sites[w.site][shift].push(w.shift_counts[shift]); + } + } + if (!(w.site in sites_days_lost)) { + sites_days_lost[w.site] = [w.days_lost]; + + } else { + sites_days_lost[w.site].push(w.days_lost); + } + } + } + + // Calculate site shift summaries + $(table).append("
Average shifts for a 100% FTE trainee
"); + + for (const site in sites) { + console.log(site, $("div")); + $(table).find(".site-summary").append(`
${site}
`); + + for (const shift in sites[site]) { + console.log(sites[site][shift]); + average = mean(sites[site][shift]) + $(table).find(`.site-${site}`).append(`
${shift}: ${average.toFixed(2)}
`); + } + + days_lost_avg = mean(sites_days_lost[site]); + $(table).find(`.site-${site}`).append(`
Training days lost: ${days_lost_avg.toFixed(2)}
`); + } + + + $(table).before($("").click(() => { + $(table).find(".rota-day").toggle(); + $(table).find(".worker-summary").toggle(); + + })) +}); \ No newline at end of file diff --git a/timetable.css b/timetable.css index 5844ef9..af0374e 100644 --- a/timetable.css +++ b/timetable.css @@ -53,6 +53,11 @@ tr:hover { background-color: lightblue; } +tr:hover .unavailable{ + + background-color: lightgray; +} + th.worker { max-width: 100%; width: 200px; @@ -78,4 +83,26 @@ th.worker { .worker-summary { position: absolute; display: none; +} +.site-summary { + display: inline-flex; +} + +.site-summary .site { + border: 1px solid black; + padding: 5px; + margin: 20px; +} + +.site-name { + font-weight: bold; +} + +.worker-summary span { + min-width: 160px; + display: inline-flex; +} + +.training-days-lost { + padding-top: 5px; } \ No newline at end of file