feat: замещение пользователей (substitution) — заместители по умолчанию и по формам, контур ознакомления, inbox reasons

- таблица user_delegations (миграция 0067) + колонки delegated_from_user_id/pending_review в task_assignees
- delegation.service: резолвер с цепочкой и защитой от циклов, bulk-до-назначение чанками, чистка истёкших замещений
- центральный хук в addTaskAssignee: заместитель добавляется при любом назначении (ручном, автопереходе, user-поле, MCP)
- контур ознакомления: после перехода отсутствующий остаётся в исполнителях с pending_review, снимается кнопкой «Ознакомлен»
- inbox reasons delegation/delegation_review + фильтр «Замещение» на главной
- блок «Замещение» в профиле пользователя, бейдж «за <имя>» и баннер ознакомления в карточке задачи
This commit is contained in:
2026-08-05 10:44:55 +03:00
parent 17a8dc42f2
commit 667bddeac9
15 changed files with 1216 additions and 12 deletions

View File

@@ -4599,6 +4599,24 @@ To block task creation from task.before_create, set: ctx.result = { allow: false
UNION
-- Замещение: пользователь — заместитель отсутствующего исполнителя
SELECT ta_d.task_id, 'delegation' AS reason, NULL::text AS role_name
FROM task_assignees ta_d
JOIN tasks t_d ON t_d.id = ta_d.task_id AND t_d.organization_id = $1 AND t_d.is_completed = false
WHERE ta_d.user_id = $2 AND ta_d.organization_id = $1
AND ta_d.delegated_from_user_id IS NOT NULL
UNION
-- Замещение: задача ждёт ознакомления отсутствующего исполнителя
SELECT ta_r.task_id, 'delegation_review' AS reason, NULL::text AS role_name
FROM task_assignees ta_r
JOIN tasks t_r ON t_r.id = ta_r.task_id AND t_r.organization_id = $1 AND t_r.is_completed = false
WHERE ta_r.user_id = $2 AND ta_r.organization_id = $1
AND ta_r.pending_review = true
UNION
SELECT un.task_id, 'notification' AS reason, NULL::text
FROM user_notifications un
JOIN tasks t2 ON t2.id = un.task_id AND t2.organization_id = $1 AND t2.is_completed = false