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