Итак, сначала нам понадобится добавить немного кода в общие модули.
В серверный общий модуль (в моем примере его имя будет СерверныйОбщийМодуль) добавляем функцию СтруктураПоОбъектуМетаданных() и процедуру ЗаполнитьОбъектИзСтруктурыВоВременномХранилище()
// Возвращает структуру с теми же реквизитами, что и объекта (справочника, документа и т.д.). Табличные части как пустые таблицы значений
//
// Параметры:
// ПолноеИмяОбъектаМетаданных - Строка - полное имя объекта метаданных
//
// Возвращаемое значение:
// Структура - структура, в которой ключи - имена реквизитов и табличных частей объекта
//
Функция СтруктураПоОбъектуМетаданных(ПолноеИмяОбъектаМетаданных) Экспорт
Результат = Новый Структура;
ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(ПолноеИмяОбъектаМетаданных);
Если ОбъектМетаданных = Неопределено Тогда
Сообщить("Не найден объект метаданных по полному имени "+ПолноеИмяОбъектаМетаданных);
Возврат Результат;
КонецЕсли;
Для Каждого Реквизит Из ОбъектМетаданных.СтандартныеРеквизиты Цикл
Результат.Вставить(Реквизит.Имя);
КонецЦикла;
Для Каждого Реквизит Из ОбъектМетаданных.Реквизиты Цикл
Результат.Вставить(Реквизит.Имя);
КонецЦикла;
Для Каждого ОбщийРеквизит Из Метаданные.ОбщиеРеквизиты Цикл
ЭлементСоставаОбщегоРеквизита = ОбщийРеквизит.Состав.Найти(ОбъектМетаданных);
Если ЭлементСоставаОбщегоРеквизита <> Неопределено И СтрСравнить(Строка(ЭлементСоставаОбщегоРеквизита.Использование), "Использовать") = 0 Тогда
Результат.Вставить(ОбщийРеквизит.Имя);
КонецЕсли;
КонецЦикла;
Для Каждого ТабличнаяЧасть Из ОбъектМетаданных.ТабличныеЧасти Цикл
ТЧ = Новый ТаблицаЗначений;
Для Каждого РеквизитТЧ Из ТабличнаяЧасть.Реквизиты Цикл
ТЧ.Колонки.Добавить(РеквизитТЧ.Имя);
КонецЦикла;
Результат.Вставить(ТабличнаяЧасть.Имя, ТЧ);
КонецЦикла;
Возврат Результат;
КонецФункции
// Заполняет объект по ДанныеЗаполнения (адрес структуры во временном хранилище, повторяющей объект документа)
//
// Параметры:
// ДанныеЗаполнения - Строка - адрес структуры во временном хранилище. Ключи структуры - имена реквизитов/табличных частей, а значения - значения реквизитов/таблицы значений
// Создать такую структуру с незаполненными значениями можно вызовом функции СтруктураПоОбъектуМетаданных()
//
Процедура ЗаполнитьОбъектИзСтруктурыВоВременномХранилище(Источник, ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка) Экспорт
Если ТипЗнч(ДанныеЗаполнения) = Тип("Строка") И ЭтоАдресВременногоХранилища(ДанныеЗаполнения) Тогда
СтруктураОбъекта = ПолучитьИзВременногоХранилища(ДанныеЗаполнения);
Если ТипЗнч(СтруктураОбъекта) = Тип("Структура") Тогда
ИменаТабличныхЧастей = Новый Массив;
ПропускаемыеКлючи = Новый Массив;
Для Каждого КЗ Из СтруктураОбъекта Цикл
Если ТипЗнч(КЗ.Значение) = Тип("ТаблицаЗначений") Тогда
ИменаТабличныхЧастей.Добавить(КЗ.Ключ);
ПропускаемыеКлючи.Добавить(КЗ.Ключ);
Иначе
Если КЗ.Значение = Неопределено Тогда
ПропускаемыеКлючи.Добавить(КЗ.Ключ);
КонецЕсли;
КонецЕсли;
КонецЦикла;
Попытка
//заполним реквизиты объекта
ЗаполнитьЗначенияСвойств(Источник, СтруктураОбъекта, , СтрСоединить(ПропускаемыеКлючи, ","));
//заполним табличные части объекта
Для Каждого ИмяТабличнойЧасти Из ИменаТабличныхЧастей Цикл
Источник[ИмяТабличнойЧасти].Загрузить(СтруктураОбъекта[ИмяТабличнойЧасти]);
КонецЦикла;
Исключение
Сообщить("При заполнении возникла ошибка: "+ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Далее, там где мы хотим открыть форму незаписанного документа с уже заполненными данными пишем
&НаКлиенте
Процедура СоздатьЗаполнитьИОткрытьНовыйДокумент()
АдресХранилища = СоздатьНовыйДокументНаСервере();
ПараметрыОткрытия = Новый Структура("Основание", АдресХранилища);
ОткрытьФорму("Документ.РасходныйОрдер.ФормаОбъекта", ПараметрыОткрытия, ЭтаФорма, УникальныйИдентификатор);
КонецПроцедуры
&НаСервере
Функция СоздатьНовыйДокументНаСервере()
//получаем структуру, повторяющую все реквизиты и табличные части документа
ДокСтруктура = СерверныйОбщийМодуль.СтруктураПоОбъектуМетаданных("Документ.Поступление");
//заполняем структуру нужными данными
ДокСтруктура.Контрагент = Объект.Контрагент;
Для Каждого ТекСтрока Из Объект.Товары Цикл
НоваяСтрока = ДокСтруктура.Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, ТекСтрока);
КонецЦикла;
//помещаем заполненную структуру в хранилище и возвращаем адрес хранилища
Возврат ПоместитьВоВременноеХранилище(ДокСтруктура, УникальныйИдентификатор);
КонецФункции
Теперь нам нужно чтобы в обработке заполнения открываемого документа вызвалась процедура ЗаполнитьОбъектИзСтруктурыВоВременномХранилище(). Проще всего сделать, это создав подписку на событие ОбработкаЗаполнения. В эту подписку включаем все нужные нам документы (те документы, которые мы хотим открывать и заполнять). В качестве обработчика подписки на событие указываем процедуру ЗаполнитьОбъектИзСтруктурыВоВременномХранилище(). Либо можно непосредственно в процедуре ОбработкаЗаполнения() вызвать СерверныйОбщийМодуль.ЗаполнитьОбъектИзСтруктурыВоВременномХранилище().
Вот собственно и все, процедура и функция в общем модуле универсальные и подойдут для любого типа документа/справочника. Добавим их один раз, можно будет открывать подобным образом любой документ/справочник (не забывая включить его в подписку на событие).
Форма = ОткрытьФорму(«Справочники.Банки.ФормаОбъекта», Новый Структура(«КакиеУгодноПараметры») );
ДанныеФормы = Форма.Объект;
ЗаполнитьНаОснованииКакДушеУгодно(ДанныеФормы);
КопироватьДанныеФормы(ДанныеФормы, Форма.Объект);
И откроется форма незаписанного заполненного документа
А нафига этот троллейбус из буханки?
https://helpf.pro/faq/view/1396.html
Гугл давно решил эту проблему за вас:
Зачем городить какую то структуру, когда можно просто сериализовать сам объект данных в строку и поместить ее во временное хранилище и затем сразу получить из строки XML натуральный объект и преобразовать его в данные формы?
(1) , (2)
Такие способы имеют недостатки. Например сама форма объекта не сможет скорректировать данные нового объекта при необходимости, т.к. не узнает, что они изменились. И даже если мы ей поможем узнать, то ей для этого придется делать лишний серверный вызов. Оба подхода пригодны, но в своих ситуациях.
Не обрабатываются стандартные и общие реквизиты.
(0), (4) Можно пример, где применение этого метода лучше стандартного открытия формы с параметрами? Я что-то не вникну сходу
Сам что то подобное делал недавно, но у меня в отличии от автора, заполняются даже элементы формы, которые не являются реквизитами объекта.
(6) Можно конечно передать в форму параметры и в ПриСозданииНаСервере() заполнить из параметров. Но это придется писать в каждой такой форме, по моему методу достаточно один раз прописать процедуры и далее добавлять нужные объекты в подписку на событие.
(5) Справедливое замечание, добавил их.
(1) Простой пример: если в открываемой форме устанавливается видимость или доступность элементов формы в зависимости от значений реквизитов объекта, то если сначала открыть форму, а потом заполнять, придется дополнительно вызывать эти процедуры. При моем способе открывается уже заполненный объект и все эти процедуры отработают автоматически.
(8), (10)
Делать заполнение в ПриСозданииНаСервере() довольно странный вариант.
Для этого есть ОбработкаЗаполнения()
То что вы передадите вторым параметром в ОткрытьФорму() будет доступно вам в ОбработкаЗаполнения()
И все нужные вам процедуры из (10) отработают корректно
(10)
Показать
Или
Уж если в так пошло то и нужно именно в ПриСозданииНаСервере все заполнять, то:
Расширение управляемой формы для документа (Managed form extension for documents)
ЗначенияЗаполнения (FillingValues)
Описание:
Тип: Структура.
Параметры заполнения нового объекта.
Ключ структуры — имя реквизита формы, значение — заполняемое значение.
итд
А если сильно сильно подумать, то можно взять за основу идею Переопределяемых общих модулей. Добавить в нем ПриСозданииНаСервере. В нужных формах вызвать в событии ПриСозданииНаСервере. Далее в зависимости от открываемой формы и параметров выполнять определенные действия.