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