Add event type handling for duties in the system
- Introduced a new `event_type` column in the `duties` table to categorize duties as 'duty', 'unavailable', or 'vacation'. - Updated the duty schedule import functionality to parse and store event types from the JSON input. - Enhanced the API response to include event types for each duty, improving the calendar display logic. - Modified the web application to visually differentiate between duty types in the calendar and duty list. - Updated tests to cover new event type functionality and ensure correct parsing and storage of duties. - Revised README documentation to reflect changes in duty event types and their representation in the system.
This commit is contained in:
@@ -4,17 +4,29 @@ import json
|
||||
from dataclasses import dataclass
|
||||
from datetime import date, timedelta
|
||||
|
||||
# Символы, обозначающие день дежурства в ячейке duty (CSV с разделителем ;)
|
||||
DUTY_MARKERS = frozenset({"б", "Б", "в", "Н", "О"})
|
||||
# Символы дежурства в ячейке duty (CSV с разделителем ;)
|
||||
DUTY_MARKERS = frozenset({"б", "Б", "в", "В"})
|
||||
UNAVAILABLE_MARKER = "Н"
|
||||
VACATION_MARKER = "О"
|
||||
|
||||
|
||||
@dataclass
|
||||
class DutyScheduleEntry:
|
||||
"""One person's schedule: full_name and three lists of dates by event type."""
|
||||
|
||||
full_name: str
|
||||
duty_dates: list[date]
|
||||
unavailable_dates: list[date]
|
||||
vacation_dates: list[date]
|
||||
|
||||
|
||||
@dataclass
|
||||
class DutyScheduleResult:
|
||||
"""Parsed duty schedule: start_date, end_date, and per-person duty dates."""
|
||||
"""Parsed duty schedule: start_date, end_date, and per-person entries."""
|
||||
|
||||
start_date: date
|
||||
end_date: date
|
||||
entries: list[tuple[str, list[date]]] # (full_name, list of duty dates)
|
||||
entries: list[DutyScheduleEntry]
|
||||
|
||||
|
||||
class DutyScheduleParseError(Exception):
|
||||
@@ -24,12 +36,12 @@ class DutyScheduleParseError(Exception):
|
||||
|
||||
|
||||
def parse_duty_schedule(raw_bytes: bytes) -> DutyScheduleResult:
|
||||
"""Parse duty-schedule JSON. Returns start_date, end_date, and list of (full_name, duty_dates).
|
||||
"""Parse duty-schedule JSON. Returns start_date, end_date, and list of DutyScheduleEntry.
|
||||
|
||||
- meta.start_date (YYYY-MM-DD) and schedule (array) required.
|
||||
- meta.weeks optional; number of days from max duty string length (split by ';').
|
||||
- For each schedule item: name (required), duty = CSV with ';'; index i = start_date + i days.
|
||||
- Cell value after strip in DUTY_MARKERS => duty day.
|
||||
- Cell value after strip: в/В/б/Б => duty, Н => unavailable, О => vacation; rest ignored.
|
||||
"""
|
||||
try:
|
||||
data = json.loads(raw_bytes.decode("utf-8"))
|
||||
@@ -53,7 +65,7 @@ def parse_duty_schedule(raw_bytes: bytes) -> DutyScheduleResult:
|
||||
raise DutyScheduleParseError("Missing or invalid 'schedule' (must be array)")
|
||||
|
||||
max_days = 0
|
||||
entries: list[tuple[str, list[date]]] = []
|
||||
entries: list[DutyScheduleEntry] = []
|
||||
|
||||
for row in schedule:
|
||||
if not isinstance(row, dict):
|
||||
@@ -75,11 +87,24 @@ def parse_duty_schedule(raw_bytes: bytes) -> DutyScheduleResult:
|
||||
max_days = max(max_days, len(cells))
|
||||
|
||||
duty_dates: list[date] = []
|
||||
unavailable_dates: list[date] = []
|
||||
vacation_dates: list[date] = []
|
||||
for i, cell in enumerate(cells):
|
||||
d = start_date + timedelta(days=i)
|
||||
if cell in DUTY_MARKERS:
|
||||
d = start_date + timedelta(days=i)
|
||||
duty_dates.append(d)
|
||||
entries.append((full_name, duty_dates))
|
||||
elif cell == UNAVAILABLE_MARKER:
|
||||
unavailable_dates.append(d)
|
||||
elif cell == VACATION_MARKER:
|
||||
vacation_dates.append(d)
|
||||
entries.append(
|
||||
DutyScheduleEntry(
|
||||
full_name=full_name,
|
||||
duty_dates=duty_dates,
|
||||
unavailable_dates=unavailable_dates,
|
||||
vacation_dates=vacation_dates,
|
||||
)
|
||||
)
|
||||
|
||||
if max_days == 0:
|
||||
end_date = start_date
|
||||
|
||||
Reference in New Issue
Block a user