Как эффективно управлять процессами и выводить список участников документа в 1С:Документооборот 8 КОРП 2.1?

Программист 1С v8.3 (Управляемые формы) 1С:Документооборот Управленческий учет IT и автоматизация бизнеса
← К списку

При работе с системой 1С:Документооборот 8 КОРП 2.1 часто возникает необходимость организовать сложную цепочку обработки документов, назначить задачи конкретным исполнителям и, конечно, вывести информацию о всех причастных лицах в печатные формы или шаблоны. Мы с вами разберем, как правильно подходить к этим задачам, избегая распространенных ошибок и оптимизируя производительность.

1. Организация процессов и назначение задач: избегаем хаоса

Прежде всего, давайте проанализируем ситуацию с отправкой документов и задач. Нередко возникает желание отправить документ или задачу всем, кто так или иначе связан с ним, например, всем членам рабочей группы. Однако такой подход является ошибочным и может привести к серьезным проблемам с ответственностью и эффективностью.

  1. Не отправляйте задачи всем подряд. Представьте ситуацию, когда финансовый директор должен согласовать крупный платеж, а дворник — открыть ворота для прибытия фуры. Если задача будет отправлена всем, кто состоит в рабочей группе документа, то дворник может ошибочно согласовать платеж, или, наоборот, финдиректор пропустит свою задачу среди множества нерелевантных. Каждый сотрудник отвечает за свой участок работы и не должен видеть чужих задач, а тем более иметь возможность их исполнять.
  2. Используйте комплексные процессы со схемой. Для организации сложной обработки документов, состоящей из цепочки различных действий, мы рекомендуем использовать Комплексные процессы. Они позволяют четко настроить последовательность действий, условия их выполнения и список исполнителей. Шаблоны комплексных процессов являются мощным инструментом для стандартизации документооборота.
  3. Назначайте задачи конкретным исполнителям или группам. Задачи должны быть адресованы строго определенным пользователям или ролям (группам исполнителей), а не всей рабочей группе документа. Это обеспечивает прозрачное распределение ответственности и предотвращает выполнение задач неподходящими сотрудниками.
  4. Типовые действия в процессах. В 1С:Документообороте 2.1 в комплексных процессах доступны различные типовые действия, такие как Исполнение, Ознакомление, Рассмотрение, Регистрация, Согласование, Утверждение/Подписание. Мы можем использовать их для построения логики процесса.

2. Рабочие группы и управление доступом к документам

Рабочие группы в 1С:Документообороте играют ключевую роль в управлении правами доступа к внутренним документам. Давайте рассмотрим их назначение и особенности.

  1. Назначение рабочих групп. Основная функция рабочей группы — ограничение доступа к документу. Если рабочая группа не заполнена, документ по умолчанию могут просматривать все пользователи. Если же рабочая группа определена, доступ к документу имеют только ее участники.
  2. Права доступа по умолчанию. По умолчанию, участник рабочей группы имеет доступ только на чтение документа. Если требуется предоставить право на изменение, необходимо установить соответствующий флажок на закладке "Рабочая группа" в карточке документа.
  3. Автоматическое и ручное заполнение. Для определенных видов документов можно настроить автоматическое ведение состава рабочей группы. В этом случае система сама добавит авторов и исполнителей процессов по документу, а также пользователей, указанных в самом документе. При ручном заполнении, пользователь, создающий документ, должен обязательно включить себя в список, иначе система не позволит записать документ.
  4. Составной тип поля "Участник". Очень важный момент, который необходимо учитывать при работе с рабочими группами программно: поле Участник в регистре сведений РегистрСведений.РабочиеГруппы является составным типом. Это означает, что оно может содержать ссылки не только на СправочникСсылка.Пользователи, но и на СправочникСсылка.СтруктураПредприятия, СправочникСсылка.РабочиеГруппы, СправочникСсылка.ПолныеРоли. Это знание критически важно при построении запросов, чтобы корректно получить данные о всех типах участников.

3. Вывод списка участников в печатные формы и шаблоны: оптимизация запросов

Предположим, перед нами стоит задача вывести список всех исполнителей (участников рабочей группы) внутреннего документа, например, докладной записки, в ее печатную форму. Рассмотрим пример кода и выясним, как его можно оптимизировать.

Исходный подход (требует оптимизации)

В одном из решений для вывода списка участников в шаблон печатной формы был предложен следующий код:


