Как проверить, что документ проводится из управляемой формы, и передать признак в модуль объекта?

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

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

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

Выясним причину: почему не работают стандартные подходы?

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

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

Способ 1. Передача признака через событие формы ПередЗаписьюНаСервере

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

Разберем по шагам реализацию этого механизма.

Шаг 1. Модуль управляемой формы. В обработчике события ПередЗаписьюНаСервере заполняем коллекцию ДополнительныеСвойства у параметра ТекущийОбъект:


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    // Передаем признак того, что запись инициирована из формы
    ТекущийОбъект.ДополнительныеСвойства.Вставить("ПровереноВФорме", Истина);
    
КонецПроцедуры

Шаг 2. Модуль объекта документа. В событиях ПередЗаписью или ОбработкаПроведения проверяем наличие переданного свойства. Если свойство отсутствует, значит, документ проводится программно, и необходимо выполнить полную проверку с безусловным откатом транзакции при ошибке:


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

Способ 2. Организация интерактивного вопроса перед записью (асинхронный паттерн)

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

  1. В клиентском обработчике ПередЗаписью на форме вызывается предварительная проверка (серверная функция без открытия транзакции записи).
  2. Если обнаружены предупреждения, запись отменяется установкой Отказ = Истина, и пользователю асинхронно задается вопрос через процедуру ПоказатьВопрос.
  3. Если пользователь нажимает «Да», форма повторно инициирует запись с передачей специального параметра в структуре параметров записи.

Посмотрим на пример реализации в модуле управляемой формы:


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

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

&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    Если ПараметрыЗаписи.Свойство("ПодтвержденоПользователем") Тогда
        ТекущийОбъект.ДополнительныеСвойства.Вставить("ПровереноВФорме", Истина);
    КонецЕсли;
    
КонецПроцедуры

Выводы и рекомендации

Подведем итог: для надежного взаимодействия между формой и объектом документа управляемого приложения следует придерживаться следующих правил:

  1. Никогда не использовать параметры сеанса для передачи кратковременных контекстных флагов.
  2. Для передачи служебных параметров в транзакцию записи формы всегда использовать свойство ТекущийОбъект.ДополнительныеСвойства в процедуре ПередЗаписьюНаСервере.
  3. Все диалоговые окна и вопросы пользователю выполнять исключительно на клиенте до открытия транзакции записи базы данных.
← На главную