При сопровождении типовых программных продуктов на платформе 1С:Предприятие 8.3 разработчики часто сталкиваются с задачей кастомизации стандартных отчетов. При этом критически важно сохранить конфигурацию на полной поддержке поставщика, чтобы избежать сложностей при регулярных обновлениях. Модификация кода типового отчета напрямую в основной конфигурации приведет к тому, что при очередном обновлении ваши изменения могут быть затерты или потребуют сложного ручного объединения.
В данной статье мы подробно разберем профессиональные методы решения этой задачи на примере управляемых форм и Системы компоновки данных (СКД). Мы рассмотрим, как перехватывать процесс формирования отчета, программно добавлять строки с данными и использовать возможности расширений и Библиотеки стандартных подсистем (БСП).
Самым гибким, современным и технологичным способом является использование расширений конфигурации. Этот механизм позволяет внедриться в логику работы отчета на этапе его выполнения, не затрагивая сам объект в основной конфигурации.
Для реализации этого метода нам необходимо заимствовать модуль объекта отчета в наше расширение и перехватить стандартное событие ПриКомпоновкеРезультата. Выясним, как это сделать по шагам:
ПриКомпоновкеРезультата с аннотацией &После или &Вместо.Проанализируем пример кода с использованием аннотации &После. В данном сценарии система сначала выполнит стандартный вывод отчета, сформирует макет и выведет его в ДокументРезультат (который является табличным документом на форме). После этого управление передается нашему коду в расширении, где мы программно дописываем нужные строки данных в конец таблицы:
&После("ПриКомпоновкеРезультата")
Процедура Расш_ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Проверим, что отчет действительно сформирован и табличный документ не пустой
Если ДокументРезультат.ВысотаТаблицы = 0 Тогда
Возврат;
КонецЕсли;
// Определяем позицию для вставки. Будем выводить данные в самый конец документа
НомерНовойСтроки = ДокументРезультат.ВысотаТаблицы + 1;
// Пример добавления строки-разделителя
ОбластьСтроки = ДокументРезультат.Область(НомерНовойСтроки, 1, НомерНовойСтроки, 5); // Диапазон колонок с 1 по 5
ОбластьСтроки.Объединить();
ОбластьСтроки.Текст = "--- Дополнительные аналитические данные (сформировано программно) ---";
ОбластьСтроки.Шрифт = Новый Шрифт(ОбластьСтроки.Шрифт, , , Истина, Ложь, Ложь); // Делаем текст жирным
ОбластьСтроки.ЦветТекста = WebЦвета.Синий;
// Переходим к выводу конкретных строк с данными
НомерНовойСтроки = НомерНовойСтроки + 1;
// Заполняем ячейку с наименованием показателя
ЯчейкаПоказатель = ДокументРезультат.Область(НомерНовойСтроки, 1);
ЯчейкаПоказатель.Текст = "Дополнительный показатель эффективности:";
// Заполняем ячейку со значением показателя
ЯчейкаЗначение = ДокументРезультат.Область(НомерНовойСтроки, 2);
ЯчейкаЗначение.Текст = "145.82%";
ЯчейкаЗначение.ГоризонтальноеПоложение = ГоризонтальноеПоложение.Право;
// При необходимости можно задать рамки для новых ячеек
ОбластьДанных = ДокументРезультат.Область(НомерНовойСтроки, 1, НомерНовойСтроки, 2);
ОбластьДанных.Обвести(Новый Линия(ТипЛинииСеткиТабличногоДокумента.Сплошная, 1));
КонецПроцедуры
Если нам необходимо не просто дописать строки в самый конец табличного документа, а встроить их непосредственно в структуру отчета (например, между группировками) или передать в компоновщик свои внешние наборы данных, то использование аннотации &После не подойдет. В этом случае мы должны полностью взять управление выводом в свои руки. Для этого используется аннотация &Вместо.
Рассмотрим подробнее шаблон кода, который отключает стандартный вывод платформы и выполняет компоновку вручную:
&Вместо("ПриКомпоновкеРезультата")
Процедура Расш_ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Отключаем стандартный вывод отчета платформой
СтандартнаяОбработка = Ложь;
// Очищаем результирующий табличный документ перед формированием
ДокументРезультат.Очистить();
// Получаем настройки отчета
НастройкиОтчета = КомпоновщикНастроек.ПолучитьНастройки();
// Выполняем компоновку макета
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиОтчета, ДанныеРасшифровки);
// Инициализируем процессор компоновки данных.
// Если используются внешние наборы данных, передаем их вторым параметром
ВнешниеНаборыДанных = Новый Структура;
// Пример: ВнешниеНаборыДанных.Вставить("ДополнительнаяТаблица", ПолучитьТаблицуДополнительныхДанных());
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, Истина);
// Выводим результат в табличный документ
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
// Начинаем вывод
ПроцессорВывода.НачатьВывод();
Пока Истина Цикл
ЭлементРезультата = ПроцессорКомпоновки.Следующий();
Если ЭлементРезультата = Неопределено Тогда
Прервать;
КонецЕсли;
// Выводим стандартный элемент отчета
ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
// Здесь мы можем проанализировать, какой именно элемент выводится.
// Например, если вывелась определенная группировка, мы можем программно встроить свою строку
Если ЭлементРезультата.ЗначенияПараметров.Свойство("ИмяГруппировки")
И ЭлементРезультата.ЗначенияПараметров.ИмяГруппировки.Значение = "Номенклатура" Тогда
// Программный вывод кастомной строки в процессе генерации отчета
// (Реализуется через вывод областей макета или прямое добавление строк)
КонецЕсли;
КонецЦикла;
ПроцессорВывода.ЗакончитьВывод();
КонецПроцедуры
Этот способ более трудоемок, но он предоставляет разработчику абсолютный контроль над структурой, областями и ячейками выводимого отчета.
Иногда логику удобнее привязать не к модулю объекта отчета, а непосредственно к его форме (например, если у отчета есть уникальная форма и нам нужно модифицировать табличное поле формы сразу после того, как пользователь нажал кнопку Сформировать).
Для этого выполним следующие действия:
Результат и типом ТабличныйДокумент).Посмотрим на пример перехвата события окончания формирования отчета на форме. Во многих типовых конфигурациях на БСП используется процедура ПослеЗаполненияПанелиОтчетов или специализированные обработчики компоновки на клиенте/сервере. Если мы заимствуем форму, мы можем привязаться к процедуре, которая вызывается после завершения формирования табличного документа:
&После("ПослеЗаполненияПанелиОтчетов")
Процедура Расш_ПослеЗаполненияПанелиОтчетов()
// Получаем доступ к табличному документу формы напрямую
ТабДок = Элементы.Результат;
Если ТабДок.ВысотаТаблицы > 0 Тогда
// Выполняем постобработку ячеек формы
Для ТекущаяСтрока = 1 По ТабДок.ВысотаТаблицы Цикл
ОбластьЯчейки = ТабДок.Область(ТекущаяСтрока, 1);
// Если находим нужный маркер в ячейке, модифицируем соседние данные
Если ОбластьЯчейки.Текст = "Итого по разделу" Тогда
// Добавим подстроку или изменим оформление
ТабДок.Область(ТекущаяСтрока, 2).Текст = "Данные скорректированы расширением";
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Если по каким-то причинам использование расширений конфигурации в вашей компании ограничено политиками безопасности или техническими регламентами, существует классический и крайне надежный способ с использованием механизмов БСП (Библиотеки стандартных подсистем).
Разберем данный алгоритм по шагам:
.erf (через меню Файл -> Сохранить как...).ОБЪЕДИНИТЬ ВСЕ, чтобы подмешать свои виртуальные строки данных, или дописать логику в модуль объекта.Результат: Для конечных пользователей ничего не меняется. Они заходят в свои привычные разделы интерфейса, нажимают стандартные кнопки вызова отчета, но система под капотом незаметно для них открывает и формирует модифицированный внешний отчет. При этом конфигурация базы данных остается полностью типовой и обновляется в автоматическом режиме без конфликтов.
Мы проанализировали различные подходы к решению задачи изменения отчета без изменения самой конфигурации. Выбор конкретного метода зависит от архитектуры вашего решения:
ПриКомпоновкеРезультата.