При разработке на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда попытка программно завершить или остановить бизнес-процесс (БП) через изменение реквизитов объекта не приносит желаемого результата. Код выполняется без ошибок, транзакция фиксируется, но в интерфейсе бизнес-процесс по-прежнему значится как активный, а его задачи остаются открытыми. Рассмотрим подробно, почему это происходит и как правильно реализовать программную остановку БП.
Рассмотрим стандартный, но зачастую ошибочный подход. Программист пытается напрямую модифицировать объект бизнес-процесса, устанавливая системные и дополнительные реквизиты:
БизнесПроцессОбъект = СсылкаНаБП.ПолучитьОбъект();
БизнесПроцессОбъект.ДатаЗавершения = ТекущаяДата();
БизнесПроцессОбъект.Завершен = Истина;
БизнесПроцессОбъект.Состояние = Перечисления.СостоянияБизнесПроцессов.Остановлен;
БизнесПроцессОбъект.Записать();
Выясним причину, по которой этот код может не работать. В современных конфигурациях (таких как ERP, КА, УТ 11 или Документооборот), построенных на базе Библиотеки стандартных подсистем (БСП), логика управления состояниями гораздо сложнее, чем простая проверка булева флага Завершен. Бизнес-процесс — это не просто запись в таблице БД, это живой механизм, тесно связанный с задачами исполнителей и регистрами сведений.
Проанализируем основные причины «игнорирования» записи:
ПередЗаписью или ПриЗаписи может стоять проверка, которая сбрасывает программно установленные флаги, если не соблюдены определенные условия (например, не заполнены обязательные результаты выполнения).ДополнительныеСвойства. Если вы просто записываете объект, логика БСП не получает «сигнала» о том, что это именно остановка, и может откатить изменения.Разберем наиболее правильный метод, который рекомендуется для конфигураций, использующих подсистему «Бизнес-процессы и задачи». Вместо прямой модификации объекта следует использовать программный интерфейс (API) библиотеки. Посмотрим на пример использования серверного общего модуля:
// Используем метод БСП для установки состояния
ПараметрыОстановки = Новый Структура;
ПараметрыОстановки.Вставить("Состояние", Перечисления.СостоянияБизнесПроцессов.Остановлен;
БизнесПроцессыИЗадачиВызовСервера.УстановитьСостояниеБизнесПроцесса(СсылкаНаБП, ПараметрыОстановки);
Этот метод хорош тем, что он не только меняет реквизиты самого процесса, но и корректно обрабатывает связанные данные: делает записи в регистры состояний и корректно взаимодействует с задачами. Проанализируем ситуацию, если этот метод недоступен. В таком случае стоит вызвать функцию, которую использует сама типовая форма при нажатии кнопки «Остановить».
Если мы работаем с «чистой» платформой или кастомной логикой, нам необходимо вручную позаботиться о связанных задачах. Рассмотрим подробнее, как это реализовать. Основная задача — найти все невыполненные задачи данного бизнес-процесса и пометить их как выполненные или отмененные.
// 1. Получаем объект БП
БПОбъект = Выборка.Ссылка.ПолучитьОбъект();
// 2. Устанавливаем признаки завершения
БПОбъект.Завершен = Истина;
БПОбъект.ДатаЗавершения = ТекущаяДата();
БПОбъект.Состояние = Перечисления.СостоянияБизнесПроцессов.Остановлен;
// 3. Обрабатываем задачи (важный шаг!)
ЗапросЗадачи = Новый Запрос;
ЗапросЗадачи.Текст =
"ВЫБРАТЬ
| ЗадачаИсполнителя.Ссылка КАК Ссылка
|ИЗ
| Задача.ЗадачаИсполнителя КАК ЗадачаИсполнителя
|ГДЕ
| ЗадачаИсполнителя.БизнесПроцесс = &БизнесПроцесс
| И НЕ ЗадачаИсполнителя.Выполнена
| И НЕ ЗадачаИсполнителя.ПометкаУдаления";
ЗапросЗадачи.УстановитьПараметр("БизнесПроцесс", БПОбъект.Ссылка);
ВыборкаЗадач = ЗапросЗадачи.Выполнить().Выбрать();
Пока ВыборкаЗадач.Следующий() Цикл
ЗадачаОбъект = ВыборкаЗадач.Ссылка.ПолучитьОбъект();
// Можно пометить на удаление или программно завершить
ЗадачаОбъект.Выполнена = Истина;
ЗадачаОбъект.РезультатВыполнения = "Остановлено программно";
ЗадачаОбъект.Записать();
КонецЦикла;
// 4. Финальная запись процесса
БПОбъект.Записать();
Выясним, почему это работает: когда мы устанавливаем ЗадачаОбъект.Выполнена = Истина, платформа закрывает текущую точку маршрута. Если при этом сам объект бизнес-процесса помечается как Завершен, система перестает генерировать новые задачи по карте маршрута.
Иногда логика в модуле объекта настолько жестко прописана, что не дает программно менять состояние. В таких исключительных случаях (и если вы уверены в своих действиях) можно использовать свойство ОбменДанными.Загрузка. Рассмотрим, как это выглядит:
БПОбъект = Ссылка.ПолучитьОбъект();
БПОбъект.ОбменДанными.Загрузка = Истина; // Отключаем проверки в модуле объекта
БПОбъект.Завершен = Истина;
БПОбъект.Состояние = Перечисления.СостоянияБизнесПроцессов.Остановлен;
БПОбъект.Записать();
Важно: этот метод следует использовать с осторожностью, так как он обходит все подписки на события и встроенные проверки целостности данных. Применив этот подход, вы можете оставить в системе «битые» данные (например, незавершенные задачи, которые будут висеть в списках у пользователей, хотя сам процесс закрыт).
Проанализируем еще один неочевидный момент. Если ваш код выполняется внутри большой транзакции, в которой позже происходит ошибка, то запись бизнес-процесса будет откачена. Проверьте, нет ли в вашем цикле блоков Попытка...Исключение, которые могут скрывать ошибки при выполнении метода Записать().
Рекомендуется всегда проверять результат записи:
Попытка
БПОбъект.Записать();
Исключение
ЗаписьЖурналаРегистрации("ПрограммнаяОстановкаБП", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
Сообщить("Не удалось остановить процесс: " + Ссылка);
КонецПопытки;
Подведем итоги. Если программная остановка не срабатывает:
Завершен, но и обновляете реквизит Состояние (если он есть в конфигурации).БизнесПроцессыИЗадачиВызовСервера или аналогичные методы вашей конфигурации.Соблюдение этих правил позволит вам корректно управлять жизненным циклом бизнес-процессов из кода, сохраняя целостность данных в информационной базе.