В разработке отчетов на системе компоновки данных (СКД) часто возникает задача сузить возможности пользователя по выбору периода. Стандартный тип СтандартныйПериод предоставляет огромную свободу: от выбора одного дня до нескольких лет. Однако для аналитических отчетов или тяжелых выборок данных часто требуется жесткое ограничение — например, формирование данных строго за один календарный месяц. Рассмотрим несколько эффективных способов реализации этой задачи, начиная от простых настроек интерфейса и заканчивая программным перехватом событий компоновки.
Проанализируем наиболее элегантный метод, который позволяет избежать написания сложного кода и делает интерфейс максимально понятным для пользователя. Вместо использования стандартного периода мы предложим пользователю выбрать конкретный месяц.
Для реализации этого метода выполним следующие шаги в конфигураторе:
ВыбранныйМесяц. Установим для него тип Дата.ДФ='MMMM yyyy'. Это заставит стандартный календарь 1С отображать только список месяцев и лет.ДатаНачала и ДатаОкончания.ДатаНачала пропишем: НачалоПериода(&ВыбранныйМесяц, "Месяц").ДатаОкончания пропишем: КонецПериода(&ВыбранныйМесяц, "Месяц").Таким образом, мы получаем удобный интерфейс выбора одного месяца, а система автоматически вычисляет его границы для корректной работы запроса.
Разберем ситуацию, когда нам необходимо использовать именно СтандартныйПериод, но при этом программно контролировать, что выбрал пользователь. Если штатные средства платформы не позволяют ограничить выбор в самом диалоге, мы можем создать собственную форму отчета и перехватить ввод данных.
Выясним, как это реализовать. На форме отчета создадим команду и кнопку, которая будет вызывать диалог редактирования периода. Рассмотрим пример кода, который принудительно устанавливает границы начала и конца месяца:
&НаКлиенте
Процедура НастроитьПериод(Команда)
Диалог = Новый ДиалогРедактированияСтандартногоПериода;
// Предварительно заполняем даты из текущих настроек
Диалог.Период.ДатаНачала = НачалоМесяца(ДатаНач);
Диалог.Период.ДатаОкончания = КонецМесяца(ДатаНач);
ОписаниеОповещения = Новый ОписаниеОповещения("НастройкаПериодаЗавершение", ЭтотОбъект);
Диалог.Показать(ОписаниеОповещения);
КонецПроцедуры
&НаКлиенте
Процедура НастройкаПериодаЗавершение(Результат, Параметры) Экспорт
Если Результат <> Неопределено Тогда
// Принудительно приводим выбранные даты к границам месяца
ДатаНач = НачалоМесяца(Результат.ДатаНачала);
ДатаКон = КонецМесяца(Результат.ДатаНачала);
// Обновляем параметры в компоновщике настроек
ОбновитьПараметрыСКД(ДатаНач, ДатаКон);
КонецЕсли;
КонецПроцедуры
В этом примере, даже если пользователь выберет произвольный интервал в диалоге, процедура завершения «подправит» его выбор, установив границы полного месяца, соответствующего дате начала. Далее нам нужно обновить значения в КомпоновщикНастроек:
&НаКлиенте
Процедура ОбновитьПараметрыСКД(Начало, Конец)
ПараметрДатаНач = Отчет.КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("ДатаНачала");
Если ПараметрДатаНач <> Неопределено Тогда
ПараметрДатаНач.Значение = Начало;
ПараметрДатаНач.Использование = Истина;
КонецЕсли;
ПараметрДатаКон = Отчет.КомпоновщикНастроек.Настройки.ParemetriДанных.Элементы.Найти("ДатаОкончания");
Если ПараметрДатаКон <> Неопределено Тогда
ПараметрДатаКон.Значение = Конец;
ПараметрДатаКон.Использование = Истина;
КонецЕсли;
КонецПроцедуры
Посмотрим на ситуацию с другой стороны. Что если мы не хотим создавать форму отчета, а желаем оставить стандартный интерфейс? В этом случае мы можем использовать модуль объекта отчета и процедуру ПриКомпоновкеРезультата. Этот метод позволяет проверить настройки пользователя непосредственно перед выполнением отчета.
Проанализируем следующий алгоритм действий:
ПриКомпоновкеРезультата в модуле объекта.
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Получаем значение периода из настроек компоновщика
ЗначениеПараметра = КомпоновщикНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Период"));
Если ЗначениеПараметра <> Неопределено И ЗначениеПараметра.Использование Тогда
ВыбранныйПериод = ЗначениеПараметра.Значение; // Тип СтандартныйПериод
// Проверяем, что дата начала и окончания принадлежат одному месяцу
Если НачалоМесяца(ВыбранныйПериод.ДатаНачала) <> НачалоМесяца(ВыбранныйПериод.ДатаОкончания) Тогда
// Вариант 1: Принудительная корректировка
ВыбранныйПериод.ДатаОкончания = КонецМесяца(ВыбранныйПериод.ДатаНачала);
ЗначениеПараметра.Значение = ВыбранныйПериод;
// Вариант 2: Отказ в формировании (раскомментировать при необходимости)
// Сообщение = Новый СообщениеПользователю;
// Сообщение.Текст = "Выбор периода более одного месяца запрещен!";
// Сообщение.Сообщить();
// СтандартнаяОбработка = Ложь;
// Возврат;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот способ хорош тем, что он работает всегда, независимо от того, через какую форму (стандартную или пользовательскую) был вызван отчет. Мы гарантируем целостность данных на уровне бизнес-логики самого отчета.
Если количество периодов, доступных пользователю, невелико (например, только месяцы текущего года), мы можем заполнить список Доступные значения для параметра типа СтандартныйПериод. Это можно сделать в конфигураторе на закладке параметров СКД. Вместо произвольного выбора дат пользователь увидит выпадающий список с заранее подготовленными элементами (Январь 2023, Февраль 2023 и т.д.). Это полностью исключает возможность выбора некорректного периода.
Рассмотрим еще один интересный подход. Мы можем оставить стандартный выбор периода для пользователя в интерфейсе, но полностью игнорировать его вторую дату (дату окончания) в самом запросе. В выражениях параметров СКД можно указать, что отчет всегда строится от НачалоПериода(&Период.ДатаНачала, "Месяц") до КонецПериода(&Период.ДатаНачала, "Месяц"). В этом случае, даже если пользователь случайно выберет год, отчет сформируется только за первый месяц этого года, что обеспечит высокую производительность и соблюдение логики «одного месяца».
Подведем итог: выбор метода зависит от ваших требований к интерфейсу. Для максимального удобства лучше использовать Способ 1 (выбор одной даты с форматом месяца). Для строгого контроля без изменения интерфейса идеально подойдет Способ 3 (перехват в модуле объекта).