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