Почему не заполняется предмет в задаче согласования комплексного процесса 1С:Документооборот и как это исправить?

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

При проектировании комплексных процессов в программе 1С:Документооборот разработчики часто используют встроенные скрипты и блоки обработки в схемах процессов. Типичный сценарий: на одном из шагов выполняется автоматическая обработка, которая заполняет вспомогательный или заполняемый предмет (например, находит контрагента по реквизитам основного документа и прикрепляет его к процессу), а на следующем шаге создается задача согласования, в которой этот предмет должен быть виден исполнителю.

Однако на практике разработчики часто сталкиваются с крайне странным поведением системы: в первой задаче согласования (которая идет сразу за блоком-обработкой) заполненный предмет отображается как пустой. При этом, если задачу согласовать и процесс перейдет на следующий этап (например, к задаче "Согласовать 2"), там этот предмет отображается корректно. Более того, в самой карточке процесса предмет также выглядит заполненным.

В этой статье мы подробно разберем внутренние механизмы работы бизнес-процессов 1С, выясним причину возникновения этой проблемы и рассмотрим правильный шаблон кода для гарантированного заполнения предметов в задачах.

Анализ причин проблемы: почему возникает эффект "пустого предмета"?

Для того чтобы понять, почему первая задача создается с пустым предметом, нам необходимо заглянуть "под капот" движка бизнес-процессов 1С:Документооборота и проанализировать жизненный цикл объектов в оперативной памяти и базе данных.

Когда бизнес-процесс доходит до блока-обработки на схеме, система выполняет код этого блока в контексте уже инициализированного в памяти сервера приложения объекта бизнес-процесса. Этот объект доступен разработчику через предопределенную переменную Процесс, которая имеет тип БизнесПроцессОбъект.КомплексныйПроцесс.

Рассмотрим типичную ошибку в коде обработки, которую часто допускают программисты:


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

// Прямая запись в базу данных по ссылке процесса:
Мультипредметность.ЗаписатьПредметБизнесПроцесса(Процесс.Ссылка, ИмяПредмета, КонтрагентСсылка);

// Попытка принудительно обновить базу данных:
ПроцОб = Процесс.Ссылка.ПолучитьОбъект();
ПроцОб.Записать();

Давайте по шагам разберем, что происходит при выполнении этого некорректного кода:

  1. Разсинхронизация памяти и базы данных. Метод Мультипредметность.ЗаписатьПредметБизнесПроцесса(...) принимает в качестве параметра ссылку Процесс.Ссылка и записывает изменения напрямую в таблицы базы данных. Конструкция Процесс.Ссылка.ПолучитьОбъект() считывает новую копию объекта из базы данных, модифицирует её и записывает обратно в СУБД. При этом текущая переменная Процесс, которая находится в оперативной памяти выполняющегося потока, остается неизменной! В ее табличной части Предметы строка с контрагентом по-прежнему пуста.
  2. Создание задачи из "устаревшей" памяти. Сразу после выполнения кода блока-обработки, в рамках той же транзакции, система переходит к генерации следующего шага схемы — созданию задачи "Согласовать 1". Для формирования реквизитов и предметов задачи система берет объект Процесс напрямую из оперативной памяти (где он не обновлен) и копирует коллекцию предметов из него. В результате создается задача с незаполненным предметом.
  3. Перезапись данных в СУБД. После завершения шага движок бизнес-процессов выполняет финальную запись основного объекта Процесс из оперативной памяти в базу данных. Это действие может даже затереть те изменения, которые разработчик пытался внести через ПолучитьОбъект().Записать().
  4. Почему вторая задача создается нормально? Когда пользователь выполняет задачу "Согласовать 1", транзакция закрывается. При переходе к следующему шагу схемы ("Согласовать 2") система инициализирует процесс заново, считывая его актуальное состояние из базы данных. Теперь объект в памяти содержит заполненный предмет, и вторая задача создается корректно.

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

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

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

  1. Вносить изменения непосредственно в коллекцию (табличную часть Предметы) переменной Процесс, которая находится в памяти.
  2. Использовать специализированный метод записи бизнес-процесса из общего модуля 1С:Документооборота. Обычный метод Процесс.Записать() не обновит связанные регистры сведений и предметы задач. Для этого существует экспортный метод РаботаСБизнесПроцессами.ЗаписатьProcess() со специальным строковым флагом обновления.

Рассмотрим подробнее правильный шаблон кода для размещения в блоке-обработке схемы комплексного процесса:


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

Разбор ключевых моментов решения

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

Что еще проверить, если предмет не отображается в задаче?

Если вы применили правильный программный код записи процесса, но предмет все равно отсутствует в карточке задачи исполнителя, рекомендуем проверить следующие настройки в режиме "1С:Предприятие":

  1. Настройка видимости предметов на этапах. Откройте ваш шаблон комплексного процесса. Перейдите на вкладку "Настройка видимости предметов". Найдите этап "Согласовать 1" и убедитесь, что для предмета "Контрагент" установлена галочка видимости. Если видимость отключена, предмет будет заполнен в базе данных и в самом процессе, но исполнитель задачи его физически не увидит на своей форме.
  2. Роли предметов. Убедитесь, что для заполняемого предмета в шаблоне процесса верно указана роль. Если в коде вы устанавливаете значение Перечисления.РолиПредметов.Заполняемый, а в шаблоне процесса этот предмет настроен как "Основной", может возникнуть конфликт типов, из-за которого перезапись коллекции будет проигнорирована.

Применяя данный подход к работе с предметами бизнес-процессов, вы обеспечите стабильное и предсказуемое поведение комплексных процессов в любых редакциях программы 1С:Документооборот 2.1 и 3.0.

← На главную