Как программно открыть управляемую форму документа при вводе на основании

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

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

Почему не работают методы открытия формы в модуле объекта

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

Методы платформы, отвечающие за интерактивное отображение окон:

  1. ОткрытьФорму — доступен только на клиенте (тонкий клиент, веб-клиент, толстый клиент, мобильное приложение).
  2. ОткрытьЗначение — доступен только на клиенте.
  3. ПолучитьФорму — доступен только на клиенте (в режиме управляемого приложения на сервере вызов данного метода приводит к ошибке или не позволяет управлять отображением окна).

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

Решение 1. Открытие связанного документа в обработчике формы «ПриОткрытии»

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

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

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

Решение 2. Передача параметров через стандартный параметр «ЗначенияЗаполнения»

Посмотрим на более универсальный механизм платформы. При программном вызове ОткрытьФорму можно передать предопределенный параметр ЗначенияЗаполнения. Платформа 1С автоматически передаст это значение в процедуру ОбработкаЗаполнения нового объекта на сервере:


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

КонецПроцедуры

При таком подходе платформа сама инициализирует новый объект на сервере и передаст структуру в параметр ДанныеЗаполнения.

Решение 3. Передача сложных табличных данных через временное хранилище

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

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

Таким образом, мы соблюдаем строгое разделение клиентского и серверного контекстов: вычисления и подготовка данных выполняются на сервере, а управление отображением окон и вызовы ОткрытьФорму — исключительно на клиенте.

← На главную