Как программно объединить данные из табличных частей Товары и Услуги в одну таблицу

Программист 1С v8.3 (Управляемые формы)
← На главную

В практике разработки на платформе 1С:Предприятие часто возникает задача консолидации данных. Типичный пример: в документе-источнике данные разнесены по разным вкладкам (табличным частям), например, Товары и Услуги, а в документе-приемнике или в печатной форме их необходимо свести в единый список. Рассмотрим подробнее, как это реализовать эффективно, избегая типичных ошибок новичков.

Проблема использования метода Загрузить()

Разберем ситуацию, с которой столкнулся автор темы. Попытка последовательного использования метода Загрузить() для одной и той же табличной части не приводит к желаемому результату:


// Ошибочный подход
ОбъектПриемник.Товары.Загрузить(Основание.Товары.Выгрузить());
ОбъектПриемник.Товары.Загрузить(Основание.Услуги.Выгрузить()); 

Проанализируем причину: метод Загрузить() полностью очищает коллекцию-приемник перед тем, как наполнить её новыми данными. В итоге в документе останутся только данные из последней загруженной таблицы (в данном случае — из услуг), а товары будут стерты. Выясним, как сделать это правильно.

Способ 1: Использование промежуточной Таблицы Значений и цикла

Этот метод является наиболее гибким и понятным. Мы сначала выгружаем данные одной табличной части в объект типа ТаблицаЗначений, а затем дополняем эту таблицу строками из второй части. Рассмотрим по шагам реализацию, предложенную в обсуждении:

  1. Выгружаем первую табличную часть (например, товары) в промежуточную таблицу.
  2. Запускаем цикл по строкам второй табличной части (услуги).
  3. Для каждой строки услуг создаем новую строку в нашей общей таблице.
  4. Используем функцию ЗаполнитьЗначенияСвойств() для автоматического копирования данных из колонок с одинаковыми именами.

Посмотрим на пример кода:


// Выгружаем товары в таблицу значений
КоллекцияОбъектов = Источник.Товары.Выгрузить();

// Добавляем услуги в ту же таблицу
Для Каждого СтрокаУслуги Из Источник.Услуги Цикл
    НоваяСтрока = КоллекцияОбъектов.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаУслуги);
КонецЦикла;

// Теперь загружаем объединенный результат в целевой документ
ДокументОбъект.ОбщаяТаблица.Загрузить(КоллекцияОбъектов);

Важный нюанс: Метод ЗаполнитьЗначенияСвойств сработает успешно только в том случае, если имена колонок в табличных частях Товары и Услуги совпадают (например, Номенклатура, Количество, Сумма). Если в услугах поле называется Содержание, а в товарах Номенклатура, вам потребуется прописать соответствие вручную внутри цикла.

Способ 2: Объединение через запрос (UNION ALL)

Проанализируем более профессиональный и производительный метод. Если данных много, использование циклов может замедлить работу системы. В таких случаях лучше всего использовать механизм запросов с оператором ОБЪЕДИНИТЬ ВСЕ. Это позволит системе на уровне СУБД подготовить единый набор данных.

Рассмотрим пример построения такого запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Т.Номенклатура КАК Номенклатура,
    |   Т.Количество КАК Количество,
    |   Т.Сумма КАК Сумма
    |ИЗ
    |   Документ.РеализацияТоваровУслуг.Товары КАК Т
    |ГДЕ
    |   Т.Ссылка = &Ссылка
    |
    |ОБЪЕДИНИТЬ ВСЕ
    |
    |ВЫБРАТЬ
    |   У.Номенклатура,
    |   У.Количество,
    |   У.Сумма
    |ИЗ
    |   Документ.РеализацияТоваровУслуг.Услуги КАК У
    |ГДЕ
    |   У.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", ДокументОснование);
РезультатЗапроса = Запрос.Выполнить();

// Выгружаем в ТЗ или сразу заполняем ТЧ
ДокументПриемник.ОбщаяТЧ.Загрузить(РезультатЗапроса.Выгрузить());

Этот способ хорош тем, что мы можем сразу привести типы данных или переименовать колонки прямо в тексте запроса, используя конструкцию КАК.

Нюансы обработки типов данных

При объединении товаров и услуг часто возникает проблема несовпадения типов. Разберем ситуацию: в товарах всегда указана ссылка на справочник Номенклатура, а в услугах поле номенклатуры может быть пустым, но заполнено текстовое поле Содержание.

Если ваша целевая табличная часть имеет колонку Номенклатура с типом СправочникСсылка.Номенклатура, вы не сможете записать туда произвольный текст из услуг. В таком случае рекомендуется:

Использование Библиотеки стандартных подсистем (БСП)

Если вы работаете в современной конфигурации (например, ERP, КА или УТ 11), в ней наверняка присутствует БСП. Мы можем воспользоваться встроенными методами для работы с таблицами, которые уже оптимизированы.

Например, метод ОбщегоНазначения.СкопироватьТаблицуЗначений или работа с коллекциями строк позволяют более гибко управлять процессом переноса, включая проверку на наличие колонок, чтобы избежать ошибок выполнения кода при отсутствии какого-либо реквизита в одной из ТЧ.

Порядок строк и индексация

Стоит учитывать, что при ручном добавлении (Способ 1) услуги всегда окажутся в конце списка, после всех товаров. Если бизнес-логика требует сохранения определенного порядка (например, по номеру строки, как они шли в исходном документе), вам придется добавить в таблицу временную колонку ИсходныйНомер, выгрузить в неё данные НомерСтроки, объединить таблицы и выполнить сортировку методом КоллекцияОбъектов.Сортировать("ИсходныйНомер"); перед окончательной загрузкой в документ.

← На главную