При работе в крупных информационных системах, таких как 1С:Документооборот 2.1, мы часто сталкиваемся с иерархическими структурами бизнес-процессов. Комплексные процессы порождают подпроцессы (согласование, исполнение, ознакомление), те, в свою очередь, могут создавать новые задачи и процессы. В результате образуется дерево с большой вложенностью. Рассмотрим ситуацию, когда нам необходимо из "листа" этого дерева (самого последнего вложенного процесса) быстро и эффективно добраться до его "корня" — самого первого инициирующего бизнес-процесса.
На уровне платформы 1С существует стандартный механизм связи: у бизнес-процесса есть реквизит ВедущаяЗадача. Казалось бы, достаточно просто обращаться к родителю через этот реквизит. Однако на практике в типовых конфигурациях, особенно в 1С:ДО, этот реквизит может быть не заполнен. Это происходит потому, что связь между процессами часто реализуется на прикладном уровне через специализированные регистры или дополнительные реквизиты, чтобы обеспечить гибкость настройки комплексных процессов. Проанализируем, как программно обойти эту иерархию снизу вверх.
В конфигурации 1С:Документооборот 2.1 основным источником информации о связях между процессами является регистр сведений ДочерниеБизнесПроцессы. Этот регистр хранит записи о том, какой родительский процесс и через какую связующую задачу породил дочерний процесс. Разберем структуру этого регистра:
Чтобы найти корень всей цепочки, нам необходимо выполнять поиск родителя до тех пор, пока мы не встретим процесс, у которого самого нет родителя в данном регистре. Рассмотрим пример рекурсивной функции, которая решает эту задачу:
Функция ВернутьГоловнойБизнесПроцесс(ДочернийБизнесПроцесс) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДочерниеБизнесПроцессы.РодительскийПроцесс КАК РодительскийПроцесс
|ИЗ
| РегистрСведений.ДочерниеБизнесПроцессы КАК ДочерниеБизнесПроцессы
|ГДЕ
| ДочерниеБизнесПроцессы.ДочернийПроцесс = &ДочернийПроцесс";
Запрос.УстановитьПараметр("ДочернийПроцесс", ДочернийБизнесПроцесс);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Если Выборка.Следующий() Тогда
// Если родитель найден, вызываем функцию повторно для найденного родителя
Возврат ВернутьГоловнойБизнесПроцесс(Выборка.РодительскийПроцесс);
Иначе
// Если записи в регистре нет, значит текущий процесс и есть корень
Возврат ДочернийБизнесПроцесс;
КонецЕсли;
КонецФункции
Проанализируем работу данного кода. Функция принимает ссылку на текущий бизнес-процесс и ищет его родителя в регистре. Если родитель найден, функция вызывает саму себя, передавая в качестве параметра уже найденного родителя. Этот процесс продолжается до тех пор, пока запрос не вернет пустой результат. Таким образом, мы "поднимаемся" по веткам дерева к самому основанию.
Важно помнить, что рекурсивные запросы могут создавать нагрузку на сервер БД при экстремально большой вложенности. Если в вашей системе глубина иерархии составляет десятки уровней, стоит рассмотреть вариант оптимизации. Вместо серии одиночных запросов мы можем однократно получить всю цепочку связей для конкретного предмета (документа) или использовать временные таблицы. Однако для большинства задач в 1С:ДО представленный выше метод является стандартным и вполне надежным.
Иногда требуется не просто найти корень, но и получить информацию о всей цепочке прохождения. Выясним, какую роль играет СвязующаяЗадача. Каждый дочерний процесс всегда привязан к конкретной задаче родителя. Мы можем использовать это для построения иерархических отчетов. Посмотрим на пример запроса, который позволяет увидеть связь уровней:
ВЫБРАТЬ
ДочерниеБизнесПроцессы.РодительскийПроцесс КАК РодительскийПроцесс,
ДочерниеБизнесПроцессы.СвязующаяЗадача КАК СвязующаяЗадача,
ДочерниеБизнесПроцессы.ДочернийПроцесс КАК ДочернийПроцесс,
ДочерниеБизнесПроцессы.СвязующаяЗадача.БизнесПроцесс.ВедущаяЗадача.БизнесПроцесс КАК ГоловнойБП_Платформенный
ИЗ
РегистрСведений.ДочерниеБизнесПроцессы КАК ДочерниеБизнесПроцессы
ГДЕ
ДочерниеБизнесПроцессы.ДочернийПроцесс = &ДочернийПроцесс
В этом запросе мы пытаемся обратиться к иерархии через точку входа СвязующаяЗадача.БизнесПроцесс. Это полезно, если вы хотите программно понять, на каком именно этапе (этап согласования, этап исполнения) родительского процесса был запущен текущий подпроцесс.
Рассмотрим еще одну ситуацию: если иерархия в регистре по какой-то причине нарушена или данные были перенесены некорректно. В 1С:Документооборот почти все процессы в рамках одной цепочки привязаны к одному и тому же Предмету (например, входящему документу). Выясним, как это использовать:
БизнесПроцесс.КомплексныйПроцесс (или другим типам), фильтруя по этому предмету.Самый ранний по времени создания процесс, имеющий статус "Комплексный", с высокой долей вероятности будет являться корневым для всей истории обработки данного документа. Однако этот метод менее точен, так как по одному документу могут быть запущены два параллельных и не связанных друг с другом процесса.
При реализации поиска головного процесса рекомендуем учитывать следующие моменты:
ДочерниеБизнесПроцессы актуален прежде всего для ветки 2.1.Таким образом, мы разобрали основной и наиболее правильный способ программного поиска корня бизнес-процесса. Использование регистра ДочерниеБизнесПроцессы совместно с рекурсивным обходом позволяет гарантированно найти "исток" любой задачи, независимо от сложности и разветвленности комплексного процесса.