/Employee/ByEmail на портале обновился: сотрудник может числиться в
нескольких компаниях, теперь отдаётся массив записей (одна на компанию).
ITnsuPortalClient.GetEmployeeByEmailAsync возвращает IReadOnlyList вместо
одного объекта; вызывающие места используют первую запись (как и раньше
при одиночном ответе), кроме нового HeadType.CompanyDirectors — там нужны
все компании.
HeadType.CompanyDirectors резолвится в директора КАЖДОЙ компании
инициатора — по одной строке результата на компанию, все с одним и тем
же OrderNo шага (они и так один шаг, то есть параллельны по построению).
Директор ищется через GetEmployeeByPositionAsync(position, company) с
захардкоженной должностью «Директор» по умолчанию и явными исключениями
для компаний, где директора называют иначе (ТОО KazPromService — «Главный
механик», ТОО СТ Global — «Генеральный директор»).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Раньше по ответу резолва нельзя было отличить «руководителя направления» от
«директора Tansu» иначе как парсингом Position (реальной должности из
справочника api.tnsu.kz, свободный текст). PositionCode — это HeadType
самого шага (Chief/DirectionHead/DirectorTansu/ManagingDirectorTansu/
DepartmentHead), null для шагов с исполнителем по email/должности/роли.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Раньше шаг маршрута мог нести ровно одно условие (field_name/operation/
value). Теперь условий может быть сколько угодно, а их объединение задаётся
явно — ConditionsLogic.And (все условия) или .Or (любое из условий).
Бэкенд:
- Новая сущность TemplateRouteStepCondition (дочерняя таблица
template_route_step_conditions, FK на шаг, cascade delete) вместо трёх
колонок на TemplateRouteStep. Миграция AddMultipleStepConditions переносит
существующие условия шагов в новую таблицу перед удалением старых колонок,
чтобы не потерять уже настроенные в деве/проде условия.
- TemplateRouteService.MatchesConditions: несколько условий шага объединяются
по ConditionsLogic (Any/All); HasUnevaluatableManagerCondition проверяет
условие на IsManager в списке условий, а не единственное поле.
- TemplateRouteStepService: дубликаты шагов теперь сравниваются по всему
набору условий (без учёта порядка) и, если условий два и более, по логике
их объединения — сравнение в памяти, а не в SQL, кандидатов на дубликат
в пределах маршрута всегда мало.
- Валидация условия: раньше «все три поля или ни одного», теперь — в каждом
элементе списка все три поля обязательны.
Фронтенд:
- RouteStepFormModal: условие — динамический список строк (добавить/удалить),
у каждой строки свой набор допустимых операторов по типу колонки; селектор
И/ИЛИ появляется, когда условий два и больше.
- describeStepCondition в таблице шагов склеивает все условия через « И »/« ИЛИ ».
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Правила из frontend/.gitignore перенесены в корневой .gitignore,
дублирующий файл удалён. README дополнен описанием SPFx frontend
(ApprovalAdmin), который ранее был ошибочно указан как отсутствующий.
4-слойная архитектура (Api/Application/Domain/Infrastructure) на .NET 10
с MediatR и EF Core + PostgreSQL, без бизнес-логики. Добавлены
docker-compose, .env.example и README для локального запуска.