Как программно установить параметры и отборы в отчете СКД при открытии формы?

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

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

Разберем детально, почему так происходит и как правильно передавать и накладывать сложные отборы СКД при открытии отчета.

В чем причина такого поведения платформы?

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

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

Способ 1. Формирование пользовательских настроек до открытия формы и их передача в параметры

Рассмотрим практический сценарий: требуется открыть отчет «Ведомость по товарам на складах» из документа «Пересчет товаров» и отобрать данные только по тем позициям, где фактическое количество не совпало с учетным. Поскольку СКД не поддерживает фильтрацию кортежей вида (Номенклатура, Характеристика) В (...), отбор строится через группу ИЛИ, внутри которой для каждой строки создается группа И (по Номенклатуре и Характеристике).

Разберем по шагам реализацию через команду с подготовкой объекта отчета, получением его варианта и генерацией структуры ПользовательскиеНастройки:


&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)

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

    ОтборПоСкладу = Новый Массив;    
    ОтборПоСкладу.Добавить(Новый Структура("Склад", ПараметрКоманды.Склад));
        
    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("Документ", ПараметрКоманды);
    ПараметрыФормы.Вставить("ПоляДляОтбора", ПоляДляОтбора);
    ПараметрыФормы.Вставить("СформироватьПриОткрытии", Истина);
    ПараметрыФормы.Вставить("ПользовательскиеНастройки", 
        ЗаполнитьПользовательскиеНастройкиОтчета("ВедомостьПоТоварамНаСкладах", 
            Новый Структура("Отбор,ОтборПоСкладу", ПоляДляОтбора, ОтборПоСкладу), 
            "_ПересчетыТоваров"));

    ОткрытьФорму("Отчет.ВедомостьПоТоварамНаСкладах.Форма", 
        ПараметрыФормы, 
        ПараметрыВыполненияКоманды.Источник, 
        ПараметрыВыполненияКоманды.Уникальность, 
        ПараметрыВыполненияКоманды.Окно, 
        ПараметрыВыполненияКоманды.НавигационнаяСсылка);

КонецПроцедуры

Посмотрим на серверную функцию заполнения настроек, которая инициализирует нужный вариант, строит дерево условий и возвращает заполненную коллекцию ПользовательскиеНастройки:


&НаСервере
Функция ЗаполнитьПользовательскиеНастройкиОтчета(ИмяОтчета, ПараметрыПользователя, ИмяВарианта) Экспорт    

    ОтчетОбъект = Отчеты[ИмяОтчета].Создать();
    КомпоновщикНастроек = ОтчетОбъект.КомпоновщикНастроек;    

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

            // Создаем общую группу ИЛИ для всех пар номенклатура-характеристика
            ГруппаОтбораТоваров = Настройки.Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
            ГруппаОтбораТоваров.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИЛИ;
            ГруппаОтбораТоваров.Использование = Истина;

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

            // Добавляем общий отбор по складу
            СкладОтборГруппы = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
            СкладОтборГруппы.Использование = Истина;
            СкладОтборГруппы.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Склад");
            СкладОтборГруппы.ВидСравнения  = ВидСравненияКомпоновкиДанных.Равно;
            СкладОтборГруппы.ПравоеЗначение = ПараметрыПользователя.ОтборПоСкладу[0].Склад;
        КонецЕсли;         
    Иначе            
        Настройки = КомпоновщикНастроек.ПолучитьНастройки();        
    КонецЕсли; 

    КомпоновщикНастроек.ЗагрузитьНастройки(Настройки);

    Возврат КомпоновщикНастроек.ПользовательскиеНастройки;

КонецФункции

Способ 2. Загрузка настроек непосредственно в форме отчета

Если вы модифицируете модуль самой формы отчета, переданные значения нужно не просто внедрить в Отчет.КомпоновщикНастроек.Настройки, но и применить к пользовательским настройкам формы.

Рассмотрим, как это выполняется с помощью методов ЗагрузитьНастройки() и ЗагрузитьПользовательскиеНастройки():


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    Если Параметры.Свойство("ПользовательскиеНастройки") Тогда
        Отчет.КомпоновщикНастроек.ЗагрузитьПользовательскиеНастройки(Параметры.ПользовательскиеНастройки);
    КонецЕсли;

КонецПроцедуры

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

  1. ПриЗагрузкеПользовательскихНастроекНаСервере — выполняется в момент, когда типовые механизмы завершили чтение сохраненных настроек, что гарантирует сохранение программно добавленных параметров.
  2. ПриЗагрузкеВариантаНаСервере — обеспечивает корректную установку отборов при переключении вариантов отчета.

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

Обратите внимание на объем формируемого дерева условий. Если документ расхождений содержит десятки или сотни строк, генерация структуры с множественными условиями ИЛИ приведет к формированию тяжелого SQL-запроса с огромным блоком WHERE.

Это может вызвать отказ СУБД от использования индексов, деградацию производительности сервера и падение отчета по таймауту. Если строк с расхождениями много, предпочтительнее передавать список ключей через внешний набор данных (таблицу значений) или временную таблицу, связывая её в схеме компоновки внутренним соединением с основным запросом.

← На главную