В практике разработчика 1С часто возникает задача: необходимо открыть форму нового, еще не записанного в базу данных документа, предварительно заполнив его реквизиты и табличную часть (ТЧ). При этом критически важно предоставить пользователю выбор — записать этот документ, провести или просто закрыть форму без сохранения изменений.
Особую сложность эта задача вызывает в современных комплексных конфигурациях, таких как 1С:ERP Управление предприятием, 1С:Комплексная автоматизация или 1С:Управление торговлей. Разработчики часто сталкиваются с тем, что при программном открытии формы и заполнении её реквизитов строки табличной части визуально остаются пустыми. Данные внутри объекта вроде бы присутствуют (это видно в отладчике), но на форме они не отображаются до тех пор, пока документ не будет записан или проведен.
Давайте подробно разберем, почему возникает такое поведение платформы «1С:Предприятие 8.3», проанализируем архитектурные особенности управляемых форм и рассмотрим несколько надежных способов решения этой задачи.
---
Для того чтобы понять, почему строки ТЧ «исчезают» или отображаются пустыми при стандартном открытии формы, нам нужно заглянуть во внутреннее устройство управляемого приложения.
В управляемых формах работа с данными происходит не напрямую через объект базы данных (например, ДокументОбъект), а через его специальную проекцию на форму. Данные формы представлены типами ДанныеФормыСтруктура (для шапки документа) и ДанныеФормыКоллекция (для табличных частей). Это сделано для минимизации трафика между клиентом и сервером.
В крупных типовых конфигурациях (ERP, КА, УТ) разработчики фирмы «1С» часто связывают элементы интерфейса формы не напрямую с физическими табличными частями документа. Для реализации сложного функционала (такого как автоматический расчет скидок, распределение НДС, работа со статусами строк, упаковками и ключами связи) на форме выводятся виртуальные таблицы или специальные реквизиты формы.
Когда мы пытаемся заполнить ТЧ напрямую на клиенте с помощью простого добавления строк:
// Такой подход часто приводит к пустым строкам на форме:
НоваяСтрока = Форма.Объект.Товары.Добавить();
НоваяСтрока.Номенклатура = ВыбраннаяНоменклатура;
Мы обходим стандартные механизмы инициализации документа. Форма открывается, но встроенные в нее алгоритмы пересчета и визуализации (которые обычно отрабатывают при создании формы на сервере) не запускаются. В результате данные в коллекции формы есть, но визуальные элементы управления не синхронизированы с ними. При записи или проведении документа срабатывает принудительный пересчет, и данные «внезапно» появляются.
Рассмотрим по шагам правильные и архитектурно верные способы решения этой задачи без снятия конфигурации с поддержки.
---
Этот способ является наиболее чистым с точки зрения стандартов разработки фирмы «1С». Платформа предоставляет штатный механизм заполнения документов при создании. Мы можем передать структуру параметров в форму нового документа при ее открытии.
Поскольку напрямую передать объект типа ТаблицаЗначений с клиента на сервер мы не можем, мы преобразуем табличную часть в Массив Структур. Каждая структура в массиве будет представлять собой строку будущей табличной части.
Проанализируем пример кода, выполняемый на клиенте:
&НаКлиенте
Процедура ОткрытьФормуНовогоДокумента()
// 1. Создаем общую структуру для параметров заполнения
ПараметрыЗаполнения = Новый Структура;
// Заполняем реквизиты шапки документа
ПараметрыЗаполнения.Вставить("Организация", СсылкаНаОрганизацию);
ПараметрыЗаполнения.Вставить("Контрагент", СсылкаНаКонтрагента);
ПараметрыЗаполнения.Вставить("Валюта", СсылкаНаВалюту);
// 2. Формируем массив структур для табличной части "Товары"
МассивСтрокТовары = Новый Массив;
// Пример заполнения одной строки (в реальном коде здесь будет цикл)
СтрокаТовара = Новый Структура;
СтрокаТовара.Вставить("Номенклатура", СсылкаНаНоменклатуру);
СтрокаТовара.Вставить("Количество", 10);
СтрокаТовара.Вставить("Цена", 150);
СтрокаТовара.Вставить("СтавкаНДС", ПредопределенноеЗначение("Перечисление.СтавкиНДС.НДС20"));
МассивСтрокТовары.Добавить(СтрокаТовара);
// Добавляем массив табличной части в общую структуру параметров
ПараметрыЗаполнения.Вставить("Товары", МассивСтрокТовары);
// 3. Помещаем структуру в специальный параметр формы "ЗначенияЗаполнения"
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("ЗначенияЗаполнения", ПараметрыЗаполнения);
// 4. Открываем форму нового документа
ОткрытьФорму("Документ.РеализацияТоваровУслуг.ФормаОбъекта", ПараметрыФормы);
КонецПроцедуры
При таком подходе платформа автоматически инициализирует создание нового документа и передаст структуру ПараметрыЗаполнения в обработчик модуля объекта ОбработкаЗаполнения.
Важный нюанс для конфигураций на поддержке: если в типовом документе логика заполнения ТЧ через входящие параметры не описана или конфигурация полностью закрыта от изменений, мы можем использовать **Расширение конфигурации**. Достаточно заимствовать в расширение модуль объекта документа и добавить метод &После("ОбработкаЗаполнения"), в котором выполнить чтение переданного массива структур и заполнить ТЧ стандартным способом.
---
Если вам необходимо выполнить заполнение формы документа сложным программным путем непосредственно перед её показом пользователю, следует использовать связку клиент-серверного взаимодействия и встроенные функции платформы: ДанныеФормыВЗначение и ЗначениеВДанныеФормы.
Этот способ позволяет получить полноценный прикладной объект (ДокументОбъект), заполнить его со всеми проверками на сервере, а затем корректно спроецировать его обратно на форму управляемого приложения.
Разберем детальный шаблон реализации этого метода:
&НаКлиенте
Процедура ОткрытьИЗаполнитьФормуДокумента()
// 1. Получаем форму нового незаписанного документа
ИмяФормы = "Документ.ЗаказКлиента.ФормаОбъекта";
ФормаДокумента = ПолучитьФорму(ИмяФормы);
// 2. Извлекаем данные формы (структуру данных)
ДанныеФормы = ФормаДокумента.Объект;
// 3. Вызываем серверную процедуру для корректного заполнения объекта
ЗаполнитьДокументНаСервере(ДанныеФормы);
// 4. Копируем измененные данные обратно в форму
КопироватьДанныеФормы(ДанныеФормы, ФормаДокумента.Объект);
// 5. Открываем форму пользователю
ФормаДокумента.Открыть();
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ЗаполнитьДокументНаСервере(ДанныеФормы)
// Преобразуем данные формы в полноценный прикладной объект 1С
ДокументОбъект = ДанныеФормыВЗначение(ДанныеФормы, Тип("ДокументОбъект.ЗаказКлиента"));
// Теперь у нас в руках полноценный ДокументОбъект со всеми методами метаданных.
// Выполняем заполнение реквизитов шапки:
ДокументОбъект.Дата = ТекущаяДатаСеанса();
ДокументОбъект.Соглашение = Справочники.СоглашенияСКлиентами.ПолучитьШаблонСоглашения();
// Заполняем табличную часть "Товары"
НоваяСтрока = ДокументОбъект.Товары.Добавить();
НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоРеквизиту("Артикул", "001");
НоваяСтрока.Количество = 5;
// КРИТИЧЕСКИ ВАЖНО для ERP/КА/УТ:
// В типовых конфигурациях обязательно нужно вызывать стандартные серверные модули пересчета,
// чтобы заполнились скрытые служебные реквизиты (ключи связи строк, ставки НДС, склады и т.д.)
// Например:
// ОбработкаТабличнойЧастиТоварыСервер.ЗаполнитьРеквизитыПриИзмененииНоменклатуры(НоваяСтрока, ДокументОбъект);
// Преобразуем измененный ДокументОбъект обратно в структуру Данных Формы
ЗначениеВДанныеФормы(ДокументОбъект, ДанныеФормы);
КонецПроцедуры
Этот метод гарантирует, что все связи и структуры управляемой формы обновятся корректно, и пользователь увидит полностью заполненную табличную часть сразу при открытии окна.
---
В случае, когда необходимо передать большой объем данных (например, когда ТЧ содержит сотни строк с характеристиками, сериями или ценами), передача тяжелых массивов структур через параметры клиента может замедлить работу интерфейса. В таких ситуациях идеальным решением выступает **Временное хранилище**.
Давайте проанализируем алгоритм этого подхода:
ТаблицаЗначений с нужной структурой колонок.ПоместитьВоВременноеХранилище(ТаблицаДанных, УникальныйИдентификаторФормы). Полученный адрес передается на клиент.АдресХранилища.ПриСозданииНаСервере данные извлекаются из хранилища и загружаются в ТЧ документа с помощью метода Объект.Товары.Загрузить(ПолучитьИзВременногоХранилища(Параметры.АдресХранилища)).Этот способ работает максимально быстро и экономит сетевой трафик между клиентом и сервером приложения.
---
В ходе обсуждения на форуме коллеги справедливо заметили, что использование технологии COMConnector для связи баз в современном ландшафте 1С является устаревшим и несет в себе множество рисков:
Вместо COM-соединений для задач интеграции и получения данных «на лету» для заполнения форм рекомендуется использовать современные **HTTP-сервисы (REST API)** или **Web-сервисы (SOAP)**. База-источник публикует простой HTTP-сервис, а база-приемник отправляет быстрый запрос и получает легкий JSON-пакет, который затем легко парсится и преобразуется в структуру заполнения документа.