Files
proc-rota/gen_cons.py
T
2025-06-05 23:40:17 +01:00

197 lines
5.1 KiB
Python

import datetime
import os
import sys
import time
from rota.shifts import NoWorkers, RotaBuilder, SingleShift, WorkerRequirement, days
import typer
import subprocess
from rota.workers import (
Worker,
NotAvailableToWork,
NonWorkingDays,
WorkRequests,
PreferenceNotToWork,
OutOfProgramme,
)
app = typer.Typer()
sites = ("rota a", "rota b", "rota c")
@app.command()
def main(
suspend: bool = False,
solve: bool = True,
time_to_run: int = 60 * 60,
ratio: float = 0.001,
start_date: datetime.datetime = "2025-09-01",
weeks: int = 16,
bom: int = 1,
):
rota_start_date = start_date.date()
suspend_on_finish = suspend
Rota = RotaBuilder(
rota_start_date,
weeks_to_rota=weeks,
balance_offset_modifier=bom,
name="cons rota",
)
# Rota = RotaBuilder(start_date, weeks_to_rota=20, balance_offset_modifier=1)
Rota.constraint_options["balance_shifts"] = False
Rota.constraint_options["balance_shifts_quadratic"] = True
Rota.constraint_options["balance_weekends"] = True
Rota.constraint_options["max_night_frequency"] = 3 # 3
Rota.constraint_options["max_night_frequency_week_exclusions"] = []
Rota.constraint_options["max_weekend_frequency"] = 4
Rota.constraint_options["hard_constrain_pair_separation"] = True
Rota.constraint_options["max_shifts_per_week"] = 3
# Rota.constraint_options["avoid_st2_first_month"] = True
Rota.add_shifts(
SingleShift(
sites=("rota a",),
name="oncall weekday",
length=12.5,
days=days[:4],
balance_offset=2,
constraint=[
{
"name": "max_shifts_per_week",
"options": 3,
}
],
),
SingleShift(
sites=("rota a",),
name="Oncall weekend",
length=12.5,
days=days[4:],
balance_offset=2,
assign_as_block=True,
constraint=[
{
"name": "max_shifts_per_week",
"options": 3,
},
{"name": "pre", "options": 2},
{"name": "post", "options": 2},
],
),
SingleShift(
sites=("rota a",),
name="weekend a",
workers_required=1,
length=12.5,
days=days[5:],
balance_offset=2,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 2},
],
display_char="a",
),
SingleShift(
sites=("rota b", "rota c"),
name="weekend b",
workers_required=1,
length=12.5,
days=days[5:],
balance_offset=2,
constraint=[
{"name": "pre", "options": 2},
{"name": "post", "options": 2},
],
display_char="b",
),
SingleShift(
sites=(
"rota a",
"rota b",
),
name="evening",
workers_required=1,
length=12.5,
days=days[:5],
balance_offset=2,
constraint=[],
),
)
# Rota.add_grade_constraint_by_week([2], [1, 2], ["night_weekday", "night_weekend"])
load_leave = True
Rota.build_shifts()
# Rota.add_grade_constraint_by_week([2], [1], Rota.get_shift_names())
for w in range(1, 12):
w = Worker(name=f"A{w:02d}", site="rota a", grade=1)
print(w)
Rota.add_worker(w)
for w in range(12, 21):
w = Worker(
name=f"B{w}",
site="rota b",
grade=1,
nwds=[
NonWorkingDays(
day="Fri",
)
],
)
print(w)
Rota.add_worker(w)
# Rota.build_workers()
# Rota.build_model()
solver_options = {"ratio": ratio, "seconds": time_to_run, "threads": 10}
# solver_options = {"seconds": time_to_run, "threads": 10}
# start_time = time.time()
Rota.build_and_solve(solver_options, export=True, solve=solve, solver="appsi_highs")
# Rota.solve_shifts_by_block(solver_options, block_length=13)
# Rota.solve_shifts_individually(solver_options)
# Rota.solve_model(options=solver_options)
# end_time = time.time()
# print(f"Time taken {end_time-start_time}")
# print(Rota.get_worker_details())
# optimizer = SolverFactory('cbc')
# result = optimizer.solve(prob,tee=True)
# result.Solver.Status = SolverStatus.warning
# prob.solutions.load_from(result)
# ResultsHolder = RotaResults(Rota)
# worker_timetable_brief = ResultsHolder.get_worker_timetable_brief(
# show_prefs=False, show_unavailable=False
# )
#
# print(worker_timetable_brief)
# Rota.export_rota_to_html("proc_rota")
# Rota.export_rota_to_csv("rota")
subprocess.run(
["scp", Rota.exported_rota_file, "ross@46.101.13.46:proc/proc-rota/output/"]
)
if suspend_on_finish:
os.system("systemctl suspend")
if __name__ == "__main__":
app()