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