При разработке сложных отчетов в Системе компоновки данных (СКД) часто возникает необходимость динамического формирования колонок. Например, когда количество периодов (месяцев или кварталов) заранее неизвестно и зависит от выбранного пользователем интервала. В таких случаях мы создаем поля программно, но стандартный вывод "в ряд" не всегда удобен для чтения. Чтобы сделать отчет профессиональным, необходимо объединять связанные показатели (например, «Остаток», «Себестоимость» и «Сумма») под общим заголовком периода. В этой статье мы подробно разберем, как реализовать программное создание колонок-групп.
Представим ситуацию: нам нужно вывести данные по нескольким периодам. Для каждого периода должны отображаться три колонки. Наша цель — создать над этими тремя колонками общую "шапку" с названием периода. Рассмотрим, какие инструменты предоставляет нам 1С для решения этой задачи. Основная сложность заключается в том, что недостаточно просто добавить поля в набор данных; нужно правильно сконфигурировать Компоновщик настроек, чтобы визуально объединить их в интерфейсе.
Этот метод является наиболее предпочтительным, если ваша задача — исключительно визуальное объединение колонок в итоговом табличном документе. Мы будем работать с объектом ГруппаВыбранныхПолейКомпоновкиДанных. Проанализируем программный код, который позволяет этого добиться.
Рассмотрим пошагово процесс создания такой структуры в цикле:
// Предположим, у нас есть количество периодов в переменной КолПериодов
Для Сч = 1 По КолПериодов Цикл
// 1. Создаем общую группу для текущего периода в настройках СКД
ИмяГруппы = "Период " + Формат(Сч, "ЧГ=0");
ГруппаПолей = НастройкиСКД.Выбор.Элементы.Добавить(Тип("ГруппаВыбранныхПолейКомпоновкиДанных"));
ГруппаПолей.Заголовок = ИмяГруппы;
// КРИТИЧЕСКИ ВАЖНО: устанавливаем горизонтальное расположение,
// чтобы вложенные поля шли слева направо под общим заголовком
ГруппаПолей.Расположение = РасположениеПоляКомпоновкиДанных.Горизонтально;
ГруппаПолей.Использование = Истина;
// 2. Добавляем поля в набор данных схемы (если они не были добавлены ранее)
// Поле "Остаток"
ИмяПоляОстаток = "Остаток_" + Сч;
ПолеНабора = СхемаКомпоновкиДанных.НаборыДанных.НаборДанных1.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
ПолеНабора.ПутьКДанным = ИмяПоляОстаток;
ПолеНабора.Поле = ИмяПоляОстаток;
ПолеНабора.Заголовок = "Остаток";
// 3. Добавляем созданное поле именно ВНУТРЬ ГруппыПолей, а не в корень Выбора
ВыбранноеПоле = ГруппаПолей.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
ВыбранноеПоле.Поле = Новый ПолеКомпоновкиДанных(ИмяПоляОстаток);
ВыбранноеПоле.Использование = Истина;
// Повторяем для других колонок (Себестоимость, Сумма...)
// ...
КонецЦикла;
Разберем, почему это работает. Когда мы добавляем элемент типа ВыбранноеПолеКомпоновкиДанных не в НастройкиСКД.Выбор.Элементы, а в ГруппаПолей.Элементы, система понимает, что это поле иерархически подчинено группе. Свойство Расположение определяет, как эти "дети" будут отрисованы относительно друг друга.
Проанализируем свойство РасположениеПоляКомпоновкиДанных, так как оно кардинально меняет вид отчета:
Существует и другой подход — создание структуры непосредственно в объекте СхемаКомпоновкиДанных. Это полезно, если вы хотите, чтобы пользователь в конструкторе отчета видел поля не плоским списком, а аккуратно разложенными по папкам. Для этого используется объект ПапкаПолейНабораДанныхСхемыКомпоновкиДанных.
Выясним нюансы этого метода. Если вы помещаете поле в папку набора данных, его ПутьКДанным должен отражать эту вложенность. Рассмотрим пример:
ИмяПапки = "ДанныеПродаж";
Папка = СхемаКомпоновкиДанных.НаборыДанных.НаборДанных1.Поля.Добавить(Тип("ПапкаПолейНабораДанныхСхемыКомпоновкиДанных"));
Папка.Заголовок = "Продажи за период";
Папка.ПутьКДанным = ИмяПапки;
// Добавляем поле внутрь
Поле = СхемаКомпоновкиДанных.НаборыДанных.НаборДанных1.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
Поле.Заголовок = "Сумма выручки";
// Путь должен включать имя папки через точку!
Поле.ПутьКДанным = ИмяПапки + ".Сумма";
Поле.Поле = "Сумма";
Важное замечание: При использовании этого метода необходимо следить за тем, чтобы выражения ресурсов (итогов) также использовали правильные пути к данным. Если путь изменился на ДанныеПродаж.Сумма, то и в поле итога нужно прописывать именно его.
Разберем ситуацию, когда наши динамические колонки должны суммироваться. Поскольку поля создаются программно, ресурсы для них тоже нужно создавать кодом. Если мы забудем это сделать, в группировках и итогах по колонкам будет пустота.
Посмотрим на пример добавления ресурса:
ПолеРесурса = СхемаКомпоновкиДанных.ПоляИтога.Добавить();
ПолеРесурса.ПутьКДанным = ИмяКолонки; // Должно совпадать с ПутьКДанным поля набора
ПолеРесурса.Выражение = "Сумма(" + ИмяКолонки + ")";
Обратите внимание, что для некоторых показателей (например, "Себестоимость" или "Цена") логичнее использовать выражение "Среднее(" + ИмяКолонки + ")" или "Максимум(...)".
Проанализируем типичную ошибку: при каждом нажатии кнопки «Сформировать» колонки добавляются снова и снова, дублируя друг друга. Чтобы избежать этого, перед выполнением цикла добавления полей всегда нужно очищать текущие настройки. Рассмотрим, как это сделать правильно:
// Очищаем выбранные поля, чтобы не было дублей при повторном формировании
КомпоновщикНастроек.Настройки.Выбор.Элементы.Очистить();
// Также стоит проверить, не нужно ли очистить ресурсы в самой схеме,
// если схема создается/модифицируется динамически
СхемаКомпоновкиДанных.ПоляИтога.Очистить();
СхемаКомпоновкиДанных.НаборыДанных.НаборДанных1.Поля.Очистить();
Выясним, что делать, если отчет строится не в виде простого списка, а в виде таблицы СКД (с группировками строк и колонок). В этом случае добавление полей в Настройки.Выбор может не дать результата, так как таблица управляет выбранными полями на уровне своих группировок.
В такой ситуации нам потребуется найти нужную группировку в структуре настроек:
// Ищем группировку колонок в таблице
ГруппировкаКолонок = НастройкиСКД.Структура[0].Колонки[0]; // Примерный путь
// Добавляем группу полей именно в выбор этой группировки
ГруппаПолей = ГруппировкаКолонок.Выбор.Элементы.Добавить(Тип("ГруппаВыбранныхПолейКомпоновкиДанных"));
Мы рассмотрели механизмы программного управления структурой колонок в СКД. Ключевым моментом для создания объединенных шапок является использование объекта ГруппаВыбранныхПолейКомпоновкиДанных с обязательной установкой свойства Расположение. Сочетая это с динамическим созданием полей набора данных и ресурсов, можно создавать отчеты любой сложности, которые будут выглядеть аккуратно и понятно для конечного пользователя. Помните о необходимости корректного указания путей к данным и очистке коллекций перед модификацией, чтобы избежать ошибок дублирования.