При разработке отчетов на базе Системы компоновки данных (СКД) начинающие разработчики часто сталкиваются с ситуацией, когда добавленные в схему параметры (например, период или дата) игнорируются системой при формировании результата. Особенно остро эта проблема проявляется, если данные для отчета готовятся не простым запросом внутри схемы, а программно в модуле объекта (через внешний набор данных). Разберем по шагам, почему это происходит и как правильно связать пользовательские настройки с вашим кодом.
Проанализируем типичную ситуацию: вы создали внешний отчет, добавили в схему компоновки (СКД) внешний набор данных с именем ПримерТаблицыЗначений. В параметрах схемы вы определили НачалоПериода и КонецПериода. Однако, когда пользователь выбирает даты на форме и нажимает «Сформировать», отчет либо выводит пустую таблицу, либо, наоборот, вываливает абсолютно все документы без фильтрации.
Выясним причину: когда вы используете внешний набор данных, СКД не управляет получением данных из базы напрямую. Она лишь ожидает, что вы передадите ей уже готовую Таблицу Значений (ТЗ). Если в коде формирования этой ТЗ вы не предусмотрели фильтрацию по датам, то СКД получит полный массив данных. Даже если в настройках самой СКД стоят отборы, они сработают уже после того, как вся таблица будет загружена в память, что крайне неэффективно и часто приводит к ошибкам «Поле не найдено».
Для начала рассмотрим, как правильно подготовить саму схему. Перейдем на закладку «Параметры» в конструкторе СКД. Нам понадобятся три элемента:
Период — тип СтандартныйПериод. Именно его мы выведем пользователю на форму для удобного выбора (например, «Текущий месяц»).НачалоПериода — тип Дата. В поле «Выражение» укажем &Период.ДатаНачала. Ограничим его использование, установив галочку «Ограничение доступности».КонецПериода — тип Дата. В поле «Выражение» укажем &Период.ДатаОкончания. Также установим «Ограничение доступности».Таким образом, пользователь взаимодействует с одним полем, а система автоматически заполняет две переменные даты, которые мы будем использовать в коде.
Теперь перейдем в модуль объекта отчета. Основная работа происходит в предопределенной процедуре ПриКомпоновкеРезультата. Рассмотрим подробнее, как получить значения, которые ввел пользователь. Мы не можем просто обратиться к переменным НачалоПериода, так как они живут внутри объекта КомпоновщикНастроек.
Проанализируем пример кода для получения дат из настроек:
// В начале процедуры всегда отключаем стандартную обработку
СтандартнаяОбработка = Ложь;
// Получаем текущие настройки пользователя
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
// Ищем параметр "Период" в настройках
ПараметрПериод = Настройки.ПараметрыДанных.Элементы.Найти("Период");
Если ПараметрПериод <> Неопределено И ПараметрПериод.Использование Тогда
ДатаНачала = ПараметрПериод.Значение.ДатаНачала;
// Важно использовать КонецДня для корректного захвата документов последней секунды
ДатаОкончания = КонецДня(ПараметрПериод.Значение.ДатаОкончания);
Иначе
// Установим значения по умолчанию, если пользователь ничего не выбрал
ДатаНачала = '00010101';
ДатаОкончания = ТекущаяДата();
КонецЕсли;
Посмотрим на пример ситуации, когда мы формируем таблицу значений для передачи в СКД. Теперь, когда у нас есть переменные ДатаНачала и ДатаОкончания, мы обязаны подставить их в текст запроса, который собирает данные.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продажи.Ссылка КАК Документ,
| Продажи.Дата КАК Дата,
| Продажи.СуммаДокумента КАК Сумма
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Продажи
|ГДЕ
| Продажи.Дата МЕЖДУ &Начало И &Конец";
Запрос.УстановитьПараметр("Начало", ДатаНачала);
Запрос.УстановитьПараметр("Конец", ДатаОкончания);
ТаблицаДляСКД = Запрос.Выполнить().Выгрузить();
Обратите внимание: если вы пропустите секцию ГДЕ в программном запросе, ваш отчет всегда будет выводить все данные, сколько бы фильтров вы ни ставили в настройках самого отчета на форме. Это и была главная ошибка в обсуждаемой теме форума.
Завершающим этапом является передача подготовленной таблицы в процессор компоновки. Разберем по шагам, как правильно инициализировать все объекты, чтобы внешние данные «подружились» с макетом.
// 1. Получаем макет компоновки
СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
// 2. Создаем макет компоновки с учетом пользовательских настроек
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
// 3. Создаем структуру для внешнего набора данных
// Имя ключа должно СТРОГО совпадать с именем Внешнего набора данных в схеме СКД
ВнешниеДанные = Новый Структура;
ВнешниеДанные.Вставить("ПримерТаблицыЗначений", ТаблицаДляСКД);
// 4. Инициализируем процессор компоновки
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеДанные, ДанныеРасшифровки);
// 5. Выводим результат в табличный документ
ДокументРезультат.Очистить();
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Рассмотрим несколько моментов, которые часто упускают из виду:
Дата, так как они могут конфликтовать с системными полями. Используйте ДатаНачалаОтчета или НачалоПериода.ДатаОкончания будет равна 01.09.2023 00:00:00. Если документ был создан в 10 утра, он не попадет в выборку МЕЖДУ. Поэтому всегда используйте функцию КонецДня().ПриКомпоновкеРезультата, платформа попытается сформировать отчет сама, не обнаружит данных в схеме (так как они приходят извне) и выдаст пустой результат или ошибку.Настройки.ПараметрыДанных может не сработать. В таких случаях надежнее проверять КомпоновщикНастроек.ПользовательскиеНастройки.Элементы.Подводя итог, можно сказать: секрет успешного отбора по дате во внешнем наборе данных СКД заключается в дублировании логики. Параметры нужны в СКД для интерфейса (формы), но эти же значения должны быть вручную переданы в ваш программный запрос Запрос.УстановитьПараметр(). Только тогда база данных вернет отфильтрованную выборку, которую СКД корректно отобразит пользователю.