Как передать значение отбора СКД в параметр данных в 1С?

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

При разработке отчетов на Системе компоновки данных (СКД) часто возникает ситуация, когда глобальный отбор отчета искажает итоговые данные. Например, если в запросе используется левое соединение справочника с таблицей продаж, то при наложении стандартного отбора по полю связанной таблицы СКД автоматически превращает соединение во внутреннее. В результате из отчета выпадают элементы справочника, по которым не было продаж за выбранный период.

Чтобы избежать этой проблемы и сохранить корректные расчеты, отбор пользователя можно перенаправить в параметр данных или виртуальную таблицу запроса. Разберем по шагам, как получить значение отбора, заданного пользователем, и передать его в параметр СКД.

Причина поведения СКД и вариант решения через модуль отчета

Выясним причину проблемы: когда пользователь устанавливает отбор на уровне отчета, этот отбор накладывается на весь итоговый результат компоновки. Если нам нужно, чтобы базовые данные выводились всегда, а фильтрация касалась только конкретного источника данных (например, виртуальной таблицы продаж), условие должно передаваться напрямую в параметр этого источника.

Для реализации этой логики используется процедура ПриКомпоновкеРезультата в модуле объекта отчета. В ней мы можем перехватить настройки компоновки до выполнения запроса, найти нужный элемент отбора и записать его значение в параметр данных.

Способ 1. Получение результирующих настроек компоновщика

Пользователи обычно задают условия в пользовательских настройках на форме отчета. Если обращаться напрямую к коллекции КомпоновщикНастроек.Настройки.Отбор, внесенные на форме изменения могут не отобразиться. Чтобы получить актуальное состояние с учетом введенных пользователем данных, необходимо вызвать метод ПолучитьНастройки().

Рассмотрим пример кода в процедуре ПриКомпоновкеРезультата:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ИмеющиесяДанные, СтандартнаяОбработка)
	
	// Получаем результирующие настройки с учетом пользовательских изменений
	Настройки = КомпоновщикНастроек.ПолучитьНастройки();
	
	ЗначениеОтбора = Неопределено;
	ИспользованиеОтбора = Ложь;
	
	// Ищем элемент отбора по нужному полю
	ПолеОтбора = Новый ПолеКомпоновкиДанных("Производитель");
	
	Для Каждого ЭлементИзКоллекции Из Настройки.Отбор.Элементы Цикл
		Если ТипЗнч(ЭлементИзКоллекции) = Тип("ЭлементОтбораКомпоновкиДанных") Тогда
			Если ЭлементИзКоллекции.ЛевоеЗначение = ПолеОтбора Тогда
				ЗначениеОтбора = ЭлементИзКоллекции.ПравоеЗначение;
				ИспользованиеОтбора = ЭлементИзКоллекции.Использование;
				Прервать;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	// Если отбор найден и включен, передаем его в параметр данных
	Если ИспользованиеОтбора И ЗначениеОтбора <> Неопределено Тогда
		Параметр = Настройки.ПараметрыДанных.Элементы.Найти("ПараметрПроизводитель");
		Если Параметр <> Неопределено Тогда
			Параметр.Значение = ЗначениеОтбора;
			Параметр.Использование = Истина;
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

В данном примере мы проверяем тип элемента коллекции, так как в отборе могут находиться не только одиночные элементы ЭлементОтбораКомпоновкиДанных, но и группы отборов ГруппаЭлементовОтбораКомпоновкиДанных. Также обратите внимание на сравнение с объектом ПолеКомпоновкиДанных, а не со строковым значением.

Способ 2. Обход пользовательских настроек по идентификатору

Проанализируем альтернативный вариант, когда требуется обратиться напрямую к структуре пользовательских настроек КомпоновщикНастроек.ПользовательскиеНастройки.

Каждый пользовательский элемент связан с элементом настроек через уникальный идентификатор. Посмотрим на пример обхода коллекции пользовательских настроек:


ЗначениеОтбора = Неопределено;

Для Каждого ЭлементНастройки Из КомпоновщикНастроек.ПользовательскиеНастройки.Элементы Цикл
	Если ТипЗнч(ЭлементНастройки) = Тип("ЭлементОтбораКомпоновкиДанных") Тогда
		// Проверяем поле отбора
		Если Строка(ЭлементНастройки.ЛевоеЗначение) = "ТорговаяМарка" Тогда
			Если ЭлементНастройки.Использование Тогда
				ЗначениеОтбора = ЭлементНастройки.ПравоеЗначение;
				Прервать;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
КонецЦикла;

Если ЗначениеОтбора <> Неопределено Тогда
	// Устанавливаем значение в параметр СКД
	КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("ТорговаяМаркаДляКлиентов", ЗначениеОтбора);
КонецЕсли;

Альтернативные архитектурные решения без написания кода

Разберем способы решения задачи средствами самой платформы 1С без использования процедуры ПриКомпоновкеРезультата:

  1. Использование параметров данных вместо отборов: Выведите в пользовательские настройки на форме отчета не элемент отбора, а параметр данных СКД (например, &Производитель). Параметры напрямую подставляются в условия виртуальных таблиц запроса и не вызывают принудительного изменения типа соединения всей схемы.
  2. Связи наборов данных: Если данные разделены на два независимых набора (Набор 1 — Справочник номенклатуры, Набор 2 — Продажи), укажите связь между ними на вкладке «Связи наборов данных». В колонке «Параметр» задайте имя параметра подчиненного набора. СКД автоматически передаст условия в подчиненный запрос, сохраняя целостность левого соединения.
  3. Расширение языка запросов: В тексте запроса виртуальной таблицы укажите условие в фигурных скобках: {ГДЕ Таблица.Производитель.* КАК ПроизводительПродаж}. Это позволит вывести отдельный доступный отбор, действующий только на один источник данных.
← На главную