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