Как в динамическом списке 1С скрыть группу номенклатуры и все ее подгруппы?

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

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

Исходная ситуация: есть конфигурация "1С:Управление нашей фирмой" 3.0. В форме списка номенклатуры (или в форме подбора) нужно программно установить отбор, который скроет группу "Материалы" с кодом "НФ-00000007" и все, что в нее вложено. При этом пользователь не должен иметь возможности отключить этот отбор.

Анализ проблемы: почему не работает отбор по полю «Родитель»

Первая мысль, которая приходит в голову, — установить отбор по полю Родитель. Логично предположить, что можно указать условие "Не в иерархии" или "Не равно" для требуемой группы. Посмотрим на код, который кажется правильным, но на самом деле не работает:


// ЭТОТ КОД НЕ РАБОТАЕТ
ГруппаМатериалы = Справочники.Номенклатура.НайтиПоКоду("НФ-00000007");

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

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

Правильное решение: отбор по полю «Ссылка»

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

Для этого в отборе в качестве левого значения указываем поле Ссылка, а в качестве вида сравнения — НеВИерархии. Этот вид сравнения как раз и предназначен для проверки вхождения ссылки на элемент в иерархию указанной группы.

Рассмотрим по шагам, как выглядит правильный код:

  1. Находим нужную группу. Используем метод НайтиПоКоду(), чтобы получить ссылку на группу "Материалы".
  2. Создаем новый элемент отбора. Добавляем его в коллекцию отборов динамического списка.
  3. Указываем левое значение. Это ключевой момент: устанавливаем Новый ПолеКомпоновкиДанных("Ссылка").
  4. Устанавливаем вид сравнения. Выбираем ВидСравненияКомпоновкиДанных.НеВИерархии.
  5. Задаем правое значение. Указываем ссылку на группу, которую мы нашли на первом шаге.
  6. Настраиваем использование и отображение. Устанавливаем флаг Использование = Истина и режим отображения Недоступный, чтобы пользователь не мог изменить настройку.

Вот итоговый работающий код:


// Находим группу номенклатуры, которую нужно исключить
ГруппаМатериалы = Справочники.Номенклатура.НайтиПоКоду("НФ-00000007");

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

Этот код следует размещать в серверной процедуре формы, например, в обработчике события ПриСозданииНаСервере.

Альтернативный метод: изменение текста запроса динамического списка

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

Преимущества этого подхода:

Реализация состоит из двух шагов:

  1. Добавление условия в текст запроса. В конфигураторе откройте свойства динамического списка, перейдите на вкладку "Настройка" и в тексте запроса добавьте условие в секцию ГДЕ. Чтобы сделать условие гибким, используем параметр:

    
    ВЫБРАТЬ
        Номенклатура.Ссылка,
        Номенклатура.Наименование,
        // ... другие поля
    ИЗ
        Справочник.Номенклатура КАК Номенклатура
    ГДЕ
        НЕ Номенклатура.Ссылка В ИЕРАРХИИ(&ИсключаемаяГруппа)
    
  2. Программная установка значения параметра. В коде формы (например, в ПриСозданииНаСервере) нужно установить значение для созданного нами параметра &ИсключаемаяГруппа.

    
    // Находим группу, которую нужно исключить
    ГруппаМатериалы = Справочники.Номенклатура.НайтиПоКоду("НФ-00000007");
        
    // Устанавливаем значение параметра в динамическом списке
    Список.Параметры.УстановитьЗначениеПараметра("ИсключаемаяГруппа", ГруппаМатериалы);
    

В некоторых типовых конфигурациях, как УНФ, могут существовать специальные процедуры для переопределения запросов, например ПереопределитьТекстЗапросаСписокЗапасы. Если такая процедура есть, то логику изменения запроса лучше размещать именно там — это более правильный подход при доработке типовых решений.

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

← На главную