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

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

При разработке бизнес-процессов часто возникает задача: в зависимости от условий прохождения маршрута или завершения параллельных веток ограничить редактирование определенных реквизитов в связанных задачах или документах. Нередко разработчики пытаются решить эту задачу «в лоб» — получить форму задачи прямо в коде точки маршрута через метод ПолучитьФорму() и программно отключить доступность полей через коллекцию Элементы. Однако при таком подходе метод возвращает Неопределено или вызывает исключение. Разберем, почему возникает эта ошибка и как архитектурно правильно управлять поведением формы на основе состояния бизнес-процесса.

Выясним причину: почему точка маршрута не видит форму

Чтобы понять причину проблемы, проанализируем контекст выполнения программного кода платформы «1С:Предприятие 8»:

  1. Серверный контекст выполнения. Код обработчиков точек маршрута бизнес-процесса выполняется исключительно на стороне сервера (в транзакции записи или в рамках фонового задания). На сервере не существует визуального интерфейса и оконной системы конкретного пользователя. Метод ПолучитьФорму() в клиент-серверной архитектуре и управляемом интерфейсе не предназначен для работы на сервере в отрыве от сеанса клиента.
  2. Изоляция клиентских сеансов. Даже если форма задачи уже физически открыта у конкретного исполнителя, серверный фоновый процесс не имеет прямого доступа к памяти чужого клиентского приложения и не может напрямую изменить свойство Доступность у элементов открытого окна.

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

Решение 1. Анализ состояния бизнес-процесса при открытии формы (Data-Driven UI)

Вместо попытки дотянуться до формы из бизнес-процесса мы разворачиваем логику в противоположную сторону. Форма задачи или документа при своем открытии сама должна опросить состояние бизнес-процесса и заблокировать нужные поля.

Рассмотрим, как это реализовать в модуле управляемой формы задачи. Для оптимизации быстродействия проверку и установку доступности рекомендуется выполнять на сервере в обработчике ПриСозданииНаСервере или ПриЧтенииНаСервере:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверяем текущую точку маршрута или состояние связанного процесса
    Если ЗначениеЗаполнено(Объект.ТочкаМаршрута) Тогда
        Если Объект.ТочкаМаршрута = БизнесПроцессы.Согласование.ТочкиМаршрута.ПередачаВРемонт Тогда
            Элементы.РеквизитДляБлокировки.Доступность = Ложь;
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

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

Решение 2. Вынос логики проверки в модуль менеджера или общий модуль

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

Создадим экспортную функцию в модуле менеджера бизнес-процесса или в общем модуле с признаками Сервер и Вызов сервера:


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

КонецФункции

Теперь эту функцию можно одинаково вызывать и в точке маршрута бизнес-процесса, и в модуле формы задачи:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    Если БизнесПроцессы.Согласование.ДолжныБытьЗаблокированыРеквизиты(Объект.БизнесПроцесс) Тогда
        Элементы.ФормаПередачаВРемонт.Доступность = Ложь;
    КонецЕсли;
    
КонецПроцедуры

Решение 3. Изменение поведения типовой формы через расширение конфигурации

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

Разберем по шагам подключение расширения:

  1. Добавим расширение в конфигурацию в режиме Конфигуратор.
  2. Захватим в расширение нужную форму задачи или документа.
  3. В модуле формы расширения перехватим событие ПриСозданииНаСервере или ПриЧтенииНаСервере с директивой &После.

&Вместо("ПриСозданииНаСервере")
// Либо директива &После:
&После("ПриСозданииНаСервере")
Процедура Расш1_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
    
    Если ЗначениеЗаполнено(Объект.БизнесПроцесс) Тогда
        Если БизнесПроцессы.Согласование.ДолжныБытьЗаблокированыРеквизиты(Объект.БизнесПроцесс) Тогда
            Элементы.ФормаПередачаВРемонт.Доступность = Ложь;
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Решение 4. Обновление формы, если она уже открыта у пользователя

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

Для таких сценариев применим механизм оповещений:

  1. В клиентском контексте при завершении задачи (или через механизм фонового опроса/Систему взаимодействия) вызывается метод Оповестить("ОбновлениеЗадачПроцесса", ПараметрыОповещения).
  2. В форме задачи описывается событие ОбработкаОповещения, в котором при совпадении имени события форма обновляет свое состояние и пересчитывает доступность:

&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
    
    Если ИмяСобытия = "ОбновлениеЗадачПроцесса" Тогда
        ЭтаФорма.Прочитать();
        ОбновитьДоступностьЭлементовНаСервере();
    КонецЕсли;
    
КонецПроцедуры

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

← На главную