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