РезультатОбработки = "";
Запрос = Новый Запрос;
Запрос.Текст =
        "ВЫБРАТЬ
        |    РабочиеГруппы.Участник КАК Участник,
        |    ВнутренниеДокументы.ВидДокумента КАК ВидДокумента,
        |    ВнутренниеДокументы.Ответственный КАК Ответственный,
        |    ВнутренниеДокументы.Подразделение КАК Подразделение,
        |    ВнутренниеДокументы.Содержание КАК Содержание,
        |    ВнутренниеДокументы.Создал КАК Создал,
        |    ВнутренниеДокументы.Должность КАК Должность,
        |    ВнутренниеДокументы.Ссылка КАК Ссылка
        |ИЗ
        |    Справочник.ВнутренниеДокументы КАК ВнутренниеДокументы
        |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.РабочиеГруппы КАК РабочиеГруппы
        |        ПО ВнутренниеДокументы.Ссылка = РабочиеГруппы.Объект
        |ГДЕ
        |    ВнутренниеДокументы.Ссылка = &Ссылка
        |    И ВнутренниеДокументы.Ссылка = РабочиеГруппы.Объект";

Запрос.УстановитьПараметр("Ссылка", Файл.ВладелецФайла);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    Участник = ВыборкаДетальныеЗаписи.Участник.ПредставлениеВПереписке;
    ДолжностьСтрока = Строка(РаботаСПользователями.ПолучитьДолжность(ВыборкаДетальныеЗаписи.Участник));
    ПодразделениеСтрока = Строка(РаботаСПользователями.ПолучитьПодразделение(ВыборкаДетальныеЗаписи.Участник));
    РезультатОбработки = РезультатОбработки + " " + ДолжностьСтрока + " " + ПодразделениеСтрока + " " + Участник;
КонецЦикла;

Анализ проблем и пути оптимизации

Представленный выше код, хоть и работоспособен, имеет ряд недостатков, которые могут существенно сказаться на производительности, особенно при большом количестве участников или документов:

  1. Запросы в цикле. Мы видим, что внутри цикла для каждой записи выполняется вызов функций РаботаСПользователями.ПолучитьДолжность() и РаботаСПользователями.ПолучитьПодразделение(). Эти функции, скорее всего, выполняют запросы к базе данных для получения информации. Многократное выполнение запросов в цикле — это очень неэффективно и является одной из основных причин замедления работы системы.
  2. Неполный учет составного типа. Поле Участник, как мы уже говорили, является составным типом. В текущем коде мы обращаемся к ВыборкаДетальныеЗаписи.Участник.ПредставлениеВПереписке, что будет работать, если Участник — это СправочникСсылка.Пользователи. Однако, если там будет, например, СправочникСсылка.СтруктураПредприятия или СправочникСсылка.РабочиеГруппы, то такое прямое обращение может быть некорректным или требовать дополнительных проверок.

Давайте разберем, как мы можем оптимизировать этот запрос, чтобы получить все необходимые данные за одно обращение к базе данных.

Оптимизированное решение

Для оптимизации мы должны перенести логику получения должности, подразделения и представления участника непосредственно в текст запроса, используя соединения с соответствующими справочниками и учитывая составной тип поля Участник. Для этого нам потребуется соединиться с различными таблицами в зависимости от типа участника.

Рассмотрим пример запроса, который объединяет необходимые данные:


РезультатОбработки = "";
Запрос = Новый Запрос;
Запрос.Текст =
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |    РабочиеГруппы.Участник КАК Участник,
        |    ВЫБОР
        |        КОГДА ТИПЗНАЧЕНИЯ(РабочиеГруппы.Участник) = ТИП(Справочник.Пользователи)
        |            ТОГДА Пользователи.ПредставлениеВПереписке
        |        КОГДА ТИПЗНАЧЕНИЯ(РабочиеГруппы.Участник) = ТИП(Справочник.СтруктураПредприятия)
        |            ТОГДА СтруктураПредприятия.Наименование
        |        КОГДА ТИПЗНАЧЕНИЯ(РабочиеГруппы.Участник) = ТИП(Справочник.РабочиеГруппы)
        |            ТОГДА РабочиеГруппыСпр.Наименование
        |        КОГДА ТИПЗНАЧЕНИЯ(РабочиеГруппы.Участник) = ТИП(Справочник.ПолныеРоли)
        |            ТОГДА ПолныеРоли.Наименование
        |        ИНАЧЕ ""Неизвестный тип участника""
        |    КОНЕЦ КАК ПредставлениеУчастника,
        |    ВЫБОР
        |        КОГДА ТИПЗНАЧЕНИЯ(РабочиеГруппы.Участник) = ТИП(Справочник.Пользователи)
        |            ТОГДА Сотрудники.Должность.Наименование
        |        ИНАЧЕ NULL
        |    КОНЕЦ КАК Должность,
        |    ВЫБОР
        |        КОГДА ТИПЗНАЧЕНИЯ(РабочиеГруппы.Участник) = ТИП(Справочник.Пользователи)
        |            ТОГДА Сотрудники.Подразделение.Наименование
        |        ИНАЧЕ NULL
        |    КОНЕЦ КАК Подразделение
        |ИЗ
        |    РегистрСведений.РабочиеГруппы КАК РабочиеГруппы
        |        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи
        |            ПО РабочиеГруппы.Участник = Пользователи.Ссылка
        |        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Сотрудники КАК Сотрудники
        |            ПО Пользователи.ФизическоеЛицо = Сотрудники.ФизическоеЛицо
        |        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.СтруктураПредприятия КАК СтруктураПредприятия
        |            ПО РабочиеГруппы.Участник = СтруктураПредприятия.Ссылка
        |        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.РабочиеГруппы КАК РабочиеГруппыСпр
        |            ПО РабочиеГруппы.Участник = РабочиеГруппыСпр.Ссылка
        |        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПолныеРоли КАК ПолныеРоли
        |            ПО РабочиеГруппы.Участник = ПолныеРоли.Ссылка
        |ГДЕ
        |    РабочиеГруппы.Объект = &Ссылка
        |
        |УПОРЯДОЧИТЬ ПО
        |    ПредставлениеУчастника";

