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