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