Как отфильтровать динамический список по иерархии подразделений при открытии формы

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

В практике разработчика 1С часто возникает задача ограничить видимость данных в списках документов или справочников. Особенно актуально это для крупных организаций, где необходимо разделять документы по подразделениям. Если по каким-то причинам использование механизма RLS (Record Level Security) невозможно или нецелесообразно (например, из-за требований к производительности или сложности настройки), приходится прибегать к программным методам фильтрации. Рассмотрим, как правильно реализовать фильтрацию динамического списка с учетом иерархии (само подразделение и все его подчиненные филиалы).

Анализ стандартного механизма параметров формы

При открытии формы в 1С:Предприятие 8.3 через функцию ОткрытьФорму мы можем передать структуру Параметры. Одним из ключей этой структуры является Отбор. Стандартное поведение платформы заключается в том, что если в ключе Отбор передано простое значение, применяется вид сравнения Равно. Если же передать массив или список значений, платформа автоматически применит вид сравнения В списке.

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

Способ 1: Передача списка всех подчиненных элементов

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

  1. Вычисляем текущее подразделение пользователя (например, из параметров сеанса или настроек).
  2. Получаем массив ссылок всех подчиненных подразделений, включая исходное. Это можно сделать простым запросом с условием В ИЕРАРХИИ.
  3. Помещаем этот массив в структуру параметров открытия формы.

Пример кода для реализации этого метода:


// 1. Получаем список подразделений (само подразделение + филиалы)
Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   ПодразделенияОрганизаций.Ссылка КАК Ссылка
|ИЗ
|   Справочник.ПодразделенияОрганизаций КАК ПодразделенияОрганизаций
|ГДЕ
|   ПодразделенияОрганизаций.Ссылка В ИЕРАРХИИ(&Родитель)";

Запрос.УстановитьПараметр("Родитель", ПодразделениеПользователя);
СписокПодразделений = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");

// 2. Формируем структуру отбора
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("ПодразделениеОрганизации", СписокПодразделений);

// 3. Формируем общие параметры формы
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Отбор", ПараметрыОтбора);

// 4. Открываем форму
ОткрытьФорму("Документ.РеализацияТоваровУслуг.ФормаСписка", ПараметрыФормы);

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

Способ 2: Использование фиксированных настроек динамического списка

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

Рассмотрим ситуацию, когда мы передаем в форму только одно «Главное подразделение», а форма сама настраивает иерархический фильтр:


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

Преимущество этого способа в том, что нам не нужно выполнять предварительный запрос для поиска всех филиалов — платформа сделает это сама на уровне СУБД, используя эффективный оператор IN HIERARCHY.

Способ 3: Особенности для БП 3.0 и расширений

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

Проанализируем, как лучше внедрить фильтрацию с помощью Расширения:

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

Посмотрим на пример в коде менеджера документа (в расширении):


&Вместо("ОбработкаПолученияФормы")
Процедура Расш_ОбработкаПолученияФормы(ВидФормы, Параметры, ВыбраннаяФорма, СтандартнаяОбработка)
    
    Если ВидФормы = "ФормаСписка" ИЛИ ВидФормы = "ФормаВыбора" Тогда
        
        // Получаем подразделение текущего пользователя
        ТекущееПодразделение = ... // Ваша логика получения
        
        // Добавляем отбор в параметры
        Если Не Параметры.Свойство("Отбор") Тогда
            Параметры.Вставить("Отбор", Новый Структура);
        КонецЕсли;
        
        // Используем фокус из Способа 1
        СписокФилиалов = ПолучитьСписокФилиалов(ТекущееПодразделение);
        Параметры.Отбор.Вставить("ПодразделениеОрганизации", СписокФилиалов);
        
    КонецЕсли;
    
КонецПроцедуры

Выясним причины ошибок при работе со структурами

Разберем типичную ошибку, с которой столкнулся автор вопроса: попытка передать сложную структуру (с ЛевоеЗначение, ВидСравнения и т.д.) напрямую в параметры Отбор.

Важно понимать: ключ Отбор в параметрах формы ОткрытьФорму ожидает простую структуру типа "ИмяПоля" : "Значение". Он не предназначен для передачи сложных объектов компоновки данных. Платформа просто не умеет парсить объекты ЭлементОтбораКомпоновкиДанных, переданные таким образом. Если вам нужны сложные условия (Больше, Меньше, В Иерархии), используйте либо предварительную подготовку списка значений (как в способе 1), либо программную установку настроек внутри самой формы (как в способе 2).

Рекомендации по безопасности

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

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

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

← На главную