1 Задача

This commit is contained in:
dipatrik10
2026-08-06 01:10:33 +03:00
parent 28268a38c0
commit 5276729a69
33 changed files with 3569 additions and 19 deletions

View File

@@ -841,6 +841,77 @@ API возвращает `409 Conflict`; соседние интервалы и
}
```
### Отсутствия преподавателей и мастер замены
| Метод | URL | Назначение |
|-------|-----|------------|
| `GET` | `/api/teacher-absences?status=` | Доступный текущей роли реестр отсутствий |
| `POST` | `/api/teacher-absences` | Зарегистрировать отсутствие или отправить преподавательскую заявку |
| `POST` | `/api/teacher-absences/{id}/review` | Подтвердить или отклонить заявку преподавателя |
| `DELETE` | `/api/teacher-absences/{id}` | Отменить ожидающее или ещё не обработанное отсутствие |
| `GET` | `/api/teacher-absences/{id}/wizard` | Затронутые занятия, проверенные кандидаты и журнал решений |
| `POST` | `/api/teacher-absences/{id}/resolve` | Атомарно применить выбранные решения |
Доступ имеют `ADMIN`, `EDUCATION_OFFICE`, `DEPARTMENT` и `TEACHER`. Преподаватель видит и
создаёт только собственные заявки; они получают статус `PENDING`. Кафедра работает только с
преподавателями, назначенными ей на период отсутствия. Ответственный сотрудник создаёт
сразу согласованную запись `APPROVED`, а кафедра, учебный отдел или администратор могут
перевести преподавательскую заявку в `APPROVED` либо `REJECTED`.
```json
{
"teacherId": 15,
"startDate": "2026-09-10",
"endDate": "2026-09-12",
"reason": "Командировка"
}
```
Для роли `TEACHER` поле `teacherId` игнорируется в пользу ID текущего пользователя. Период
включительный, не длиннее 120 дней и не может пересекаться с другой активной записью того
же преподавателя.
`GET /{id}/wizard` ищет фактические занятия через `ScheduleQueryService`. Кандидат на замену
должен иметь связь с дисциплиной; если для этой связи настроены `teacher_lesson_types`, тип
занятия также обязан совпасть. Из списка исключаются архивные, занятые и отсутствующие
преподаватели. Варианты переноса выбираются среди ближайших учебных дат вне периода
отсутствия, аудитории — среди активных и свободных. Каждый кандидат заранее проходит тот же
валидатор `ScheduleOverrideService`, что и обычная разовая правка.
Пример группового подтверждения:
```json
{
"decisions": [
{
"baseRuleSlotId": 31,
"lessonDate": "2026-09-10",
"resolution": "REPLACE_TEACHER",
"newTeacherId": 28,
"comment": "Согласовано кафедрой"
},
{
"baseRuleSlotId": 44,
"lessonDate": "2026-09-11",
"resolution": "MOVE_TIME",
"targetLessonDate": "2026-09-14",
"newTimeSlotId": 3
},
{
"baseRuleSlotId": 52,
"lessonDate": "2026-09-12",
"resolution": "REJECT"
}
]
}
```
Допустимые решения: `REPLACE_TEACHER`, `MOVE_TIME`, `CHANGE_CLASSROOM`, `CANCEL`, `REJECT`.
Первые четыре создают обычный `schedule_override`; `REJECT` фиксирует осознанное отклонение
без изменения расписания. Весь пакет выполняется в одной транзакции: конфликт любого
выбранного действия возвращает `409` и откатывает остальные. Незаполненные занятия не
меняются. Когда обработаны все оставшиеся занятия, отсутствие получает статус `RESOLVED`.
## Загруженность
| Метод | URL | Назначение |