Табель учёта рабочего времени (форма Т-13)
Назначение
Раздел, позволяющий корпорации выгрузить табель учёта рабочего времени по унифицированной форме Т-13 за выбранный период (обычно — календарный месяц). Без этого экспорта корпорация не может закрыть отчётность ФНС/бухгалтерии и не рассматривается к покупке как замена iiko. См. LOCALIOFFICE-998.
Экран — кнопка «Экспорт Т-13» в журнале явок, открывающая модалку с выбором периода и опциональным фильтром по подразделению/юрлицу. По нажатию «Скачать» — браузер получает xlsx-файл.
Customer Journey Map
[Журнал явок] │ └─► «Экспорт Т-13» │ ▼ [Модалка «Экспорт табеля Т-13»] • Период (dateFrom..dateTo) • Подразделение (опц.) • Юрлицо (опц.) │ └─► «Скачать» │ ▼ POST /staffing/attendances/timesheet-t13/export │ ├─► 200 → xlsx-файл (Content-Disposition: attachment) ├─► 400 → toast: «Некорректный период» └─► 404 → toast: «Подразделение/юрлицо не найдено»Эндпоинты раздела
| Метод | Маршрут | Назначение | Контроллер |
|---|---|---|---|
POST | /staffing/attendances/timesheet-t13/export | Экспорт табеля Т-13 в xlsx | attendance.controller.ts |
Селекторы для модалки используют существующие эндпоинты:
| Селектор | Откуда брать | Фильтрация |
|---|---|---|
| Подразделение | GET /organization/subdivisions | isDeleted: false |
| Юрлицо | GET /organization/legal-entities | по текущей корпорации |
DTO запроса (T13ExportDto)
| Поле | Тип | Обяз. | Описание |
|---|---|---|---|
dateFrom | string (YYYY-MM-DD) | ✅ | Нижняя граница периода |
dateTo | string (YYYY-MM-DD) | ✅ | Верхняя граница периода (включительно). Диапазон ≤ 366 дней |
subdivisionId | string (UUID) | — | Если задан — выгрузка только по одному подразделению; юрлицо в шапке файла берётся из subdivision.legalEntity |
legalEntityId | string (UUID) | — | Если задан без subdivisionId — выгрузка по всем подразделениям юрлица; в шапке имя юрлица |
Если заданы оба фильтра — subdivisionId имеет приоритет, legalEntityId игнорируется.
Если не задан ни один фильтр — выгрузка по всей корпорации, в шапке имя корпорации.
Формат ответа
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheetContent-Disposition: attachment; filename="timesheet-t13.xlsx"- Body — бинарный xlsx.
Фронту скачивание организовать через fetch → Blob → URL.createObjectURL + <a download> (стандартный паттерн для xlsx-экспортов).
Семантика данных в xlsx
Шапка файла:
- Заголовок «Табель учёта рабочего времени (форма Т-13)»
- Организация (юрлицо при фильтре по подразделению/юрлицу; имя корпорации иначе)
- Подразделение (только при фильтре по конкретному подразделению)
- Период
dateFrom – dateTo (часовой пояс корпорации)
Таблица:
- Одна строка = тройка
(сотрудник × должность × подразделение). Если сотрудник за период работал на двух должностях — две строки. - Фиксированные колонки: № п/п, табельный номер, ФИО (
Фамилия И. О.), должность, подразделение. - Дневные колонки за каждый день периода. В ячейке:
- Для «явки» (
AttendanceType.earningRule = WORK): код типа явки + часы за день. - Для «неявки» (
SICK_LEAVE,VACATION,ABSENCE,BUSINESS_TRIP,COMPENSATORY,CUSTOM): только код, часы пустые.
- Для «явки» (
- Итоговые блоки: «За I половину месяца» (
day ≤ 15), «За II половину месяца» (day ≥ 16), «Итого за период» — пара «дни / часы». - Подвал «Итого» — сумма по всем строкам.
Расчёт часов в ячейке
Position.workScheduleType | Источник часов |
|---|---|
HOURLY | Attendance.durationInMinutes для CLOSED-явок с earningRule = WORK |
SCHEDULED / SALARY | Пересечение интервала явки с плановой сменой (ScheduleEntry) того же (employeeId, positionId) за тот же учётный день |
Приоритет кода в дне с несколькими явками
Если за один учётный день у сотрудника несколько явок с разными типами, в ячейку идёт код приоритетного типа: WORK > BUSINESS_TRIP > SICK_LEAVE > VACATION > COMPENSATORY > ABSENCE > CUSTOM. Часы при этом — суммарные WORK-часы дня (неявки часы не дают).
Семантика статусов и enum’ов
AttendanceType.shortName(например, «Я», «ОТ», «Б») идёт в ячейку как буквенный код типа.- Учётный день для группировки —
Attendance.accountingDate, считается изconfirmedArrivalTime ?? registeredArrivalTimeс учётомSubdivision.timezoneиCorporation.accountingDayStartTime. Ночные смены попадают в свой учётный день.
Известные расхождения и план доработок
- ⚠️ Прямой связи
Attendance ↔ ScheduleEntryпока нет (LOCALIOFFICE-993, open). Пересечение SCHEDULED/SALARY часов считается через любую плановую смену того же дня по(employeeId, positionId). Корректно для типового случая (одна плановая смена в день). После LOCALIOFFICE-993 расчёт перейдёт на прямую связь. - ⚠️ Коэффициенты к ставке у типов явок (LOCALIOFFICE-988, in progress) и среднее число рабочих часов в месяце (LOCALIOFFICE-990, open) на Т-13 пока не влияют — экспорт показывает фактические часы из явок, без коэффициентов.
- ✅ Календарное деление полумесяцев
1..15 / 16..endработает и для произвольного периода (для периодов вне одного месяца итоги частичные).