Запрос.УстановитьПараметр("Ссылка", Файл.ВладелецФайла); // Предполагаем, что Файл.ВладелецФайла - это ссылка на документ
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    СтрокаУчастника = "";
    Если Не ЗначениеЗаполнено(ВыборкаДетальныеЗаписи.Должность) И Не ЗначениеЗаполнено(ВыборкаДетальныеЗаписи.Подразделение) Тогда
        // Если нет должности и подразделения (например, если участник - не пользователь, а группа)
        СтрокаУчастника = ВыборкаДетальныеЗаписи.ПредставлениеУчастника;
    Иначе
        // Для пользователей выводим должность, подразделение и ФИО
        Если ЗначениеЗаполнено(ВыборкаДетальныеЗаписи.Должность) Тогда
            СтрокаУчастника = СтрокаУчастника + ВыборкаДетальныеЗаписи.Должность + " ";
        КонецЕсли;
        Если ЗначениеЗаполнено(ВыборкаДетальныеЗаписи.Подразделение) Тогда
            СтрокаУчастника = СтрокаУчастника + "(" + ВыборкаДетальныеЗаписи.Подразделение + ") ";
        КонецЕсли;
        СтрокаУчастника = СтрокаУчастника + ВыборкаДетальныеЗаписи.ПредставлениеУчастника;
    КонецЕсли;

    РезультатОбработки = РезультатОбработки + СтрокаУчастника + Символы.ПС;
КонецЦикла;

Что мы сделали в этом оптимизированном запросе:

  1. Единый запрос. Все необходимые данные (представление участника, должность, подразделение) мы получаем одним запросом, избегая цикличных обращений к базе данных.
  2. Учет составного типа. Мы используем конструкцию ВЫБОР КОГДА ТИПЗНАЧЕНИЯ(...) для корректного получения представления участника в зависимости от его типа (пользователь, элемент структуры предприятия, рабочая группа и т.д.).
  3. Условные соединения. Выполняем ЛЕВОЕ СОЕДИНЕНИЕ с различными справочниками (Пользователи, Сотрудники, СтруктураПредприятия, РабочиеГруппы, ПолныеРоли), чтобы получить всю возможную информацию.
  4. Форматирование. В цикле обхода результата запроса мы формируем строку для каждого участника, добавляя Символы.ПС (перевод строки) после каждого сотрудника, как было предложено в форуме, для лучшей читаемости в печатной форме.

Этот подход значительно повышает производительность и корректность получения данных из рабочей группы документа.

4. Расширения конфигурации: когда и как использовать

В контексте доработок и оптимизации функционала 1С:Документооборот мы можем рассмотреть использование расширений конфигурации.

  1. Цель расширений. Расширения позволяют добавлять или изменять функциональность типовой конфигурации без снятия ее с поддержки. Это предпочтительный способ модификации системы, так как он упрощает процесс обновления.
  2. Осторожность с правами доступа. Мы должны быть крайне осторожны при внесении изменений в типовую логику прав доступа или критические механизмы системы с помощью расширений. Некорректные доработки могут привести к непредсказуемым последствиям и сложностям при дальнейших обновлениях.
  3. Примеры использования. Расширения могут быть полезны для оптимизации производительности (например, переработка типовых механизмов формирования динамических запросов), добавления новых отчетов, обработок или изменения форм без затрагивания основной конфигурации.

Мы рассмотрели ключевые аспекты правильной организации документооборота, управления задачами и оптимизации вывода данных в 1С:Документооборот 8 КОРП 2.1. Следуя этим рекомендациям, вы сможете создать более эффективную и производительную систему.

← К списку