Как в 1С 7.7 определить, какой именно группе из списка значений принадлежит товар?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

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

Рассмотрим частые ошибки при решении этой задачи и разберем корректные способы обхода и сопоставления данных.

Причины типовых ошибок при работе со списками групп

Разберем типичные заблуждения, с которыми сталкиваются разработчики:

  1. Попытка вызова Сообщить(СписокЗначений): если передать в процедуру Сообщить() переменную, содержащую объект типа СписокЗначений, платформа не будет перечислять элементы или строки списка, а выведет стандартное строковое представление агрегатного типа данных — "СписокЗначений".
  2. Ошибочный метод Группа.Принадлежит(...): у объекта справочника нет метода с таким именем. Метод Принадлежит() существует у объекта СписокЗначений. Если попытаться вызвать его у самого элемента справочника, платформа выдаст фатальную ошибку: Поле агрегатного объекта не обнаружено (Принадлежит).
  3. Путаница между проверкой списка и проверкой элемента: для проверки вхождения элемента справочника в конкретную родительскую группу предназначен контекстный метод справочника ПринадлежитГруппе().

Способ 1. Итерационный перебор списка значений с проверкой через ПринадлежитГруппе()

Проанализируем базовый способ решения. Если у нас есть проверяемый элемент номенклатуры (например, ТекТовар) и список значений ВыбТовар, содержащий выбранные папки, мы можем организовать цикл по строкам этого списка значений.

Посмотрим на пример правильной реализации:


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

Обратим внимание на синтаксис: метод ПринадлежитГруппе(<Группа>) вызывается у проверяемого элемента, а целевая группа передается ему в качестве параметра.

Способ 2. Быстрая предварительная фильтрация через СписокЗначений.Принадлежит()

Вызов метода ПринадлежитГруппе() внутри вложенных циклов создает нагрузку на базу данных при обработке больших массивов номенклатуры. В платформе 1С 7.7 метод СписокЗначений.Принадлежит(<Значение>) обладает встроенной поддержкой иерархии справочников: если в списке находятся группы, платформа автоматически определяет, принадлежит ли переданный элемент хотя бы одной из этих групп или подгрупп.

Однако метод Принадлежит() у списка значений возвращает только число 1 (истина) или 0 (ложь), не сообщая, какая конкретно группа совпала. Поэтому оптимально совмещать быструю проверку с детальным обходом:


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

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

Способ 3. Подъем по иерархии родителей вверх (для больших списков)

Если на форме выбран список из десятков групп, перебирать весь список значений для каждого товара становится накладно. В иерархических справочниках 1С 7.7 глубина вложенности ограничена (не более 10 уровней). Гораздо быстрее подниматься от текущего товара вверх по цепочке Родитель и искать каждого родителя в списке значений через метод точного поиска НайтиЗначение(), который работает мгновенно в оперативной памяти.

Разберем реализацию этого алгоритма:


ТекРодитель = ТекТовар.Родитель;
ЦелеваяГруппа = ПолучитьПустоеЗначение("Справочник.ТМЦ");

Пока ТекРодитель.Выбран() = 1 Цикл
    // Ищем прямое совпадение родителя в списке групп на форме
    Если ВыбТовар.НайтиЗначение(ТекРодитель) > 0 Тогда
        ЦелеваяГруппа = ТекРодитель;
        Прервать; // Найдена ближайшая группа
    КонецЕсли;
    ТекРодитель = ТекРодитель.Родитель;
КонецЦикла;

Если ПустоеЗначение(ЦелеваяГруппа) = 0 Тогда
    Сообщить("Товар " + ТекТовар + " принадлежит группе " + ЦелеваяГруппа);
КонецЕсли;

Важные особенности и нюансы платформы 1С 7.7

  1. Вложенные группы в списке: если пользователь выбрал в списке значений как родительскую («Напитки»), так и вложенную в нее группу («Соки»), то при вызове ПринадлежитГруппе() условие выполнится для обеих. При обходе по Способу 1 будет возвращена та группа, которая расположена в списке выше. При использовании Способа 3 будет определена наиболее глубокая (ближайшая к товару) группа.
  2. Проверка группы на саму себя: в 1С 7.7 вызов Группа.ПринадлежитГруппе(Группа) возвращает 1. Если в алгоритм обработки может попасть не только конечный элемент, но и сама группа, следует предварительно проверять признак ЭтоГруппа().
← На главную