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