Как программно открыть управляемую форму документа из процедуры ОбработкаЗаполнения?

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

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

Почему нельзя открыть форму из ОбработкаЗаполнения

Проанализируем контекст исполнения кода. Процедура ОбработкаЗаполнения располагается в модуле объекта и выполняется строго на сервере. На стороне сервера графическая подсистема и интерфейсный контекст клиента отсутствуют в принципе.

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

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

Вариант 1. Реализация через пользовательскую клиентскую команду

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

Разберем по шагам логику работы такого алгоритма:

  1. Пользователь нажимает кнопку команды на клиенте.
  2. Серверная функция подготавливает необходимые структуры данных для обоих документов (или выполняет их запись, если это строго регламентировано).
  3. На клиенте последовательно вызывается метод ОткрытьФорму() для каждого создаваемого документа.

Посмотрим на пример клиентского обработчика команды:


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

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


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

Вариант 2. Передача параметров через форму и открытие в ПриОткрытии

Если бизнес-процесс требует использования стандартного меню «Создать на основании», алгоритм разделяется между модулем объекта и модулем формы нового документа:

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

Рассмотрим пример модуля формы первого документа:


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

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

Для корректной и стабильной отрисовки интерфейса вызов второй формы в событии ПриОткрытии можно также передавать через ПодключитьОбработчикОжидания() с минимальным интервалом времени (0.1 сек) и признаком однократного вызова.

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

← На главную