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