feat: persist exact Week Ahead task times (Closes #1270)
This commit is contained in:
1 parent
f78da3dfc9
commit
5fb4da30a4
11 files changed
+180
-18
No files matched your search
@@ -738,6 +738,7 @@ class WeekPlanDay(BaseModel):
|
||||
capacity_minutes: int | None = Field(default=None, ge=15, le=1440)
|
||||
estimates: dict[str, int] = Field(default_factory=dict, max_length=5)
|
||||
free_windows: list[WeekFreeWindow] | None = Field(default=None, max_length=16)
|
||||
start_times: dict[str, str] = Field(default_factory=dict, max_length=5)
|
||||
|
||||
|
||||
class WeekPlanUpdate(BaseModel):
|
||||
|
||||
@@ -578,6 +578,39 @@ class TodayStore:
|
||||
})
|
||||
previous_end = end
|
||||
plan["free_windows"] = normalized_windows
|
||||
if "start_times" in day:
|
||||
start_times = day["start_times"]
|
||||
if not isinstance(start_times, dict) or len(start_times) > 5:
|
||||
raise ValueError("task start times must be a bounded object")
|
||||
if not set(start_times).issubset(plan["ids"]):
|
||||
raise ValueError("task start times must belong to work on the same date")
|
||||
occupied = []
|
||||
for identity in plan["ids"]:
|
||||
if identity not in start_times:
|
||||
continue
|
||||
value = start_times[identity]
|
||||
if (
|
||||
not isinstance(value, str) or len(value) != 5 or value[2] != ":"
|
||||
or not value[:2].isdigit() or not value[3:].isdigit()
|
||||
or int(value[:2]) > 23 or int(value[3:]) > 59
|
||||
):
|
||||
raise ValueError("task start times must use HH:mm times")
|
||||
start = int(value[:2]) * 60 + int(value[3:])
|
||||
minutes = plan["estimates"].get(identity)
|
||||
if not isinstance(minutes, int) or start + minutes > 1440:
|
||||
raise ValueError("task start times must fit their estimates within the date")
|
||||
end = start + minutes
|
||||
if any(start < other_end and end > other_start for other_start, other_end in occupied):
|
||||
raise ValueError("task start times must not overlap")
|
||||
windows = plan.get("free_windows")
|
||||
if windows and not any(
|
||||
int(window["start_time"][:2]) * 60 + int(window["start_time"][3:]) <= start
|
||||
and end <= int(window["end_time"][:2]) * 60 + int(window["end_time"][3:])
|
||||
for window in windows
|
||||
):
|
||||
raise ValueError("task start times must fit retained free windows")
|
||||
occupied.append((start, end))
|
||||
plan["start_times"] = {identity: start_times[identity] for identity in plan["ids"] if identity in start_times}
|
||||
duplicate_ids = seen_ids.intersection(plan["ids"])
|
||||
if duplicate_ids:
|
||||
raise ValueError("work must be assigned to only one Week Ahead date")
|
||||
|
||||
Reference in new issue
Block a user