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