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