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