Маршрутизация — диагностический чеклист¶
Чеклист для диагностики проблем с переходами по маршруту. Каждый пункт: симптом, проверка, решение.
Чеклист «Почему переход не сработал»¶
flowchart TD
A["Переход не сработал"] --> B{"Что наблюдаем?"}
B -- "Кнопки перехода не видно" --> C["Нет прав на переход, либо кнопка скрыта: HiddenStep или смарт-фильтр видимости"]
B -- "Кнопка есть, но переход не идёт" --> D{"Запрашивались подписи?"}
D -- "да, статус «На подписи»" --> E["Подписи не обработаны; не указан статус возврата при отклонении — задача застряла"]
D -- "нет" --> F["Не заполнены обязательные ДП, либо смарт «Перед переходом» отменил переход"]
B -- "Автопереход по подзадачам не сработал" --> G{"Дочерние — подзадачи или связанные?"}
G -- "связанные задачи" --> H["Автопереход отслеживает только подзадачи — нужны дочерние, не связанные"]
G -- "подзадачи" --> I["Обязательные ДП на переходе; есть незакрытые подзадачи; несколько автопереходов из статуса"]
1. Обязательные ДП на переходе не заполнены¶
Симптом. Пользователь нажимает кнопку перехода, ДП подсвечиваются красным, переход не выполняется. Либо автопереход (при завершении подзадач, по смарту) молча не срабатывает.
Проверка.
Администратор: открыть настройки перехода, вкладка «Доп. параметры» — там список ДП, обязательных для данного перехода.
SQL — найти обязательные ДП на переходе:
SELECT
sepr.StepID,
sris.StepDescr AS TransitionName,
sepr.ExtParamID,
ep.ExtParamName
FROM StepExtParamRestrictions sepr
JOIN StatesRoutesInSubcat sris ON sris.StepID = sepr.StepID
JOIN ExtParams ep ON ep.ExtParamID = sepr.ExtParamID
WHERE sris.SubcatID = @SubcatID
ORDER BY sris.StepID;
SQL — проверить, заполнены ли обязательные ДП у конкретной задачи:
SELECT
sepr.ExtParamID,
ep.ExtParamName,
epv.ExtParamValue
FROM StepExtParamRestrictions sepr
JOIN ExtParams ep ON ep.ExtParamID = sepr.ExtParamID
LEFT JOIN ExtParamValues epv ON epv.ExtParamID = sepr.ExtParamID AND epv.TaskID = @TaskID
WHERE sepr.StepID = @StepID;
API — при попытке перехода API возвращает data.ok = false и массив requiredExtParams с ID незаполненных ДП:
{
"data": {
"ok": false,
"requiredExtParams": [1234, 5678]
}
}
Решение.
- Заполнить обязательные ДП до перехода.
- Если переход автоматический (смарт, автопереход при завершении подзадач) — убедиться, что смарт-действие «Перед переходом» заполняет эти ДП, либо убрать обязательность с перехода.
- Частая ошибка: включили
AutoPerformStepOnSubtasksClose, но на целевом переходе есть обязательные ДП — автопереход не сработает, потому что некому их заполнить. - Если пользователь видит значение в поле, а переход отклоняется с «Заполните параметры»: значение, набранное без клика вне поля, сохраняет сама кнопка перехода — тип «Текст» со сборки 2.268.692, «Большой текст», «Число» и «Деньги» со сборки 2.268.700. На более старых сборках и на мобильной карточке такой отказ ожидаем: перед переходом значение не записывается.
2. Нет прав на переход¶
Симптом. Кнопка перехода не отображается вообще, или пользователь видит кнопку, но при нажатии получает ошибку.
Проверка.
Три уровня ограничения доступа к переходу (все в настройках перехода):
| Настройка | Поле БД | Поведение |
|---|---|---|
| Ограничить доступ (по умолчанию) | — | Кнопка только для пользователей с правом «Исполнять» |
| Ограничить доступ (выбрана настройка) | — | Кнопка скрыта согласно выбранному ограничению |
| Смарт-фильтр видимости | VisibilitySmartFilterID |
Кнопка видна/скрыта по результату смарт-выражения |
| Для заказчика | OwnerOnly |
Переход только для заказчика |
| Для пользователя (исполнителя) | UserOnly |
Переход только для исполнителя |
| Для администратора | ForAdmin |
Переход только для администратора категории |
| Для права исполнять | ForPerfRight |
Переход только для имеющих право «Исполнять» |
| Для права создавать | ForAddRight |
Переход только для имеющих право «Создавать» |
| Для ответственного исполнителя | ForResponsiblePerformer |
Переход только для ответственного |
SQL — проверить ограничения конкретного перехода:
SELECT
StepID, StepDescr, OwnerOnly, UserOnly,
ForAdmin, ForPerfRight, ForAddRight,
ForResponsiblePerformer, ForViewver,
HiddenStep, VisibilitySmartFilterID
FROM StatesRoutesInSubcat
WHERE SubcatID = @SubcatID AND StepID = @StepID;
Решение.
- Убедиться, что у пользователя есть право «Исполнять» в категории (или соответствующее другое право).
- Проверить смарт-фильтр видимости — может скрывать кнопку по условию.
- Исключение: Робот1Ф (системный пользователь) может выполнять любые переходы, независимо от настроек видимости.
3. Подписи не завершены¶
Симптом. Задача «зависла» в статусе «На подписи — {Статус}». Переход не происходит, хотя пользователь нажал кнопку.
Проверка.
Нажатие кнопки перехода не переводит задачу сразу — сначала запрашиваются подписи. Задача переходит в промежуточный статус «На подписи». Переход завершится только после обработки всех обязательных подписей на всех этапах маршрута согласования.
Что проверять:
- Открыть карточку задачи — блок подписей. Есть ли необработанные подписи?
- Акцептант не видит подпись? Проверить — он может быть определён через роль, смарт-выражение или ДП. Если список пуст, подпись не запросится.
- Подпись отклонена? При отклонении задача возвращается в статус, указанный в настройках подписи. Если статус не указан — остаётся в исходном.
Ловушка: если используется отдельный статус «Согласование» (рекомендуемый паттерн), а при отклонении подписи задача остаётся в нём (настройка по умолчанию) — задача «застрянет». Нужно указать статус возврата при отклонении (например, «Подготовка»).
Решение.
- Подпись «висит» — акцептант должен обработать (акцептовать/отклонить/удалить).
- Настроить сроки обработки подписей — при просрочке возможна эскалация.
- При настройке перехода с подписями — обязательно указать статус при отклонении, чтобы задача не застревала.
4. Автопереход при завершении подзадач — нюансы¶
Симптом. Галочка AutoPerformStepOnSubtasksClose включена на переходе, все подзадачи завершены, но переход не произошёл.
Проверка.
SQL — проверить, что галочка включена:
SELECT StepID, StepDescr, AutoPerformStepOnSubtasksClose,
StateID AS FromStateID, StateNextID AS ToStateID
FROM StatesRoutesInSubcat
WHERE SubcatID = @SubcatID AND AutoPerformStepOnSubtasksClose = 1;
Условия срабатывания автоперехода:
| Условие | Комментарий |
|---|---|
| Все подзадачи (дочерние) в завершающем статусе | Проверяются только прямые дочерние задачи |
| Задача находится в статусе «Из статуса» перехода | Если задача уже не в этом статусе — переход не сработает |
| Нет обязательных ДП на переходе (или они заполнены) | Главная причина несрабатывания. Автопереход выполняется системой, заполнить ДП некому |
| Нет обязательных подписей на переходе (или они настроены на автоакцепт) | Подписи блокируют автопереход |
Нет SmartFilter BeforeTaskStep, отменяющего переход |
Смарт «Перед переходом» может вернуть отмену |
Частые причины несрабатывания:
- Обязательные ДП на переходе — самый частый случай. Снять обязательность или заполнить ДП до закрытия последней подзадачи.
- Связанные задачи, а не подзадачи. В настройках «Подзадачи на переходе» если у задачи стоит галочка «Связанная задача», она не считается дочерней. Автопереход
AutoPerformStepOnSubtasksCloseигнорирует связанные задачи — реагирует только на дочерние. - Есть незакрытая подзадача из другой категории — проверить все дочерние, не только из текущей.
- Несколько переходов с
AutoPerformStepOnSubtasksCloseиз одного статуса — неопределённое поведение. Должен быть ровно один такой переход из данного статуса.
SQL — проверить, все ли подзадачи закрыты:
SELECT TaskID, Description, IsClosed, StateID
FROM Tasks
WHERE ParentTaskID = @ParentTaskID AND IsClosed = 0;
Решение.
- Убрать обязательные ДП с перехода, на котором стоит автопереход при завершении подзадач.
- Либо заполнять ДП заранее (смарт-действие при создании задачи, значение по умолчанию).
- Убедиться, что дочерние задачи — именно подзадачи, а не связанные задачи.
5. Смарт-действие в пакете конфликтует с переходом¶
Симптом. Смарт-действия выполняются (видно в логе автоматизации), но переход не происходит. Или происходит переход, но данные не те, что ожидались.
Проверка.
Последовательность выполнения при переходе:
- Смарт-пакеты «Перед переходом» (
BeforeTaskStep) - Проверка обязательных ДП, подписей, прав
- Выполнение перехода (смена статуса)
- Процедура при переходе (SQL)
- Постановка подзадач на переходе
- Смарт-пакеты «После перехода» (
AfterTaskStep,AfterTaskStateChange)
Если смарт «После перехода» сам переводит задачу в другой статус, для этой второй смены смарты «После смены статуса (в т. ч. принудительно)» и «После изменения состояния связанной задачи», обновление денормализации и коннекторы выполняются только после того, как ту же обработку закончит первая смена, — см. Настройки переходов.
Если смарт «Перед переходом» бросает исключение или явно отменяет переход — переход не произойдёт.
Если на переходе есть подписи, порядок другой:
- Запрос подписей
- Смарт-действия «После подписания статической подписи»
- Переход по маршруту
- Смарт-действия «После перехода»
Журнал автоматизации:
SELECT TOP 20
Id, Type, ObjectName, TaskId, Duration, Date,
CAST(AdditionalInfo AS NVARCHAR(500)) AS Info
FROM AutomationScriptsLog
WHERE TaskId = @TaskID
ORDER BY Id DESC;
Где Type = 2 — смарт-действие, Type = 4 — смарт-пакет.
Решение.
- Проверить в журнале автоматизации, выполнился ли пакет и с каким результатом.
- Если смарт «Перед переходом» меняет ДП, от которых зависит условие этого же перехода — может возникнуть конфликт.
- Смарт-действие
SetState(смена статуса) в пакете «Перед переходом» — опасная конструкция: задача может перейти в другой статус до основного перехода. - Если смарт-отмена «Перед переходом» срабатывает при заполненном на экране ДП с клавиатурным вводом — проверьте версию сборки: кнопка перехода сохраняет набранное значение до выполнения смарта и проверки обязательных ДП, поэтому на актуальной сборке смарт читает его заполненным. На более старых сборках и на мобильной карточке значение до сервера не доходит.
6. Связанные задачи (не подзадачи) — автопереход не работает¶
Симптом. Настроены «Подзадачи на переходе» с галочкой «Связанная задача». Ожидается, что автопереход AutoPerformStepOnSubtasksClose сработает при их завершении — но он не срабатывает.
Проверка.
В настройках подзадач на переходе есть поле «Связанная задача»:
«Задача будет создана не как дочерняя, а как связанная. При включении в родительской задаче не работает опция "Автоматически делать переход при завершении всех подзадач" на соответствующих переходах.»
Это штатное поведение. Автопереход при завершении подзадач отслеживает только дочерние задачи (Tasks.ParentTaskID = @TaskID), а не связанные (TaskLinks).
Решение.
- Если нужен автопереход — создавать именно подзадачи, а не связанные задачи.
- Для связанных задач использовать смарт-автоматизацию на событии «После изменения статуса» в категории связанной задачи, которая проверяет статус родительской и выполняет переход.
7. Переход скрыт (кнопка скрыта)¶
Симптом. Переход существует в маршруте, но пользователь не видит отдельной кнопки на карточке задачи. В ленте основного маршрута переход виден, если он сам входит в основной маршрут; скрытый переход вне основного маршрута пользователю не предлагается.
Проверка.
SQL — проверить флаг скрытости и принадлежность перехода основному маршруту:
SELECT StepID, StepDescr, HiddenStep, IsMainRouteStep, VisibilitySmartFilterID
FROM StatesRoutesInSubcat
WHERE SubcatID = @SubcatID;
Два механизма ограничения видимости кнопки:
| Механизм | Поле | Поведение |
|---|---|---|
HiddenStep = 1 |
Кнопка скрыта | Отдельной кнопки на карточке нет. Переход доступен пользователю из ленты основного маршрута — только если сам переход входит в основной маршрут (IsMainRouteStep = 1); иначе он не попадает ни в кнопки карточки, ни в ленту, ни в пакетный диалог, ни в список действий мобильного приложения |
| Смарт-фильтр видимости | VisibilitySmartFilterID |
Кнопка показывается или скрывается по условию выражения. Условие проверяется и при выполнении перехода пользователем: не прошедший по фильтру переход отклоняется |
Выполнение через API. Пользовательский вызов POST /api/tasks/{taskId}/change-step скрытие не обходит: если передан StepId перехода с HiddenStep = 1, не входящего в основной маршрут, сервер отклоняет запрос, а статус задачи не меняется. Программные сценарии идут собственным путём и этим ограничением не затронуты: смарт-действие SetState, автоматический переход при постановке задачи, при завершении всех подзадач и по просрочке, а также системные переходы, которые выбирает сам код — например, акцепт или отклонение встречи из календаря, отклонение по резолюции подписи, переход по данным из 1С.
Решение.
- Если переход должен быть доступен отдельной кнопкой — снять флаг «Кнопка скрыта».
- Если переход должен выполняться пользователем из ленты — включить его в основной маршрут.
- Если кнопка скрыта смарт-фильтром — проверить условие выражения в администрировании.
- Если запрос
change-stepотклонён — собрать номер задачи, категорию, исходный и целевой статусы, версию системы и текст ошибки и передать в поддержку.
8. Параллельные ветки маршрута¶
Симптом. Из одного статуса есть несколько переходов. Пользователь нажал «не ту» кнопку. Или система выполнила не тот автопереход.
Проверка.
SQL — все переходы из данного статуса:
SELECT
StepID, StepDescr, StateID, StateNextID,
AutoPerformStepOnSubtasksClose,
OnOverduePerformStepID,
HiddenStep, OwnerOnly, UserOnly, OrderId
FROM StatesRoutesInSubcat
WHERE SubcatID = @SubcatID AND StateID = @CurrentStateID
ORDER BY OrderId;
Проблемные ситуации:
- Несколько
AutoPerformStepOnSubtasksClose = 1из одного статуса — неопределённый результат. Нужен ровно один. - Альтернативный переход при просрочке (
OnOverduePerformStepID) — jobOverdueStepActionJob(каждые 4 мин) проверяет просроченные шаги и выполняет альтернативный переход. Может конкурировать с ручным переходом. - Шаг при постановке — автопереход сразу после создания задачи. Если у пользователя нет прав на этот переход, задача останется в начальном статусе без уведомления.
Решение.
- Для автоматических переходов — использовать скрытые кнопки (
HiddenStep = 1), чтобы пользователь не нажал вручную. AutoPerformStepOnSubtasksClose— максимум один переход из каждого статуса.- Для альтернативного перехода при просрочке — проверить значение
TermMinutesиOnOverduePerformStepID.
Диагностика¶
Где смотреть¶
Информацию о переходах задачи можно найти в журналах системы:
| Журнал | Таблица | Что покажет |
|---|---|---|
| Ошибки | ExceptionsLog |
Технические ошибки при переходе (SourceID = 5 — бизнес-логика, 12 — API) |
| Ошибки бизнес-логики | ExceptionsLog (SourceID = 5) |
Ошибки смартов, валидации, бизнес-правил при переходе |
| Выполнения автоматизации | AutomationScriptsLog |
Выполнение смарт-пакетов на переходе (Type = 2 действие, 4 пакет) |
| Общий (Системный) | ActionLog |
Изменения настроек категории, статусов, переходов (административные действия) |
| История переходов (API) | POST /api/tasks/{taskId}/stephistory |
Последовательность переходов задачи, кто и когда |
SQL-запросы для диагностики¶
Ошибки при переходе конкретной задачи (за последние 7 дней):
SELECT TOP 20 ID, Date, SourceID,
CAST(Exception AS NVARCHAR(500)) AS ExceptionShort
FROM ExceptionsLog
WHERE Exception LIKE '%TaskID=' + CAST(@TaskID AS VARCHAR) + '%'
AND Date > DATEADD(DAY, -7, GETDATE())
ORDER BY ID DESC;
Смарт-автоматизации по задаче:
SELECT TOP 20
Id, Type, ObjectName, TaskId, UserID,
Duration, Date,
CAST(AdditionalInfo AS NVARCHAR(500)) AS Info
FROM AutomationScriptsLog
WHERE TaskId = @TaskID
ORDER BY Id DESC;
Полная конфигурация переходов категории:
SELECT
sris.StepID,
sris.StepDescr AS ButtonName,
s1.Description AS FromState,
s2.Description AS ToState,
sris.HiddenStep,
sris.AutoPerformStepOnSubtasksClose,
sris.OnOverduePerformStepID,
sris.TermMinutes,
sris.OwnerOnly,
sris.UserOnly,
sris.ForAdmin,
sris.ForPerfRight,
sris.VisibilitySmartFilterID,
sris.ForceComment,
sris.OrderId
FROM StatesRoutesInSubcat sris
JOIN States s1 ON s1.StateID = sris.StateID
JOIN States s2 ON s2.StateID = sris.StateNextID
WHERE sris.SubcatID = @SubcatID
ORDER BY sris.StateID, sris.OrderId;
Обязательные ДП по всем переходам категории:
SELECT
sris.StepID,
sris.StepDescr AS ButtonName,
ep.ExtParamID,
ep.ExtParamName,
epv.ExtParamValue AS CurrentValue
FROM StepExtParamRestrictions sepr
JOIN StatesRoutesInSubcat sris ON sris.StepID = sepr.StepID
JOIN ExtParams ep ON ep.ExtParamID = sepr.ExtParamID
LEFT JOIN ExtParamValues epv ON epv.ExtParamID = sepr.ExtParamID AND epv.TaskID = @TaskID
WHERE sris.SubcatID = @SubcatID
ORDER BY sris.StepID, ep.ExtParamName;
Типичные сценарии из практики¶
Сценарий 1: «Автопереход при завершении подзадач не работает»¶
Запрос. Включена галочка «Автоматически делать переход при завершении всех подзадач». Все подзадачи закрыты, но родительская задача не двигается.
Диагностика.
- Проверить обязательные ДП на переходе (пункт 1).
- Проверить, что дочерние — именно подзадачи, а не связанные (пункт 6).
- Проверить, что нет незакрытых подзадач из других категорий.
- Проверить, нет ли подписей на переходе (пункт 3).
- Посмотреть
ExceptionsLog— возможна ошибка при попытке автоперехода.
Типичное решение. Убрать обязательные ДП с перехода. Если ДП нужны — заполнить их до закрытия последней подзадачи (смарт-действие на родительской задаче или ручное заполнение).
Сценарий 2: «Смарт-действия выполняются, но переход нет»¶
Запрос. На переходе настроен смарт-пакет. Пакет отработал (видно в логе), но задача осталась в прежнем статусе.
Диагностика.
- Посмотреть
AutomationScriptsLog— завершился ли пакет без ошибок. - Проверить, не отменил ли смарт «Перед переходом» сам переход (Action = Cancel).
- Проверить порядок: смарт «Перед переходом» выполняется до проверки обязательных ДП. Если смарт заполняет ДП, а ДП обязательны — проверить, успевает ли значение записаться.
- Посмотреть
ExceptionsLog— исключение в смарте блокирует переход.
Сценарий 3: «Даты вехи самопроизвольно смещаются»¶
Запрос. В проектной задаче даты вех меняются без видимых действий пользователя.
Диагностика.
Побочный эффект автоматических переходов:
- Настройка перехода «Действие с датой начала работы» (
TaskStartTimeAction) — может очищать или заполнять текущим временем. - Настройка «Сбросить срок» (
ResetDueTime) — очищает поле «Срок» при переходе. - Смарт-действия «После перехода» — могут менять даты через
ChangeExtParamValue. - Job
OverdueStepActionJob— при просрочке шага может выполнить альтернативный переход с побочными эффектами.
SQL — проверить настройки действий с датами на переходах:
SELECT StepID, StepDescr, ResetDueTime, TaskStartTimeAction,
AskPermissionToPerformTSTAction
FROM StatesRoutesInSubcat
WHERE SubcatID = @SubcatID
AND (ResetDueTime = 1 OR TaskStartTimeAction > 0);
Сценарий 4: «Задача в завершающем статусе считается незакрытой; тикер и грид расходятся»¶
Запрос. После смены типа статуса (например, «Активный» → «Завершающий/Закрывающий») часть задач в этом статусе продолжает считаться открытыми: IsClosed = 0; счётчик просроченных (тикер) и таблица (грид) показывают разное число.
Диагностика.
Признаки «работа завершена» / «задача закрыта» (States.FinishWork / States.CloseTask) проставляются задаче при входе в статус через переход. Смена этих флагов у уже существующего статуса задним числом задачи не пересчитывает — денормализованные Tasks.IsClosed (и производное «просрочена») у уже стоящих задач остаются прежними, поэтому тикер и грид считают по рассинхронизированным данным.
SQL — задачи, «зависшие» незакрытыми в закрывающем статусе:
SELECT t.TaskID, t.StateID, s.Description, t.IsClosed
FROM Tasks t
JOIN States s ON s.StateID = t.StateID
WHERE t.SubcatID = @SubcatID AND s.CloseTask = 1 AND t.IsClosed = 0;
Решение. Прогнать такие задачи через переход (повторный вход в статус) или пересчитать состояние пакетно. На будущее — задавать тип статуса до наполнения категории задачами.
Связи таблиц маршрута (модель данных)¶
Маршрут категории — переходы между статусами — хранится в StatesRoutesInSubcat (из статуса StateID в StateNextID, для категории SubcatID). Движение задачи по маршруту фиксируется в StepLog, а принудительные смены статуса вопреки маршруту — в TaskStatusForcedChangesLog. Текущий статус и категория задачи — в самой Tasks.
graph LR
SL["StepLog — движение по маршруту"]
SRIS["StatesRoutesInSubcat — маршрут категории"]
T["Tasks — задачи"]
ST["States — статусы"]
FCL["TaskStatusForcedChangesLog — принудительные переходы"]
U["Users — пользователи"]
SC["Subcategories — категории"]
SL -- "TaskID" --> T
SL -- "StepID" --> SRIS
SL -- "UserID" --> U
SRIS -- "SubcatID" --> SC
SRIS -- "StateID (из)" --> ST
SRIS -- "StateNextID (в)" --> ST
T -- "SubcatID" --> SC
T -- "StateID" --> ST
FCL -- "TaskID" --> T
FCL -- "UserID" --> U
FCL -- "OldState / NewState" --> ST
Полная версия с колонками и схемы связей других подсистем БД — в system/db-er-diagrams.md.
См. также: