Как программно установить отбор и параметры в СКД и настроить связь по владельцу?

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

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

Причины проблемы фильтрации подчиненных данных в обычном приложении

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

Для реализации корректного поведения существуют три основных подхода:

  1. Вынесение управляющих полей ввода непосредственно на форму отчета с последующей синхронизацией значений с компоновщиком настроек.
  2. Программный перехват событий табличного поля отборов для динамической подстановки владельца при открытии формы выбора.
  3. Программное управление отборами и параметрами компоновщика настроек из встроенного языка.

Способ 1. Вынесение реквизитов на форму и синхронизация с СКД

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

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


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

Если требуется передавать значения не в параметры данных, а непосредственно в коллекцию отборов компоновщика, напишем процедуру установки элемента отбора:


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

Способ 2. Перехват события начала выбора в табличном поле отбора

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

Разберем реализацию по шагам:

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

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

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

Программная установка отборов в группировках СКД

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

Обратим внимание на то, что для корректной установки левого значения рекомендуется использовать метод НайтиПоле коллекции ДоступныеПоляОтбора:


// Установка отбора для первой группировки отчета
Группировка = КомпоновщикНастроек.Настройки.Структура[0];

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

Программное заполнение параметров данных СКД

При работе с параметрами данных схемы компоновки данных наиболее безопасным и лаконичным способом является вызов метода УстановитьЗначениеПараметра. Этот метод избавляет от необходимости вручную искать элемент коллекции и проверять его на равенство Неопределено:


// Программная установка параметра периода
КонецПериодаОтчета = ?(ПериодОтчета = '00010101', КонецДня(ТекущаяДата()), КонецДня(ПериодОтчета));
КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра(
    Новый ПараметрКомпоновкиДанных("КонецПериода"), 
    КонецПериодаОтчета
);

Защита отборов от случайного или нежелательного изменения пользователем

Нередко возникает задача жестко зафиксировать определенные условия (например, ограничение по организации или складу для конкретного пользователя), чтобы пользователь не мог снять флажок Использование или изменить правое значение.

Для решения этой задачи в платформе предусмотрены следующие штатные механизмы:

  1. Использование фиксированных настроек: Запись отбора в коллекцию КомпоновщикНастроек.ФиксированныеНастройки.Отбор. Настройки из этой коллекции объединяются с пользовательскими по условию «И», не выводятся в стандартную таблицу отборов на форме и не могут быть отредактированы пользователем.
  2. Отключение доступности элемента через режим отображения: Для элементов пользовательских настроек свойство РежимОтображения позволяет заблокировать интерактивное редактирование:
    
    ЭлементОтбора.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
    
  3. Перехват событий формы: Если отбор должен быть виден в таблице, но защищен от изменений, в событии табличного поля ПриНачалеРедактирования или ПередНачаломИзменения можно проверять текущую строку и устанавливать параметр Отказ = Истина.
← На главную