Как программно выполнять задачи бизнес-процесса в 1С без участия пользователя

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

Приветствуем вас! При проектировании бизнес-процессов (БП) в среде «1С:Предприятие» разработчики часто сталкиваются с важной задачей оптимизации юзабилити. Классическая схема работы БП предполагает, что пользователь открывает задачу, выполняет целевое действие (например, проводит документ), а затем вручную возвращается к форме задачи и нажимает кнопку «Выполнено». Однако заставлять пользователей делать двойную работу — неэффективно и неудобно.

В этой публикации мы подробно разберем, как реализовать автоматическое продвижение бизнес-процесса по карте маршрута на основе действий пользователя с документами-основаниями. Мы изучим штатные методы платформы, научимся избегать опасных транзакционных блокировок базы данных, рассмотрим интеграцию с механизмами БСП (Библиотеки стандартных подсистем) и обсудим альтернативные архитектурные решения.

Связывание задачи с документом-основанием

Чтобы программа могла автоматически закрыть задачу при записи или проведении документа, между этими объектами должна быть настроена четкая связь в метаданных. Платформа 1С не связывает задачи и документы автоматически — эту логику необходимо заложить на этапе проектирования.

Рассмотрим два основных варианта реализации связи:

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

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

Поиск активной задачи для автовыполнения

Чтобы выполнить задачу программно, ее необходимо сначала найти в базе данных по ссылке на документ-основание. Напишем оптимальный поисковый запрос, который мы сможем вызывать на стороне сервера.

Разберем пример функции поиска невыполненной задачи:


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

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

Правильный метод платформы для завершения задачи

Разберем распространенную архитектурную ошибку, которую совершают многие начинающие разработчики. Часто при попытке закрыть задачу программно разработчики пытаются напрямую изменить реквизиты объекта:


// ВНИМАНИЕ: ЭТО ОШИБКА! Бизнес-процесс не сдвинется с места!
ЗадачаОбъект = ЗадачаСсылка.ПолучитьОбъект();
ЗадачаОбъект.Выполнена = Истина;
ЗадачаОбъект.Записать();

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

Для корректного программного завершения задачи мы обязаны использовать специализированный системный метод — ЗадачаОбъект.ВыполнитьЗадачу(). Именно этот метод изменяет статус задачи и одновременно инициирует движение бизнес-процесса вперед, запуская обработчики ПередВыполнением и ПриВыполнении на уровне карты маршрута.

Посмотрим на пример правильной реализации:


Процедура ВыполнитьЗадачуПрограммно(ЗадачаСсылка) Экспорт
    
    Если Не ЗначениеЗаполнено(ЗадачаСсылка) Тогда
        Возврат;
    КонецЕсли;
    
    Попытка
        ЗадачаОбъект = ЗадачаСсылка.ПолучитьОбъект();
        // Используем штатный метод продвижения бизнес-процесса
        ЗадачаОбъект.ВыполнитьЗадачу();
    Исключение
        // Обязательно логируем ошибку в Журнал регистрации
        ЗаписьЖурналаРегистрации("АвтовыполнениеЗадач",
            УровеньЖурналаРегистрации.Ошибка,
            ЗадачаСсылка.Метаданные(),
            ЗадачаСсылка,
            ОписаниеОшибки());
            
        ВызватьИсключение "Не удалось автоматически выполнить задачу: " + ОписаниеОшибки();
    КонецПопытки;
    
КонецПроцедуры

Транзакционные блокировки и архитектурные риски

Выполнение задачи в транзакции записи или проведения документа (например, внутри обработчиков ПередЗаписью, ПриЗаписи или ОбработкаПроведения модуля документа) — это **серьезная архитектурная ошибка**, которая ведет к блокировкам базы данных.

Проанализируем причину проблемы. Проведение документа открывает транзакцию базы данных. Вызов метода ЗадачаОбъект.ВыполнитьЗадачу() внутри этой транзакции заставляет бизнес-процесс двигаться дальше. Движение БП может инициировать создание новых задач, запись в другие регистры или повторное изменение этого же документа. В многопользовательской среде это неизбежно вызовет взаимные блокировки СУБД (Deadlocks) и приведет к падению производительности системы.

Рассмотрим два надежных решения этой проблемы:

Решение 1. Выполнение задачи на клиенте в обработчике «ПослеЗаписи»

Если документ проводится пользователем интерактивно, мы дожидаемся успешного завершения транзакции проведения документа и только после этого запускаем выполнение задачи.


&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    // Транзакция проведения завершена, базы данных разблокированы.
    // Теперь можно безопасно продвигать бизнес-процесс.
    АвтовыполнениеЗадачиНаСервере(Объект.Ссылка);
КонецПроцедуры

&НаСервереБезКонтекста
Процедура АвтовыполнениеЗадачиНаСервере(ДокументСсылка)
    ЗадачаСсылка = НайтиАктивнуюЗадачуПоДокументу(ДокументСсылка);
    Если ЗначениеЗаполнено(ЗадачаСсылка) Тогда
        ВыполнитьЗадачуПрограммно(ЗадачаСсылка);
    КонецЕсли;
КонецПроцедуры

Решение 2. Асинхронное фоновое выполнение задач

Если документы создаются программно (например, через загрузки или HTTP-сервисы), клиентский обработчик формы использовать невозможно. В этом случае применяется асинхронный подход:

Использование программного интерфейса БСП

Если в вашей конфигурации внедрена БСП (подсистема «Бизнес-процессы и задачи»), выполнять задачи прямым обращением к объекту крайне не рекомендуется. Прямой вызов может обойти внутренние механизмы БСП (такие как проверка прав доступа, очистка кэшей, регистрация истории выполнения и т.д.).

Для безопасного выполнения задач в БСП разработан специальный программный интерфейс:


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

Альтернативный вариант проектирования: Точки условия

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

Вместо того чтобы создавать стандартную задачу, а потом программно её выполнять, на карте маршрута бизнес-процесса в этой точке лучше использовать Точку условия или Автоматическую точку действия. Бизнес-процесс при переходе на эту точку сам проверит статус связанного документа (например, проведен ли он). Если условие выполнено, процесс автоматически пойдет дальше по карте маршрута, вообще не создавая лишних задач в системе. Это более надежный подход, который исключает написание сложных обработчиков автовыполнения.

← На главную