Как в запросе 1С проверить вхождение номенклатуры в определенную группу (родителя)

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

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

Базовая проверка родителя в запросе

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


ВЫБОР
    КОГДА РеализацияТоваровУслугТовары.Номенклатура.Родитель = &СсылкаГруппы
        ТОГДА РеализацияТоваровУслугТовары.Количество
    ИНАЧЕ 0
КОНЕЦ

Этот метод работает быстро, так как 1С выполняет простое сравнение ссылок. Однако у него есть существенный минус: если внутри "Группы 1" есть "Подгруппа А", и товар лежит в ней, условие не сработает. Для проверки вхождения на любом уровне вложенности используется оператор В ИЕРАРХИИ.

Использование оператора В ИЕРАРХИИ

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


ВЫБОР
    КОГДА РеализацияТоваровУслугТовары.Номенклатура В ИЕРАРХИИ (&СсылкаГруппы)
        ТОГДА РеализацияТоваровУслугТовары.Количество
    ИНАЧЕ 0
КОНЕЦ

Важный нюанс производительности: Оператор В ИЕРАРХИИ на уровне СУБД трансформируется в достаточно сложный запрос. Если ваш справочник Номенклатура содержит сотни тысяч элементов, а глубина иерархии велика, использование этого оператора в секции ВЫБОР или ГДЕ может замедлить отчет. Если вам заранее известно, что иерархия не нужна, всегда отдавайте предпочтение обычному равенству.

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

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

КОГДА Номенклатура.Родитель.Наименование = "Продукты"

Проанализируем, почему это считается плохой практикой (или "говнокодом"):

  1. Человеческий фактор: Любой пользователь с правами редактирования может переименовать "Продукты" в "Продукты питания", и ваш отчет мгновенно перестанет работать.
  2. Дубли: В справочнике могут существовать две разные папки с одинаковым названием в разных ветках. Запрос по наименованию не позволит их различить.
  3. Локализация: Если база будет использоваться на другом языке, строковые константы в коде станут проблемой.

Вместо этого рекомендуется использовать поиск по коду или, что еще лучше, предопределенные элементы. Если определенные группы номенклатуры важны для бизнес-логики, их стоит создать в конфигураторе как предопределенные. Тогда в запросе можно будет написать:

ГДЕ Номенклатура В ИЕРАРХИИ (ЗНАЧЕНИЕ(Справочник.Номенклатура.ГруппаПродукты))

Реализация в Системе компоновки данных (СКД)

Если мы работаем в СКД, задача передачи конкретных групп в параметры решается несколькими способами. Рассмотрим ситуацию, когда нам нужно проверить вхождение в одну из 6–10 разных групп.

Способ 1: Массив в параметре

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


ВЫБОР
    КОГДА Номенклатура В ИЕРАРХИИ (&СписокНужныхГрупп)
        ТОГДА "Нужная категория"
    ИНАЧЕ "Прочее"
КОНЕЦ

Способ 2: Настройка выражений в СКД

Выясним, как передать значения в параметр без написания программного кода в модуле отчета. В конструкторе СКД на закладке "Параметры" есть колонка "Выражение". Мы можем прописать там логику получения ссылки по коду:

Справочники.Номенклатура.НайтиПоКоду("000000001")

Если нам нужно передать список кодов, мы можем воспользоваться подзапросом прямо в тексте основного запроса, чтобы не зависеть от внешних параметров, которые пользователь может случайно очистить:


ГДЕ Номенклатура В ИЕРАРХИИ (
    ВЫБРАТЬ Ссылка 
    ИЗ Справочник.Номенклатура 
    ГДЕ Код В ("УТ-0001", "УТ-0005", "УТ-0010")
)

Использование дополнительных реквизитов (Альтернативный подход)

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

Создадим для номенклатуры дополнительный реквизит "Категория для отчета" (тип: Булево или Справочник). Тогда в запросе нам не нужно будет проверять В ИЕРАРХИИ. Мы просто проверим значение этого реквизита. Это гораздо надежнее, так как товар может находиться в любой папке, но сохранять свою логическую категорию.

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

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


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

Подведем итоги

Проанализировав все способы, можно составить иерархию "правильности" решений:

  1. Самый надежный: Использование дополнительных реквизитов или предопределенных элементов.
  2. Стандартный: Использование параметров типа СправочникСсылка или СписокЗначений с оператором В ИЕРАРХИИ.
  3. Гибкий: Использование выражений в параметрах СКД для поиска групп по коду.
  4. Нежелательный: Жесткое прописывание наименований папок в тексте запроса.

Выбирайте метод исходя из того, насколько часто в вашей базе меняется структура справочника Номенклатура и насколько критична скорость выполнения запроса.

← На главную