# Duty-schedule import format The **duty-schedule** format is used by the `/import_duty_schedule` command. Only users in `ADMIN_USERNAMES` or `ADMIN_PHONES` can import. ## Import flow 1. **Handover time** — The bot asks for the shift handover time and optional timezone (e.g. `09:00 Europe/Moscow` or `06:00 UTC`). This is converted to UTC and used as the boundary between duty periods when creating records. 2. **JSON file** — Send a file in duty-schedule format (see below). On re-import, duties in the same date range for each user are replaced by the new data. ## Format specification - **meta** (required) — Object with: - **start_date** (required) — First day of the schedule, `YYYY-MM-DD`. - **weeks** (optional) — Not used to limit length; the number of days is derived from the longest `duty` string (see below). - **schedule** (required) — Array of objects. Each object: - **name** (required) — Full name of the person (string). - **duty** (required) — String of cells separated by **`;`**. Each cell corresponds to one day starting from `meta.start_date` (first cell = start_date, second = start_date + 1 day, etc.). Empty or whitespace = no event for that day. ### Cell values (single character, case-sensitive where noted) | Value | Meaning | Notes | |-------|----------------|--------------------------| | **в**, **В**, **б**, **Б** | Duty | Any of these four | | **Н** | Unavailable | Exactly `Н` | | **О** | Vacation | Exactly `О` | | (empty/space/other) | No event | Ignored for import | The number of days in the schedule is the maximum length of any `duty` string when split by `;`. If `duty` is empty or missing, it is treated as an empty list of cells. ## Example JSON ```json { "meta": { "start_date": "2025-02-01", "weeks": 4 }, "schedule": [ { "name": "Ivanov Ivan", "duty": ";;В;;;Н;;О;;В;;" }, { "name": "Petrov Petr", "duty": ";;;В;;;;;;В;;;" } ] } ``` - **start_date** is 2025-02-01; the longest `duty` has 14 cells (after splitting by `;`), so the schedule spans 14 days (2025-02-01 … 2025-02-14). - First person: duty on day index 2 (В), unavailable on 6 (Н), vacation on 8 (О), duty on 11 (В). Other cells are empty. - Second person: duty on day indices 3 and 10. ## Validation - `meta` and `meta.start_date` must be present and valid; `start_date` must parse as `YYYY-MM-DD`. - `schedule` must be an array; each item must be an object with string `name` (non-empty after strip) and string `duty` (if missing, treated as `""`). - Invalid JSON or encoding raises an error; the parser reports missing or invalid fields (see `duty_teller.importers.duty_schedule.DutyScheduleParseError`).