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