При работе с legacy-кодом или адаптации старых отчетов под управляемые формы программисты часто сталкиваются с необходимостью использовать ПостроительОтчета. Несмотря на то, что современным стандартом разработки является Система компоновки данных (СКД), в некоторых конфигурациях до сих пор успешно функционируют механизмы на базе построителя, которые приходится поддерживать и дорабатывать в тонком клиенте.
Типичная проблема возникает при попытке выгрузить кросс-таблицу или сложный многоуровневый отчет в формат Microsoft Excel. Платформа 1С при формировании отчета через ПостроительОтчета принудительно выводит промежуточные итоги по группировкам строк. При выгрузке такого документа в Excel формулы и сторонние макросы начинают задваивать или застраивать итоговые суммы, что делает дальнейший автоматизированный анализ данных невозможным. Выясним, почему возникает эта проблема, и разберем несколько способов ее решения.
В объекте ПостроительОтчета за вывод итогов отвечает свойство РазмещениеИтоговВСтроках. Данное свойство принимает значения из системного перечисления ТипРазмещенияИтогов. К сожалению, архитектура этого объекта не предполагает варианта «Не выводить вообще». Платформа предлагает лишь настроить их положение:
Если поле добавлено в коллекцию ИзмеренияСтроки, обойти это ограничение стандартными свойствами построителя невозможно. Нам придется прибегнуть к постобработке готового табличного документа.
Ниже мы подробно проанализируем четыре практических метода решения этой проблемы: от быстрого «костыля» до профессиональных и высокопроизводительных подходов.
---
Рассмотрим алгоритм, предложенный автором обсуждения. Идея заключается в том, что после формирования отчета мы получаем готовый ТабличныйДокумент. Строки детальных записей, как правило, имеют белый фон, в то время как строки группировок и итогов окрашиваются макетом оформления в отличные от белого цвета.
Разберем по шагам логику этого решения:
КоличествоУровнейГруппировокСтрок().Разгруппировать(), чтобы пользователю не выводились «плюсики» сворачивания.Посмотрим на пример реализации данного алгоритма:
КолвоУровней = ЭтаФорма.Результат.КоличествоУровнейГруппировокСтрок();
Если КолвоУровней > 1 Тогда
Таб = ЭтаФорма.Результат;
Строк = Таб.ВысотаТаблицы;
// Снимаем группировку со всего документа
Таб.Область("R1:R" + Формат(Строк, "ЧРГ=; ЧГ=0")).Разгруппировать();
ИндексСтроки = 2; // Предполагаем, что строка 1 — это шапка
Пока ИндексСтроки <= Таб.ВысотаТаблицы Цикл
ЯчейкаПроверки = Таб.Область(ИндексСтроки, 2, ИндексСтроки, 2);
Цвет = ЯчейкаПроверки.ЦветФона;
// Проверяем, является ли цвет белым
Если (Цвет.Зеленый = 255) И (Цвет.Красный = 255) И (Цвет.Синий = 255) Тогда
ИндексСтроки = ИндексСтроки + 1;
Иначе
// Удаляем строку группировки/итога
ОбластьУдаления = Таб.Область("R" + Формат(ИндексСтроки, "ЧРГ=; ЧГ=0"));
Таб.УдалитьОбласть(ОбластьУдаления, ТипСмещенияТабличногоДокумента.ПоВертикали);
КонецЕсли;
КонецЦикла;
КонецЕсли;
Преимущества метода: Простота реализации без необходимости глубоко влезать в структуру запросов построителя.
Критические недостатки:
УдалитьОбласть() в цикле по вертикали заставляет платформу пересчитывать геометрию всего документа при каждой итерации. На таблицах более 1000 строк этот код вызовет серьезное зависание интерфейса 1С.---
Чтобы уйти от нестабильной проверки цветов, проанализируем внутреннее содержимое ячеек. При выводе итоговых строк ПостроительОтчета помещает в свойство ПараметрРасшифровки ячеек специальную структуру, содержащую информацию о группировке. У детальных же записей в расшифровке находится ссылка на элемент справочника, документ или простое значение.
Рассмотрим, как можно надежно выявить и очистить строки итогов на основе анализа типа данных расшифровки:
Таб = ЭтаФорма.Результат;
ИндексСтроки = Таб.ВысотаТаблицы;
// Обходим таблицу снизу вверх, чтобы корректно удалять строки без сдвига индексов
Пока ИндексСтроки > 1 Цикл
Ячейка = Таб.Область(ИндексСтроки, 1); // Проверяем первую колонку группировки
Расшифровка = Ячейка.ПараметрРасшифровки;
// Строки группировок и итогов часто содержат структуру или массив в расшифровке
Если ТипЗнч(Расшифровка) = Тип("Структура") Тогда
ОбластьУдаления = Таб.Область("R" + Формат(ИндексСтроки, "ЧРГ=; ЧГ=0"));
Таб.УдалитьОбласть(ОбластьУдаления, ТипСмещенияТабличногоДокумента.ПоВертикали);
КонецЕсли;
ИндексСтроки = ИндексСтроки - 1;
КонецЦикла;
Этот способ гораздо стабильнее, так как он не зависит от визуального отображения, стилей или настроек монитора пользователя.
---
Если ваш отчет содержит тысячи строк, последовательное удаление областей со сдвигом парализует работу пользователя. Оптимизируем этот процесс. Вместо удаления «плохих» строк из готового документа, мы создадим новый пустой ТабличныйДокумент и скопируем в него только «хорошие» (детальные) строки.
Разберем пример быстрой сборки плоской таблицы:
ИсходныйТаб = ЭтаФорма.Результат;
НовыйТаб = Новый ТабличныйДокумент;
// Копируем параметры страницы и шапку (допустим, первые 3 строки)
НовыйТаб.Вывести(ИсходныйТаб.Область("R1:R3"));
Для НомерСтроки = 4 По ИсходныйТаб.ВысотаТаблицы Цикл
Ячейка = ИсходныйТаб.Область(НомерСтроки, 1);
// Проверяем, является ли строка детальной (например, по типу значения расшифровки)
Если ТипЗнч(Ячейка.ПараметрРасшифровки) <> Тип("Структура") Тогда
// Выводим только детальные строки
НовыйТаб.Вывести(ИсходныйТаб.Область("R" + Формат(НомерСтроки, "ЧРГ=; ЧГ=0")));
КонецЕсли;
КонецЦикла;
// Заменяем результат на очищенный документ
ЭтаФорма.Результат = НовыйТаб;
Этот метод работает в десятки раз быстрее, так как операция Вывести() в новый документ выполняется линейно и не требует постоянной перестройки индексов строк исходного макета.
---
Проанализируем структуру нашего отчета. Если нам требуется получить плоскую таблицу без иерархии группировок, лучшим решением будет вообще отказаться от добавления нескольких полей в коллекцию ИзмеренияСтроки.
Вместо этого мы можем использовать механизм дополнительных полей:
ИзмеренияСтроки добавляем только одно, самое конечное и детальное измерение (например, Номенклатура или Контрагент).ВыбранныеПоля как дополнительные поля.
ПостроительОтчета.РазмещениеДополнительныхПолей = ТипРазмещенияДополнительныхПолей.ВОтдельныхКолонках;
ПостроительОтчета.ВыводитьОбщиеИтоги = Ложь;
При таком подходе платформа сформирует абсолютно плоскую таблицу, где каждое измерение будет выведено в отдельной колонке на уровне детальных записей, а промежуточные группировочные строки просто не будут созданы. Это самый чистый способ получения готового к выгрузке в Excel файла, не требующий написания громоздких циклов постобработки табличного документа.