При работе с отчетами, построенными на Системе Компоновки Данных (СКД) в 1С:Предприятии, часто возникает необходимость в динамическом изменении заголовков колонок. Например, требуется, чтобы заголовок расчетной колонки отражал выбранный период отчета, такой как месяц окончания периода. В этой статье мы подробно разберем, как реализовать такую функциональность в управляемых формах (УТ 11, ERP) с помощью программного подхода, а также рассмотрим другие методы и проанализируем распространенные ошибки. Для удобной настройки интерактивного выбора месяца в качестве периода отчета можно использовать готовое решение для выбора месяца в СКД.
Наиболее гибким и рекомендуемым способом для динамического изменения заголовков колонок в СКД является использование обработчика события ПриКомпоновкеДанных. Этот обработчик выполняется на этапе формирования макета компоновки данных, до того как начнется вывод самого отчета. Это позволяет нам внести изменения в структуру и настройки отчета, которые будут учтены при его последующей генерации.
Рассмотрим по шагам, как это сделать:
Определимся с местом размещения кода. Наш код необходимо разместить в модуле объекта отчета, в обработчике события ПриКомпоновкеДанных. Если обработчик еще не создан, мы создадим его.
Для этого в конфигураторе откроем отчет, перейдем на вкладку "Прочее", выберем "Модуль объекта", и найдем или создадим процедуру ПриКомпоновкеДанных.
Получим доступ к настройкам компоновщика. Внутри обработчика ПриКомпоновкеДанных нам доступен объект КомпоновщикНастроек, который содержит все текущие настройки отчета, заданные пользователем или по умолчанию.
Процедура ПриКомпоновкеДанных(КомпоновщикМакета, НастройкиКомпоновкиДанных, ДанныеРасшифровки, СтандартнаяОбработка)
// Доступ к текущим настройкам отчета
Настройки = КомпоновщикНастроек.Настройки;
// ... дальнейшая логика
КонецПроцедуры
Обратите внимание, что объект НастройкиКомпоновкиДанных, переданный как параметр, также содержит настройки, но КомпоновщикНастроек.Настройки является более универсальным способом получить доступ к полным настройкам компоновщика, включая параметры.
Получим значение параметра, влияющего на заголовок. В нашем случае это дата окончания периода отчета. Параметры могут быть получены из коллекции Настройки.ПараметрыДанных.Элементы.
ДатаОкончанияПериода = Неопределено;
Для Каждого ЭлементПараметра Из Настройки.ПараметрыДанных.Элементы Цикл
Если ЭлементПараметра.Параметр.Имя = "ПериодОтчетаКонец" Тогда // Или другое имя вашего параметра даты окончания
ДатаОкончанияПериода = ЭлементПараметра.Значение;
Прервать;
КонецЕсли;
КонецЦикла;
Если ДатаОкончанияПериода = Неопределено Тогда
Возврат; // Или установить значение по умолчанию / вывести ошибку
КонецЕсли;
Мы используем цикл для перебора параметров, так как их порядок может меняться. Важно использовать точное имя параметра, заданное в схеме компоновки данных.
Сформируем новый заголовок. Используя полученную дату, мы можем сформировать динамическую строку для заголовка. Например, нам нужен месяц окончания периода.
НовыйЗаголовок = "Отгрузка за " + Формат(ДатаОкончанияПериода, "ДФ=MMMM ГГГГ");
Функция Формат() позволяет гибко форматировать дату в нужное нам представление (например, "Январь 2023").
Найдем вычисляемое поле и изменим его заголовок. Расчетная колонка (вычисляемое поле) должна быть включена в выбранные поля отчета. Мы должны найти этот элемент в коллекции Настройки.ВыбранныеПоля.Элементы и изменить его свойство Заголовок.
Для Каждого ВыбранноеПоле Из Настройки.ВыбранныеПоля.Элементы Цикл
// Ищем наше вычисляемое поле по его имени (Поле.Имя) или представлению
// Имя поля должно точно соответствовать имени вычисляемого поля в СКД
Если ВыбранноеПоле.Поле = "ОтгрузкаПоследнегоМесяца" Тогда
ВыбранноеПоле.Заголовок = НовыйЗаголовок;
Прервать; // Найдено, можно выйти из цикла
КонецЕсли;
КонецЦикла;
Если ваша расчетная колонка является частью группировки, возможно, потребуется искать ее в Настройки.Группировки.Элементы, а затем в ПоляГруппировки или ВыбранныеПоля внутри этой группировки. В большинстве случаев достаточно поиска по ВыбранныеПоля.
Полный пример кода для обработчика ПриКомпоновкеДанных:
Процедура ПриКомпоновкеДанных(КомпоновщикМакета, НастройкиКомпоновкиДанных, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Истина; // Обычно оставляем стандартную обработку
Настройки = КомпоновщикНастроек.Настройки;
// 1. Получаем значение параметра даты окончания периода
ДатаОкончанияПериода = Неопределено;
Для Каждого ЭлементПараметра Из Настройки.ПараметрыДанных.Элементы Цикл
Если ЭлементПараметра.Параметр.Имя = "ПериодОтчетаКонец" Тогда // Предполагаем, что у вас есть параметр с таким именем
ДатаОкончанияПериода = ЭлементПараметра.Значение;
Прервать;
КонецЕсли;
КонецЦикла;
Если ДатаОкончанияПериода = Неопределено Тогда
// Если параметр не установлен, используем текущую дату или дату по умолчанию
ДатаОкончанияПериода = КонецМесяца(ТекущаяДата());
КонецЕсли;
// 2. Формируем новый заголовок
// Пример: "Отгрузка за Январь 2023"
НовыйЗаголовок = "Отгрузка за " + Формат(ДатаОкончанияПериода, "ДФ=MMMM ГГГГ");
// 3. Находим вычисляемое поле и изменяем его заголовок
// Предполагаем, что имя вашего вычисляемого поля в СКД - "ОтгрузкаПоследнегоМесяца"
Для Каждого ВыбранноеПоле Из Настройки.ВыбранныеПоля.Элементы Цикл
Если ВыбранноеПоле.Поле = "ОтгрузкаПоследнегоМесяца" Тогда
ВыбранноеПоле.Заголовок = НовыйЗаголовок;
// Можно также изменить Представление, если требуется для других целей
// ВыбранноеПоле.Представление = НовыйЗаголовок;
Прервать;
КонецЕсли;
КонецЦикла;
// Если поле может быть в группировке (например, в детальных записях или в заголовке группировки)
// Проверяем группировки отчета
Для Каждого ЭлементГруппировки Из Настройки.Группировки.Элементы Цикл
// Проверяем выбранные поля внутри каждой группировки
Для Каждого ВыбранноеПолеГруппировки Из ЭлементГруппировки.ВыбранныеПоля.Элементы Цикл
Если ВыбранноеПолеГруппировки.Поле = "ОтгрузкаПоследнегоМесяца" Тогда
ВыбранноеПолеГруппировки.Заголовок = НовыйЗаголовок;
Прервать;
КонецЕсли;
КонецЦикла;
// Если поле используется как поле группировки
Если ЭлементГруппировки.Поле = "ОтгрузкаПоследнегоМесяца" Тогда
ЭлементГруппировки.Заголовок = НовыйЗаголовок;
КонецЕсли;
КонецЦикла;
// Также можно проверить другие коллекции, например, Поля
Для Каждого ПолеСКД Из НастройкиКомпоновкиДанных.Поля Цикл
Если ПолеСКД.Поле = "ОтгрузкаПоследнегоМесяца" Тогда
ПолеСКД.Заголовок = НовыйЗаголовок;
Прервать;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Преимущества данного подхода:
Макеты СКД также могут быть использованы для управления заголовками, но их применение для динамического изменения заголовка вычисляемого поля на основе внешнего параметра (как дата отчета) менее прямолинейно и универсально по сравнению с программным методом в ПриКомпоновкеДанных. При необходимости можно воспользоваться примером разработки собственных макетов компоновки данных на примере УТ 11.5.
Когда макеты могут быть полезны:
В контексте задачи "месяц окончания периода отчета в заголовке расчетной колонки", использование макетов напрямую для заголовка вычисляемого поля будет менее эффективным, поскольку они не могут напрямую получить и отформатировать параметр отчета. Однако, если мы хотим использовать макет для оформления, а динамический текст вставлять программно, это возможно, но усложняет решение без явных преимуществ.
Автор в сообщении 7 пытался изменить заголовок, используя ручную компоновку данных в обработчике ПриКомпоновкеРезультата. Давайте проанализируем ситуацию и выясним причину возникновения "пустого отчета".
Суть проблемы:
Обработчик события ПриКомпоновкеРезультата предназначен для работы с уже сгенерированным результатом компоновки данных, который представлен в виде ТабличногоДокумента или через ПроцессорВыводаРезультатаКомпоновкиДанных. Это событие возникает, когда отчет уже почти сформирован и готов к выводу. Его основная цель — пост-обработка или корректировка оформления уже сформированных ячеек, строк или колонок, но не изменение базовой структуры или данных отчета.
Код, приведенный автором:
СтандартнаяОбработка = Ложь;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(
ЭтотОбъект.СхемаКомпоновкиДанных,
ЭтотОбъект.КомпоновщикНастроек.Настройки,
ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Ячейка = ДокументРезультат.НайтиТекст("ОтгрузкаПоследнегоМесяца");
Если Ячейка <> Неопределено Тогда
Ячейка.Текст = НовыйЗаголовок;
КонецЕсли;
Пошаговый анализ ошибки:
СтандартнаяОбработка = Ложь;
Отключение стандартной обработки означает, что платформа не будет самостоятельно формировать отчет. Всю работу по компоновке и выводу берет на себя наш код.
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(...);
Здесь мы создаем новый экземпляр КомпоновщикаМакетаКомпоновкиДанных и вручную запускаем процесс формирования макета. Критическая проблема заключается в том, что в качестве второго параметра (настройки компоновки) передается ЭтотОбъект.КомпоновщикНастроек.Настройки. Как справедливо отмечено в сообщении 10, на момент вызова ПриКомпоновкеРезультата, если отчет не был скомпонован стандартным образом, или если параметры не были корректно инициализированы в КомпоновщикНастроек, эти настройки могут быть пустыми или содержать неполную информацию.
Когда мы вручную вызываем Выполнить(), мы начинаем процесс компоновки с нуля. Если настройки (включая параметры отчета, такие как период) не были переданы или были пусты, то СКД формирует макет, который не содержит данных, потому что не знает, какие данные выбирать.
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(...);
Далее мы создаем новый ПроцессорКомпоновкиДанных и инициализируем его. Это еще один шаг ручной компоновки, который будет использовать макет, сформированный на предыдущем шаге. Если макет был сформирован с пустыми настройками, процессор также не сможет получить данные.
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.Вывести(...);
Затем мы выводим результат. Если данные не были получены на предыдущих шагах, то и выводить нечего, и отчет получается пустым.
Ячейка = ДокументРезультат.НайтиТекст("ОтгрузкаПоследнегоМесяца");
Если Ячейка <> Неопределено Тогда Ячейка.Текст = НовыйЗаголовок; КонецЕсли;
Эта часть кода сама по себе корректна для поиска и изменения текста в уже сформированном табличном документе. Проблема в том, что к этому моменту ДокументРезультат уже пуст или не содержит искомого текста, поскольку весь отчет был сформирован некорректно.
Таким образом, основная причина "пустого отчета" заключается в том, что, отключая стандартную обработку и пытаясь вручную перекомпоновать отчет в ПриКомпоновкеРезультата, автор не передал или не смог получить все необходимые актуальные настройки и параметры для успешной генерации данных.
Когда использовать ПриКомпоновкеРезультата?
Этот обработчик следует использовать для:
Для изменения структуры отчета, таких как заголовки колонок, влияющих на сбор данных, всегда предпочтительнее использовать ПриКомпоновкеДанных.
В ходе нашего анализа мы выяснили, что наиболее эффективным и надежным способом динамического изменения заголовка расчетной колонки в отчете СКД, основанном на параметрах отчета (например, периоде), является программное изменение свойств поля в коллекции ВыбранныеПоля или ПоляГруппировки внутри обработчика события ПриКомпоновкеДанных.
Этот подход гарантирует, что изменения будут учтены на этапе формирования макета компоновки данных, что обеспечивает универсальность и корректность отображения отчета. Мы также разобрали распространенную ошибку, связанную с попыткой ручной перекомпоновки отчета в ПриКомпоновкеРезультата, и объяснили, почему такой подход приводит к нежелательным результатам, таким как пустой отчет.
Всегда помните, что ПриКомпоновкеДанных предназначен для настройки того, *как* данные будут скомпонованы, а ПриКомпоновкеРезультата — для *пост-обработки* уже скомпонованного и выведенного результата.