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