Почему при программном формировании отчета СКД не находятся параметры периода и как это исправить?

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

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

В этой статье мы подробно разберем, почему возникает эта ошибка, изучим архитектурные нюансы платформы 1С:Предприятие 8.3 при работе с СКД и рассмотрим правильные, надежные способы программной установки параметров.

Выясняем причину: два уровня существования параметров в СКД

Для понимания природы этой проблемы нам необходимо разделять структуру СКД на два независимых уровня представления данных:

  1. Уровень схемы компоновки данных (метаданные): Находится в объекте СхемаКомпоновкиДанных.Параметры. Здесь всегда перечислены абсолютно все параметры, которые объявлены в ваших SQL-подобных запросах к базе данных или добавлены вручную на вкладке "Параметры" в конструкторе СКД.
  2. Уровень настроек компоновки (динамические значения): Находится в коллекции НастройкиКомпоновкиДанных.ПараметрыДанных. Эта коллекция создается динамически для каждого конкретного варианта отчета.

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

Решение проблемы: правильная инициализация Компоновщика настроек

Для того чтобы связать схему компоновки (метаданные) и настройки варианта отчета, в платформе 1С предусмотрен специальный объект — Компоновщик настроек компоновки данных. Проанализируем правильный алгоритм его программной инициализации.

При использовании компоновщика платформа обращается к так называемому "источнику доступных настроек". На основе метаданных схемы компоновщик автоматически генерирует в коллекции настроек недостающие элементы для всех параметров, существующих в схеме. Только после этого шага мы сможем успешно найти и изменить любые параметры.

Рассмотрим по шагам работающий пример программного формирования отчета с заполнением параметров периода:


// 1. Получаем внешний отчет и его схему компоновки данных
НужныйОтчет = ВнешниеОтчеты.Создать(ИмяФайлаОтчета, Ложь);
СхемаКомпоновкиДанных = НужныйОтчет.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");

// 2. Получаем исходные настройки по умолчанию из схемы
НастройкиПоУмолчанию = СхемаКомпоновкиДанных.НастройкиПоУмолчанию;

// 3. Создаем и инициализируем компоновщик настроек
КомпНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
ИсточникНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКомпоновкиДанных);
КомпНастроек.Инициализировать(ИсточникНастроек);

// 4. Загружаем наши настройки в инициализированный компоновщик
КомпНастроек.ЗагрузитьНастройки(НастройкиПоУмолчанию);

// 5. Теперь работаем с настройками, которые находятся внутри компоновщика
РабочиеНастройки = КомпНастроек.Настройки;

// 6. Успешно находим и заполняем параметры периода
НачалоПериода = РабочиеНастройки.ПараметрыДанных.Элементы.Найти("ДатаНачала");
Если НачалоПериода <> Неопределено Тогда
    НачалоПериода.Значение = НачалоДня(ТекущаяДата() - 86400); // Вчерашний день
    НачалоПериода.Использование = Истина;
КонецЕсли;

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

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

Более надежный и стандартный метод поиска: НайтиЗначениеПараметра()

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

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

Посмотрим на пример его использования:


// Поиск параметра "ДатаНачала" с использованием специализированного метода
ИмяПараметраСКД = Новый ПараметрКомпоновкиДанных("ДатаНачала");
ПараметрДатаНачала = РабочиеНастройки.ПараметрыДанных.НайтиЗначениеПараметра(ИмяПараметраСКД);

Если ПараметрДатаНачала <> Неопределено Тогда
    ПараметрДатаНачала.Значение = НачалоДня(ТекущаяДата() - 86400);
    ПараметрДатаНачала.Использование = Истина;
КонецЕсли;

Важный нюанс платформы: Пользовательские настройки

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

Платформа 1С обрабатывает их следующим образом: при формировании отчета значения из коллекции ПользовательскиеНастройки имеют наивысший приоритет. Они перекрывают значения из основной коллекции КомпоновщикНастроек.Настройки.ПараметрыДанных. Если параметры вынесены в пользовательские настройки, изменение их в обычных настройках компоновщика не даст никакого эффекта — при выводе они просто перезапишутся пустыми значениями с формы.

Чтобы программно установить такие параметры, нам необходимо найти их в коллекции пользовательских настроек по их уникальному идентификатору. Разберем этот алгоритм:


// 1. Сначала находим описание параметра в обычных настройках, чтобы получить его Идентификатор
ПараметрВНастройках = КомпНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("ДатаНачала"));

Если ПараметрВНастройках <> Неопределено Тогда
    // Проверяем, вынесен ли параметр в пользовательские настройки
    Если ЗначениеЗаполнено(ПараметрВНастройках.ИдентификаторПользовательскойНастройки) Тогда
        
        // 2. Ищем элемент в пользовательских настройках по этому Идентификатору
        ЭлементПользовательскойНастройки = КомпНастроек.ПользовательскиеНастройки.Элементы.Найти(ПараметрВНастройках.ИдентификаторПользовательскойНастройки);
        
        Если ЭлементПользовательскойНастройки <> Неопределено Тогда
            ЭлементПользовательскойНастройки.Значение = НачалоДня(ТекущаяДата() - 86400);
            ЭлементПользовательскойНастройки.Использование = Истина;
        КонецЕсли;
        
    Иначе
        // Если параметр не вынесен в пользовательские настройки, меняем его в обычных настройках
        ПараметрВНастройках.Значение = НачалоДня(ТекущаяДата() - 86400);
        ПараметрВНастройках.Использование = Истина;
    КонецЕсли;
КонецЕсли;

Почему нельзя изменять параметры напрямую в схеме компоновки данных?

У начинающих разработчиков иногда возникает соблазн обойти проблемы с компоновщиком настроек, устанавливая значения напрямую в коллекцию параметров самой схемы:

СхемаКомпоновкиДанных.Параметры.ДатаНачала.Значение = ПолучитьДату();

Делать так категорически не рекомендуется по следующим архитектурным причинам:

Любые динамические изменения параметров, отборов и группировок всегда должны производиться исключительно в изолированных объектах настроек (в свойствах компоновщика или макета компоновки конкретного сеанса работы пользователя).

← На главную