Как в процедуре ПриКомпоновкеРезультата вывести данные в дополнительный табличный документ или таблицу значений

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

При разработке сложных отчетов на базе Системы компоновки данных (СКД) часто возникает задача вывести информацию не только в стандартный ДокументРезультат, но и в дополнительные структуры данных. Это может быть вторая табличная часть на форме, отдельный ТабличныйДокумент для формирования сводки или промежуточная ТаблицаЗначений для последующих расчетов. Рассмотрим подробнее, как реализовать такие механизмы в процедуре ПриКомпоновкеРезультата модуля объекта отчета.

Способ 1. Программный вывод в коллекцию значений (Таблицу значений)

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


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    // Отключаем стандартный вывод, так как будем управлять процессом вручную
    СтандартнаяОбработка = Ложь;
    
    // 1. Стандартный вывод в ДокументРезультат
    НастройкиОсновнойСхемы = КомпоновщикНастроек.ПолучитьНастройки();
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиОсновнойСхемы, ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    // 2. Дополнительный вывод в Таблицу Значений
    // Важно: для коллекции значений используется другой тип генератора макета
    МакетДляТЗ = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиОсновнойСхемы, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
    
    ПроцессорКомпоновкиТЗ = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновкиТЗ.Инициализировать(МакетДляТЗ, , , Истина);
    
    ПроцессорВыводаТЗ = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
    ТаблицаРезультата = Новый ТаблицаЗначений;
    ПроцессорВыводаТЗ.УстановитьОбъект(ТаблицаРезультата);
    ПроцессорВыводаТЗ.Вывести(ПроцессорКомпоновкиТЗ);
    
    // Теперь данные находятся в ТаблицаРезультата, их можно передать в ТЧ формы или другой документ
    // Например: Объект.МояТабличнаяЧасть.Загрузить(ТаблицаРезультата);

КонецПроцедуры

Выясним причину, по которой этот метод не всегда идеален. Главный минус заключается в том, что фактически запрос к базе данных выполняется дважды. Если отчет строится по огромному массиву данных, время формирования увеличится вдвое. Поэтому перейдем к более оптимальному решению.

Способ 2. Поэлементный обход (самый эффективный метод)

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

  1. Инициализируем ПроцессорКомпоновкиДанных стандартным образом.
  2. Запускаем цикл по элементам результата.
  3. Каждый элемент выводим в основной документ и одновременно анализируем его содержимое для записи в наш дополнительный приемник.

Проанализируем пример реализации такого подхода:


ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);

ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);

// Начинаем вывод
ПроцессорВывода.НачатьВывод();

Пока Истина Цикл
    ЭлементРезультата = ПроцессорКомпоновки.Следующий();
    Если ЭлементРезультата = Неопределено Тогда
        Прервать;
    КонецЕсли;

    // Выводим элемент в основной табличный документ
    ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);

    // Анализируем данные для дополнительного вывода
    // Например, если нам нужны только детальные записи:
    Если ЭлементРезультата.ТипЭлемента = ТипЭлементаРезультатаКомпоновкиДанных.НаборДанных Тогда
        // Здесь можно получить значения полей
        Для Каждого ЗначениеПараметра Из ЭлементРезультата.ЗначенияПараметров Цикл
            // Логика записи данных в вашу ТЗ или второй документ
        КонецЦикла;
    КонецЕсли;
КонецЦикла;

ПроцессорВывода.ЗакончитьВывод();

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

Способ 3. Использование данных расшифровки для сбора итогов

Если ваша задача — вывести в отдельный документ только итоговые показатели (например, список сотрудников и их общие продажи), можно использовать объект ДанныеРасшифровки. Рассмотрим подробнее этот механизм. После того как отчет выведен в ДокументРезультат, коллекция ДанныеРасшифровки.Элементы заполняется информацией о каждой выведенной ячейке.

Мы можем программно обойти элементы расшифровки, найти группировки по сотрудникам и извлечь значения ресурсов. Это избавит нас от необходимости сложной настройки циклов вывода. Однако стоит помнить, что структура данных в расшифровке достаточно специфична и требует аккуратного обращения с индексами полей.

Способ 4. Метод "Скрытых областей"

Рассмотрим еще один оригинальный способ, который часто применяется в управленческой отчетности. Если нужно вывести итоги в отдельный табличный документ, мы можем сделать следующее:

Такой подход позволяет использовать всю мощь визуального оформления СКД (условное оформление, форматы) для обоих документов одновременно.

Резюмируем: выбор метода зависит от объема данных. Для небольших отчетов вполне подойдет Способ 1 с повторным выполнением. Для высокопроизводительных систем рекомендуем использовать Способ 2 с поэлементным обходом через ПроцессорКомпоновки.Следующий(). Это даст максимальный контроль над данными и обеспечит высокую скорость работы отчета.

← На главную