Как открыть форму нового заполненного документа без записи в базу данных в управляемом приложении?

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

При разработке в управляемом интерфейсе 1С часто возникает задача: сформировать новый документ, программно заполнить его реквизиты (включая табличные части) и показать пользователю на экране, не сохраняя объект в базу данных. В этом случае пользователь должен сам принять решение — записать документ по кнопке или закрыть форму без сохранения.

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

Почему возникает ошибка при передаче объекта на клиент?

Проанализируем клиент-серверную архитектуру платформы «1С:Предприятие 8.3». На стороне тонкого клиента типы группы ДокументОбъект, СправочникОбъект и им подобные недоступны. Они существуют исключительно в контексте сервера. Попытка вернуть созданный или полученный объект из функции с директивой &НаСервере на клиент вызывает ошибку сериализации.

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

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

Способ 1. Заполнение через данные формы и функцию КопироватьДанныеФормы()

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

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

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

Посмотрим на пример реализации данного алгоритма:


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

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

Важный момент: прямое присвоение свойств объекту формы на клиенте или попытка перезаписать ФормаДокумента.Объект напрямую вызовет исключение платформы. Именно поэтому использование метода КопироватьДанныеФормы() является обязательным.

Способ 2. Открытие формы с параметром ЗначенияЗаполнения

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

Платформа позволяет передать структуру ЗначенияЗаполнения в качестве параметра метода ОткрытьФорму(). Имена ключей структуры должны совпадать с именами реквизитов документа.

Посмотрим на пример заполнения через структуру:


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

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


&НаСервере
Функция ПолучитьСтруктуруЗаполнения(ИсточникСсылка)
    
    СтруктураЗаполнения = Новый Структура;
    МетаданныеДокумента = ИсточникСсылка.Метаданные();
    
    Для Каждого Реквизит Из МетаданныеДокумента.Реквизиты Цикл
        СтруктураЗаполнения.Вставить(Реквизит.Имя, ИсточникСсылка[Реквизит.Имя]);
    КонецЦикла;
    
    Возврат СтруктураЗаполнения;
    
КонецФункции

Ограничение способа: передать напрямую ТаблицуЗначений в параметр ЗначенияЗаполнения с клиента нельзя, так как этот тип не поддерживается на тонком клиенте. Для заполнения табличных частей данным способом потребуется дополнительная обработка структуры в процедуре ОбработкаЗаполнения модуля объекта.

Способ 3. Передача заполненного объекта через временное хранилище

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

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

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

Код вызывающей стороны:


&НаКлиенте
Процедура ОткрытьЧерезХранилище()
    
    АдресХранилища = СформироватьДокументВХранилище();
    
    ПараметрыОткрытия = Новый Структура("АдресВоВременномХранилище", АдресХранилища);
    ОткрытьФорму("Документ.РеализацияТоваровУслуг.ФормаОбъекта", ПараметрыОткрытия);
    
КонецПроцедуры

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

Код в модуле формы открываемого документа (в событии ПриСозданииНаСервере):


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

Способ 4. Использование механизма ввода на основании (ОбработкаЗаполнения)

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


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

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

← На главную