ТЗ: отпуска, больничные и отгулы
Редакция от 01.10.2026. Рабочая версия с комментариями — документ Claude Docs; этот файл — её копия в репозитории.
1. Цель и принципы
Модуль отвечает на один вопрос: кто и когда отсутствует. Сотрудник подаёт отпуск, больничный или отгул за свой счёт, руководитель решает, вся система видит, что человека нет. Деньги модуль не считает и не двигает: ни отпускных, ни вычетов, ни оплаты больничного. Это учёт присутствия, а не расчёт.
- Одна сущность — отсутствие. Отпуск, больничный и отгул за свой счёт различаются видом, правилами согласования и подтверждающим документом, но живут в одной таблице и на одном экране.
- Без денег. Отсутствие не создаёт платежей, строк табеля, вычетов и начислений. Табель видит отсутствие только как подсказку руководителю. Если позже понадобится вычет за отгул, он останется ручной строкой табеля, как сейчас.
- Не блокирует работу. Сотрудник в отпуске может зайти в систему, отметить часы или закрыть задачу. Система подсказывает, но не запрещает.
- Один поток согласования. Заявка, решение руководителя, затем генерального директора, уведомление. Больничный согласования не требует: его регистрируют, а руководитель принимает к сведению.
- Остатки — в днях, не в деньгах. Модуль ведёт норму отпуска за год и остаток в календарных днях. Это справочная цифра для сотрудника и руководителя, не бухгалтерский баланс.
- Встраивается, а не добавляет раздел. Отсутствия — третий вид страницы «Табель» рядом с «Моими часами» и «Командой», остаток — ещё и в профиле. Календарь отсутствий — виджет на главной.
Что не входит: расчёт отпускных и больничных, экспорт в 1С и кадровые приказы, график отпусков как юридический документ, перенос остатков между годами по ТК (остаток переносится простым правилом, см. раздел 5).
2. Как устроено сейчас
Отсутствий в системе нет совсем: ни таблицы, ни поля, ни экрана. Единственный след — ручная строка «Вычет» в табеле с подсказкой «отгул, больничный — до учёта отсутствий». Зато есть всё, на что модуль опирается: оргструктура, согласование командировок как образец, уведомления, файлы, табель.
| Что | Как сейчас | Что это значит для модуля |
|---|---|---|
| Сотрудник и руководитель | У сотрудника есть руководитель (users.manager_id), основной отдел и дополнительные, руководитель отдела (departments.manager_id). Подчинённые считаются рекурсивно. Даты приёма на работу нет | Согласующий берётся тем же правилом, что и в табеле. Норму отпуска нельзя считать от даты приёма — нужно новое поле |
| Командировки | Ближайший аналог: заявка с датами, согласующий, статусы «запланирована → согласована → в пути → завершена», проверка пересечений, лента «Расписание» на главной. Уведомлений у командировок нет | Модуль повторяет схему модуля и боковую панель командировок; отсутствие не должно пересекаться с командировкой |
| Рабочий день | Везде «не суббота и не воскресенье»: срок выплаты, серия дней, черновик табеля помощника, пятничное напоминание. Производственного календаря и праздников нет | Нужен один общий календарь компании (праздники и переносы), иначе отпуск считается неверно |
| Напоминания о часах | Сотруднику в 18:00 за сегодня, руководителю отдела в 10:00 за вчера; выходные не учитываются | В дни отсутствия напоминания нужно гасить |
| Серия дней (прогресс) | Рабочий день без часов рвёт серию через два рабочих дня | Отпуск не должен рвать серию: дни отсутствия считаются как выходные |
| Табель | Оклад целиком в день начисления, смены — дни с часами, вычет — ручная строка. В «Команде» видно часы без табеля и с какой даты | Табель получает подсказку «в периоде отпуск 5 дней», расчёт не меняется |
| Главная | «Расписание» на 7 или 30 дней (логистика и командировки), «Загрузка людей» = часы за месяц / 168 | Отсутствия добавляются третьей группой в «Расписание»; норма загрузки уменьшается на дни отсутствия |
| Задачи | Срок и исполнитель есть, об отсутствии исполнителя ничего не знают | Карточка задачи получает метку «исполнитель в отпуске до…» |
| Файлы | Файл привязывается к сущности из списка (проект, задача, командировка, сотрудник…), права проверяются по сущности | Скан больничного — новая сущность absence в списке, виден сотруднику и руководителю |
| Уведомления | Тип + текст + ключ от повторов; фронт ведёт по префиксу типа | Новые типы absence.* и маршрут к заявке |
| Права | Матрица объектов по ролям; для табелей — own_timesheet (всем) и others_timesheets (руководитель дивизиона — свой); признаки для интерфейса из /org/me | Отсутствия идут по тем же объектам, новый объект матрицы не нужен |
| Экраны | «Табель» с видами «Мои часы» и «Команда», профиль с вкладками, карточка сотрудника в админке, сетка месяца часов. Календарного компонента в дизайн-системе нет | Новый раздел меню не нужен; календарь команды — новый компонент на базе сетки месяца |
3. Виды отсутствий
Четыре вида различаются тем, кто решает, как считаются дни и какой остаток они тратят.
| Вид | Кто заводит | Решение | Дни | Остаток | Документ |
|---|---|---|---|---|---|
| Отпуск | Сотрудник; руководитель и администратор — за сотрудника | Руководитель, затем генеральный директор | Календарные, праздники не входят | Отпуска | Не нужен |
| Больничный | Сотрудник, руководитель или администратор — кто узнал первым | Действует сразу; руководитель принимает к сведению | Календарные; конец может быть открыт | Не тратит | Скан листа нетрудоспособности — по желанию |
| Отгул за свой счёт | Сотрудник; руководитель — за сотрудника | Руководитель, затем генеральный директор | Рабочие | Не тратит | Не нужен |
| Отгул в счёт переработки | Сотрудник; руководитель — за сотрудника | Руководитель, затем генеральный директор | Рабочие | Переработки: 8 ч за день, 4 ч за половину | Не нужен |
Отпуск. Период от даты до даты, можно делить на части. Дни считаются календарные, как в ТК: отпуск с понедельника по воскресенье — 7 дней. Праздничные дни из календаря компании в отпуск не входят и остаток не уменьшают. Заявка подаётся заранее; срок «заранее» — настройка компании, по умолчанию 14 дней; позже — можно, но согласующие видят пометку «поздняя заявка».
Больничный. Человек заболел сегодня и не знает, когда выйдет, поэтому дата окончания необязательна. Больничный действует с момента регистрации, а руководитель нажимает «Принять к сведению»: пока не нажал, больничный висит у него в очереди и раз в рабочий день приходит напоминание. Открытый больничный действует, пока сотрудник или руководитель не закроет его датой выхода. Заводить задним числом можно: болеющий не всегда в системе.
Отгул за свой счёт. Один или несколько рабочих дней, выходные внутри периода не считаются. «За свой счёт» — только название вида: вычет модуль не считает, руководитель видит отгул в табеле подсказкой и решает сам.
Отгул в счёт переработки. Тратит накопленную переработку: часы сверх нормы дня в рабочие дни и все часы в выходные и праздники (раздел 5). Денег не касается: переработка — справочная величина в часах, оплаты сверхурочных модуль не считает.
Половина дня. Отпуск, отгул за свой счёт и отгул в счёт переработки можно взять на половину одного дня — утро или вторая половина. Такое отсутствие стоит 0,5 дня отпуска или 4 часа переработки. Многодневное отсутствие половинками не начинается и не заканчивается. Больничный — только целые дни.
Общее для всех: комментарий сотрудника необязателен; поле «Кто на связи» — необязательный заместитель, виден команде и в карточке задачи. Другие виды (удалённая работа, учёба) добавляются как новые значения вида без новых таблиц.
4. Основной сценарий
Сотрудник подаёт заявку, руководитель решает, система сама переводит отсутствие в «Действует» и «Завершён» по датам.
stateDiagram-v2
[*] --> pending: заявка (отпуск, отгулы)
[*] --> active: больничный — сразу
pending --> pending_director: руководитель согласовал
pending --> rejected: отказ с причиной
pending_director --> approved: генеральный директор утвердил
pending_director --> rejected: отказ с причиной
approved --> active: наступила дата начала
active --> done: период прошёл
pending --> cancelled: отмена до начала
approved --> cancelled: отмена до началаОтклонённую заявку сотрудник подаёт заново с другими датами. Генеральный директор — настройка компании (по умолчанию первый активный владелец). Если руководитель и есть генеральный директор или заявку подал сам генеральный директор, лишний шаг пропускается.
- Заявка. В «Табель → Отсутствия» или в профиле сотрудник нажимает «Отсутствие», выбирает вид и даты (для одного дня — целый день или половина). Форма сразу показывает число дней, остаток отпуска или переработки и пересечения: с другим отсутствием, командировкой, задачами со сроком в эти дни.
- Руководитель. Заявка уходит руководителю сотрудника (
users.manager_id); нет его — руководителю основного отдела, нет и его — сразу генеральному директору. Руководитель видит заявку в очереди с подсказкой, кто ещё из отдела отсутствует в эти дни, и решает: «Согласовать» или «Отклонить» с причиной. - Генеральный директор. Согласованная руководителем заявка переходит к нему с пометкой, кто и когда согласовал. «Утвердить» или «Отклонить» с причиной. Сотрудник получает уведомление о каждом решении.
- Больничный. Действует с момента регистрации. Руководитель получает уведомление «Иванов на больничном с 01.10» и нажимает «Принять к сведению»; на статус это не влияет. Закрыть больничный датой выхода может любой из них, скан листа — по желанию.
- Действует. С даты начала система показывает метку «В отпуске до 15.10» везде, где виден сотрудник, меняет его статус в чате и включает автоответ. Напоминания о часах в эти дни не приходят.
- Завершён. На следующий день после даты окончания воркер переводит отсутствие в «Завершён». Открытый больничный без даты выхода остаётся «Действует»; через 14 дней руководитель получает напоминание уточнить дату.
Отмена и отзыв: сотрудник отменяет свою заявку до даты начала без причины, руководитель или генеральный директор отзывает согласованное до начала с причиной. Действующее отсутствие не отменяют, а закрывают раньше: сотрудник вышел — дата окончания сдвигается, неиспользованные дни возвращаются в остаток.
5. Правила
Правила проверяет сервер, форма повторяет их подсказками до нажатия кнопки. Запретов мало, предупреждений больше: решает руководитель, а не система.
| Правило | Запрет или предупреждение |
|---|---|
| Два отсутствия одного сотрудника с общими днями | Запрет (409 absences_overlap). Отклонённые и отменённые не считаются. Больничный поверх отпуска — разрешён: отпуск укорачивается до дня перед больничным, остаток возвращается, руководитель получает уведомление |
| Отпуск или отгул пересекается с командировкой (запланирована, согласована, в пути) | Запрет с ссылкой на командировку. Больничный — разрешён, организатор командировки получает уведомление. То же правило с другой стороны: командировку на дни отпуска не создать |
| Начало в прошлом | Сотрудник: отпуск и отгул — запрет, больничный — до 60 дней назад. Руководитель и администратор — любая дата (забыли оформить), сразу в статусе «Согласован» или «Завершён» |
| Поздняя заявка на отпуск (меньше срока из настроек, по умолчанию 14 дней) | Предупреждение сотруднику и пометка руководителю |
| Отпуск длиннее остатка | Предупреждение «превышение на 3 дня» обоим; согласовать можно, остаток уходит в минус |
| Отгулов за свой счёт больше порога за год (настройка, по умолчанию 5 рабочих дней) | Предупреждение руководителю в заявке |
| Срок задачи сотрудника попадает в отсутствие | Предупреждение в заявке со списком задач; при постановке задачи на отсутствующего — предупреждение автору |
| Своя заявка руководителя | Согласует его руководитель, затем генеральный директор; заявка самого генерального директора — сразу «Согласован» |
Правка. Заявку «На согласовании» сотрудник правит свободно. Согласованную — только сокращает; сдвинуть или удлинить — значит снова согласовать (статус возвращается в «На согласовании», прежние даты видны в истории). У действующего меняется только дата окончания: раньше — свободно, позже — больничный просто продлевается, отпуск и отгул продлевает руководитель. Руководитель и администратор правят любое отсутствие подчинённого; каждая правка — в истории с автором.
Отмена. До даты начала — сотрудник без причины, руководитель с причиной. После начала отмены нет, есть раннее закрытие. Завершённое отсутствие не удаляется, администратор может пометить его «ошибочным» — дни возвращаются в остаток.
Остаток отпуска. Норма — настройка компании (по умолчанию 28 календарных дней в год), у сотрудника может быть своя. Остаток на год = норма + перенос с прошлого года + корректировки администратора − дни согласованных и завершённых отпусков года. Неиспользованный остаток переносится целиком. При запуске модуля администратор вводит каждому стартовый остаток корректировкой с причиной «остаток на 01.01.2026». Норма не делится по месяцам стажа: даты приёма в системе нет, а точный кадровый расчёт не цель модуля.
Переработка. Считается из записей часов с даты запуска модуля (настройка «Учёт переработок с»): в рабочий день — часы сверх 8, в выходной или праздник — все часы; дни отсутствия не считаются рабочими. Остаток = накоплено + корректировки администратора в часах − согласованные отгулы в счёт переработки (8 ч за день, 4 ч за половину). Правка часов задним числом сразу меняет остаток. Отгул сверх остатка — предупреждение обоим согласующим, не запрет.
Половина дня. Только у отсутствия в один день («с» = «по»), отметка «утро» или «вторая половина». Две половины одного дня не пересекаются; в такой день норма для напоминаний и кольца — 4 ч.
Календарь компании. Праздники и переносы рабочих дней ведёт администратор; при запуске заполняется производственным календарём РФ на текущий и следующий год. Одна функция «рабочий ли день» заменяет четыре нынешние проверки «не суббота и не воскресенье»: срок выплаты, серия, черновик помощника, пятничное напоминание.
6. Влияние на остальную систему
Отсутствие нигде не запрещает действие и нигде не считает деньги. Оно меняет три вещи: что система показывает, кого не дёргает напоминаниями и какие дни считает рабочими.
| Где | Что меняется |
|---|---|
| Часы | Запись часов в день отсутствия разрешена (вышел на день из отпуска), но форма предупреждает, а в таблице у записи метка «в отпуске». Таймер задачи работает как обычно |
| Табель | В предпросмотре и карточке табеля — строка-подсказка «Отсутствия в периоде: отпуск 05–09.10 (5 дн.), отгул 14.10». Строк начисления не добавляется, оклад и смены считаются как сейчас. Вычет остаётся ручным: кнопка «Вычет за отгул» только подставляет причину и дни, сумму вводит руководитель |
| «Команда» в табеле | У сотрудника в отсутствии — метка вместо «не заданы условия оплаты»; дни отсутствия не считаются «часами без табеля старше порога» |
| Серия и кольцо дня | День отсутствия для серии — как выходной: не рвёт и не продлевает. Кольцо в шапке в такой день показывает «Отпуск» вместо «0 из 8 ч» |
| Напоминания о часах | Сотруднику в 18:00 и руководителю в 10:00 — не приходят за дни отсутствия. Быстрая отметка не открывается. Утренняя сводка помощника руководителю получает строку «Сегодня отсутствуют: …» |
| Задачи | В карточке задачи рядом с исполнителем — «в отпуске до 15.10, на связи Петров». В списке и на доске — значок у аватара. При назначении со сроком в дни отсутствия — предупреждение автору, не запрет |
| Справочник и команда проекта | Метка «Отсутствует до …» у сотрудника в справочнике, карточке и составе команды. Практика «ушёл в отпуск — выключили сотрудника» заканчивается: «неактивен» остаётся только для уволенных |
| Командировки | Проверка пересечения с отпуском и отгулом при создании командировки, та же ошибка, что у пересекающихся командировок |
| Главная | В «Расписании» — группа «Отсутствия» на 7 или 30 дней. «Загрузка людей» делит часы на норму без дней отсутствия (норма 168 ч минус 8 ч за каждый рабочий день отсутствия). Руководитель видит виджет «Кто отсутствует» с очередью заявок |
| Помощник | Инструмент «кто отсутствует» и «мой остаток отпуска»; действие «подать заявку на отпуск» с подтверждением |
| Живые обновления | Маршруты /absences* дают событие absence; «Команда», виджет и календарь обновляются без перезагрузки |
| Чаты | У сотрудника в отсутствии статус «В отпуске до 15.10» (больничный, отгул) в списке чатов и в шапке личного чата. Автоответ: на первое за день личное сообщение каждого собеседника система отвечает от имени сотрудника «Я в отпуске до 15.10. По срочным вопросам — Петров» с пометкой «автоответ». Текст автоответа сотрудник может задать в заявке или выключить. В групповых чатах — только статус, без автоответа |
Чего не происходит: задачи не переназначаются, сроки не сдвигаются, табель не пересчитывается, платежи не создаются.
7. Экраны фронтенда
Нового раздела в меню нет: отсутствия живут там, где человек уже смотрит на свои часы и на команду. Всё собирается из дизайн-системы (AppSidePanel, AppDialog, AppDataTable, AppStatusChip, AppStatTiles); новый компонент один — календарь команды на месяц, на базе сетки месяца из «Моих часов».
| Экран | Сейчас | Станет |
|---|---|---|
| «Табель» | Виды «Мои часы» и «Команда» | Третий вид «Отсутствия» — у всех. Вверху плитки: остаток отпуска, переработка, следующее отсутствие, у решающих — «Ждут решения». Ниже очередь заявок (только у руководителей и генерального директора), затем календарь отдела на месяц и список своих отсутствий за год. Кнопки в шапке: «Отсутствие» и «Выгрузить в Excel» (для тех, кто видит нескольких) |
| «Табель → Мои часы» | Плитки, сетка месяца, записи | Дни отсутствия в сетке месяца закрашены с подписью вида, праздники затенены |
| Карточка отсутствия | — | Боковая панель, как у командировки: вид, даты (или половина дня), дни, статус, решения руководителя и генерального директора с датами, кто на связи, автоответ, комментарий, файл больничного, история. Кнопки по статусу и роли: Согласовать, Утвердить, Отклонить, Принять к сведению, Отменить, Закрыть раньше, Продлить. Открывается по ссылке /timesheets?view=absences&absence=ID и из уведомлений. Коллега из отдела видит в ней только вид, даты и кто на связи |
| Диалог «Отсутствие» | — | Вид (четыре варианта), даты «с — по» (у больничного «по» необязательно), для одного дня — «Весь день / Утро / Вторая половина», счётчик дней и остатка, «Кто на связи», текст автоответа (можно выключить), комментарий, файл. Под датами — предупреждения из раздела 5. Руководитель открывает тот же диалог с выбором сотрудника |
| Карточка сотрудника («Сотрудники») | Вкладки Профиль, Доступ, Проекты, Оплата, NDA | Вкладка «Отсутствия»: норма отпуска сотрудника, остаток по годам, переработка, корректировки с причиной, список отсутствий |
| Профиль | Вкладки Профиль, Задачи, Проекты, Прогресс, Оформление, Безопасность | На вкладке «Профиль» — карточка «Отпуск»: остаток, переработка, следующее отсутствие, кнопка «Подать» |
| Главная | «Расписание»: логистика и командировки | В «Расписании» группа «Отсутствия». Руководителю и генеральному директору — виджет «Кто отсутствует»: сегодня, ближайшая неделя, заявки на решение |
| Карточка задачи, справочник, команда проекта, чаты | Имя и отдел | Метка «В отпуске до 15.10» рядом с именем через общий AppUser |
| Администрирование | «Зарплата» — настройки выплат | Новая страница «Календарь и отсутствия»: праздники и переносы по годам, настройки (генеральный директор, норма отпуска, срок подачи, порог отгулов, напоминание об открытом больничном, учёт переработок с даты) |
Календарь отдела. Строка — сотрудник, колонка — день, полоска — отсутствие с цветом вида, половина дня — половина ячейки, «на согласовании» — пунктиром, командировки — серым для контекста. Месяц листается стрелками, выходные и праздники затенены, сегодня выделено. Сотрудник видит коллег своих отделов; руководитель — ещё и подчинённых, те, кто видит всех, — фильтр по отделу. Нажатие на полоску открывает карточку. На телефоне календарь сворачивается в список «кто когда».
Выгрузка в Excel. Файл «График отсутствий 2026.xlsx» с двумя листами: «Отсутствия» (сотрудник, отдел, вид, с, по, дней, статус, кто согласовал и когда) и «Остатки» (сотрудник, норма, перенос, использовано, осталось, переработка). В файл попадают те же сотрудники, что видны на экране, с тем же фильтром по отделу.
Статусы и подписи — только через реестры (statuses.ts: набор absence — pending, pending_director, approved, active, done, rejected, cancelled; dictionaries.ts: absenceKind, absenceHalf), как требует guard. Признаки прав — из /org/me: absences_decide (решает как руководитель), absences_director (утверждает вторым уровнем), absences_manage (заводит за любого, правит норму, остатки и календарь).
8. Данные, API, права, уведомления
Новый модуль internal/modules/absences по обычной схеме (model, service, repository_pg, transport_http, тесты) и маленький пакет internal/workcalendar с одной функцией «рабочий ли день» для всех модулей. Связи с табелем, задачами, командировками, чатами и напоминаниями — через интерфейсы сервисов в композиционном корне, как сделано для выплат по табелям. Миграции начинаются с 0175.
Схема
| Таблица | Поля |
|---|---|
absences (новая) | user_id, kind (vacation, sick, unpaid, overtime_off), date_from, date_to (NULL — открытый больничный), half (NULL — целые дни, am / pm — половина одного дня), days NUMERIC(6,1) (снимок: календарные без праздников для отпуска, календарные для больничного, рабочие для отгулов), status (pending, pending_director, approved, active, done, rejected, cancelled), comment, backup_user_id, auto_reply (текст; NULL — выключен), requested_by, manager_id + manager_decided_at, director_id + director_decided_at, acknowledged_by + acknowledged_at (больничный), decision_note, late, created_at, updated_at. Индексы по (user_id, date_from) и по status; запрет пересечения — проверка в транзакции с блокировкой строки сотрудника |
absence_events (новая) | История: absence_id, actor_id, action (created, updated, approved, director_approved, rejected, acknowledged, cancelled, closed_early, extended), before, after JSONB, note, created_at |
absence_adjustments (новая) | Корректировки остатков: user_id, balance (vacation — дни на год year, overtime — часы), amount со знаком, reason, created_by, created_at |
company_calendar (новая) | date (ключ), kind (holiday, workday — перенос на выходной), name |
absence_settings (новая, одна строка) | director_id (генеральный директор; NULL — первый активный владелец), vacation_days_per_year 28, notice_days 14, unpaid_warn_days 5, open_sick_reminder_days 14, overtime_since (дата запуска), updated_by, updated_at |
users | Новое поле vacation_days_per_year (NULL — по настройке компании) |
chat_messages | Признак автоответа kind = 'auto_reply' (вид сообщения уже есть: forwarded) |
files | Сущность absence в списке сущностей; доступ — сотрудник, его руководитель, генеральный директор, администратор |
Переходы по датам делает воркер раз в час: approved → active с даты начала, active → done на следующий день после окончания; там же напоминания. Чтение «кто отсутствует в дату» не зависит от воркера: оно считается по датам и статусу approved / active.
API
| Метод и путь | Назначение |
|---|---|
GET /absences/my?year= | Свои отсутствия за год, остаток отпуска (норма, перенос, корректировки, использовано, осталось) и переработка в часах |
POST /absences | Подать: {user_id?, kind, date_from, date_to?, half?, comment?, backup_user_id?, auto_reply?}. За другого — только тот, кто решает по нему |
POST /absences/check | Проверка без сохранения: дни, остаток после, согласующие, предупреждения (overlap, trip, late, over_balance, over_overtime, unpaid_many, tasks_due) |
GET /absences, GET /absences/:id | Отсутствия в охвате (status, user_id, from, to, department_id, queue=mine — ждут моего решения, пагинация); карточка с историей и файлами |
GET /absences/calendar?from&to&department_id? | Календарь отдела: сотрудники, их отсутствия и командировки, праздники периода |
GET /absences/export?year&department_id? | Выгрузка в Excel: листы «Отсутствия» и «Остатки» |
PATCH /absences/:id | Даты, половина, комментарий, кто на связи, автоответ — по правилам раздела 5 |
POST /absences/:id/approve, /reject, /acknowledge, /cancel, /close | Решения, «принять к сведению» и раннее закрытие. approve сам понимает уровень: руководитель или генеральный директор. reject и отмена согласующим требуют {note} |
GET /absences/users/:id, POST /absences/users/:id/adjustments, PATCH /absences/users/:id/norm | Карточка сотрудника: остатки по годам и переработка, корректировка с причиной, личная норма |
GET /absences/today?user_ids= | Кто из списка отсутствует сегодня — для меток в задачах, справочнике, команде и чатах (один запрос на экран) |
GET /calendar?year=, PUT /calendar/:date, DELETE /calendar/:date | Праздники и переносы |
GET /absences/settings, PUT /absences/settings | Настройки отсутствий |
Списки — каноническим конвертом transport.RespondList, ошибки — через реестр текстов (absences_overlap, absences_trip_overlap, absences_past_date, absences_note_required, absences_transition_forbidden, absences_half_day_range, absences_forbidden). Существующие ответы получают поле absence там, где нужна метка: строка «Команды» табеля, карточка задачи, предпросмотр табеля (absences_in_period).
Права
| Действие | Кто может |
|---|---|
| Подать своё отсутствие, видеть свои и свои остатки | Каждый |
| Видеть вид и даты отсутствий коллег | Все сотрудники своих отделов (основного и дополнительных); метку «отсутствует до…» у имени видит каждый. Комментарии, решения и файлы — только сам сотрудник и те, кто решает |
| Видеть отсутствия за пределами своего отдела | Руководитель — подчинённых; чтение others_timesheets — свой дивизион или всех; генеральный директор и администратор — всех |
| Согласовать первым уровнем, принять больничный к сведению, подать за сотрудника | Руководитель сотрудника (по оргструктуре, иначе руководитель отдела); администратор |
| Утвердить вторым уровнем, отозвать согласованное | Генеральный директор из настроек; администратор |
| Норма сотрудника, корректировки остатков, календарь, настройки | Запись users_and_rights (владелец, операционный директор), администратор; читать календарь может каждый |
| Выгрузка в Excel | Те, кто видит отсутствия нескольких сотрудников, — в своём охвате |
Новый объект матрицы не заводится; docs/concepts/permissions-matrix.md получает строку о том, какие объекты гейтят отсутствия.
Уведомления
| Событие | Тип | Кому |
|---|---|---|
| Новая заявка, заявка перешла ко второму уровню | absence.requested | Тому, чьё решение сейчас нужно |
| Больничный зарегистрирован, продлён, закрыт | absence.sick | Руководителю; организатору пересекающейся командировки |
| Согласовано руководителем, утверждено, отклонено, отозвано | absence.decided | Сотруднику, с причиной |
| Заявка без решения два рабочих дня, больничный не принят к сведению за рабочий день | absence.pending_reminder | Тому, чьё решение нужно, раз в день |
| Открытый больничный дольше порога | absence.sick_open | Руководителю и сотруднику |
| Завтра начинается отсутствие подчинённого | absence.starts_tomorrow | Руководителю, одним списком за день |
Ключ от повторов — тип:идентификатор:получатель:дата, как у табелей. Уведомление открывает карточку отсутствия.
9. Этапы и приёмка
Три этапа, каждый выкатывается на staging отдельно и полезен сам по себе. После первого команда уже видит, кто когда отсутствует.
| Этап | Что входит | Результат |
|---|---|---|
| 1. Заявки и календарь | Модуль и миграции; календарь компании с праздниками РФ на 2026–2027; четыре вида и половины дня; два уровня согласования и «принять к сведению»; правила пересечений (в том числе с командировками); файл больничного; история; уведомления; воркер статусов. Экраны: вид «Отсутствия» (очередь, календарь отдела, мои отсутствия), карточка и диалог, страница «Календарь и отсутствия» с праздниками и генеральным директором | Сотрудник подаёт, руководитель и генеральный директор решают, отдел видит календарь |
| 2. Встраивание | Общая функция «рабочий день» в табеле, серии, помощнике и напоминаниях; напоминания о часах молчат в дни отсутствия; серия не рвётся, кольцо показывает отсутствие; подсказка в табеле; метки в задачах, справочнике, команде проекта; статус и автоответ в чатах; проверка пересечения в командировках; группа в «Расписании»; виджет «Кто отсутствует»; строка в сводке помощника | Отсутствие видно везде, где виден человек, и никого не дёргает зря |
| 3. Остатки, переработка, Excel | Норма отпуска, остаток по годам с переносом, корректировки и стартовые остатки; переработка и её расход отгулами; предупреждения о превышении; вкладка «Отсутствия» в карточке сотрудника; карточка «Отпуск» в профиле; выгрузка в Excel; инструменты помощника; «Загрузка людей» с учётом отсутствий | Сотрудник знает свои остатки, руководство выгружает график |
Приёмочный сценарий
Проходится через интерфейс целиком со сверкой базы после каждого шага; он же становится шагом e2e-сценария.
- [ ] Администратор видит праздники года, добавляет перенос, выбирает генерального директора и вводит инженеру стартовый остаток 10 дней.
- [ ] Инженер подаёт отпуск на неделю через три дня: форма показывает 7 дней, остаток 3, согласующих и пометку «поздняя заявка». Отпуск поверх своей командировки подать нельзя.
- [ ] Руководитель получает уведомление и согласует; заявка уходит генеральному директору, он утверждает. Инженер получает два уведомления, отпуск виден коллегам из отдела в календаре и в «Расписании».
- [ ] Инженер подаёт отгул в счёт переработки на половину дня внутри отпуска — отказ «пересекается»; вне отпуска — форма показывает переработку и списание 4 ч. Отменяет отпуск до начала — остаток снова 10.
- [ ] Руководитель регистрирует инженеру больничный с вчерашнего дня без даты окончания: он сразу «Действует» и уже принят к сведению. В карточке задачи инженера — метка, напоминание в 18:00 не приходит, серия дней не рвётся.
- [ ] Коллега пишет инженеру в личный чат: видит статус «На больничном» и получает один автоответ; второе сообщение того же дня автоответа не получает.
- [ ] Инженер закрывает больничный сегодняшним днём и прикрепляет скан; файл виден руководителю и не виден коллеге.
- [ ] Руководитель формирует табель за период с больничным: в карточке есть подсказка об отсутствии, сумма и строки не изменились, платежей не прибавилось.
- [ ] Генеральный директор выгружает график в Excel: в файле отпуск инженера и его остатки совпадают с экраном.
- [ ] Старт, пауза и завершение задачи в день отсутствия проходят без ошибок; на телефоне календарь сворачивается в список, страница не шире экрана.
Готовность каждого этапа
- Тесты сервиса (пересечения, счёт дней с праздниками, переходы, остаток),
go test ./..., проверка контрактов. - Контракты перегенерированы,
docs/concepts/absences.mdнаписан, правки вtimesheets.md,permissions-matrix.md,realtime-sync.md. - Миграции проверены в обе стороны на локальной базе; перед staging — дамп.
- Фронтенд проходит guard, проверку типов и e2e; новый пункт меню «Календарь» добавлен в ожидаемые меню ролей e2e.
10. Решения по открытым вопросам
Все вопросы первой редакции закрыты 01.10.2026. Решения уже внесены в разделы выше.
| Вопрос | Решение |
|---|---|
| Кто согласует | Руководитель сотрудника по оргструктуре; если не задан — руководитель отдела |
| Второй уровень согласования | Нужен: сначала руководитель, потом генеральный директор — для отпуска и обоих отгулов |
| Как считать отпуск | Календарными днями, праздники не входят |
| Остаток в конце года | Переносится на следующий год |
| Половины дня и отгул в счёт переработки | Нужны: четвёртый вид отсутствия и половина одного дня для всех видов, кроме больничного |
| Кто видит календарь | Вся команда отдела: вид и даты коллег; комментарии и файлы — только сотрудник и согласующие |
| Больничный | Действует сразу, руководитель принимает к сведению |
| Скан больничного | Необязателен, загрузить можно |
| Выгрузка в Excel | Нужна: отсутствия и остатки за год |
| Статус в чате | Меняется; в личных чатах работает автоответ |