При разработке отчетов и обработок в 1С часто возникает задача разделить данные по категориям номенклатуры, которые определяются её положением в иерархии справочника. Рассмотрим подробно, как реализовать такую проверку в запросе, разберем типичные ошибки новичков и изучим профессиональные подходы к решению этой задачи, особенно в контексте Системы компоновки данных (СКД).
Начнем с самого простого случая. Если нам нужно проверить, является ли конкретная папка прямым родителем элемента, мы используем обращение к полю Родитель. Проанализируем пример кода для использования в тексте запроса:
ВЫБОР
КОГДА РеализацияТоваровУслугТовары.Номенклатура.Родитель = &СсылкаГруппы
ТОГДА РеализацияТоваровУслугТовары.Количество
ИНАЧЕ 0
КОНЕЦ
Этот метод работает быстро, так как 1С выполняет простое сравнение ссылок. Однако у него есть существенный минус: если внутри "Группы 1" есть "Подгруппа А", и товар лежит в ней, условие не сработает. Для проверки вхождения на любом уровне вложенности используется оператор В ИЕРАРХИИ.
Разберем, как проверить принадлежность к группе с учетом всех вложенных папок. Это наиболее универсальный способ для иерархических справочников:
ВЫБОР
КОГДА РеализацияТоваровУслугТовары.Номенклатура В ИЕРАРХИИ (&СсылкаГруппы)
ТОГДА РеализацияТоваровУслугТовары.Количество
ИНАЧЕ 0
КОНЕЦ
Важный нюанс производительности: Оператор В ИЕРАРХИИ на уровне СУБД трансформируется в достаточно сложный запрос. Если ваш справочник Номенклатура содержит сотни тысяч элементов, а глубина иерархии велика, использование этого оператора в секции ВЫБОР или ГДЕ может замедлить отчет. Если вам заранее известно, что иерархия не нужна, всегда отдавайте предпочтение обычному равенству.
Часто у начинающих разработчиков возникает соблазн написать проверку напрямую по названию папки, чтобы не возиться с параметрами:
КОГДА Номенклатура.Родитель.Наименование = "Продукты"
Проанализируем, почему это считается плохой практикой (или "говнокодом"):
Вместо этого рекомендуется использовать поиск по коду или, что еще лучше, предопределенные элементы. Если определенные группы номенклатуры важны для бизнес-логики, их стоит создать в конфигураторе как предопределенные. Тогда в запросе можно будет написать:
ГДЕ Номенклатура В ИЕРАРХИИ (ЗНАЧЕНИЕ(Справочник.Номенклатура.ГруппаПродукты))
Если мы работаем в СКД, задача передачи конкретных групп в параметры решается несколькими способами. Рассмотрим ситуацию, когда нам нужно проверить вхождение в одну из 6–10 разных групп.
Вместо создания десяти отдельных параметров &Группа1, &Группа2 и так далее, лучше использовать один параметр с типом Список значений или массив. В запросе это будет выглядеть так:
ВЫБОР
КОГДА Номенклатура В ИЕРАРХИИ (&СписокНужныхГрупп)
ТОГДА "Нужная категория"
ИНАЧЕ "Прочее"
КОНЕЦ
Выясним, как передать значения в параметр без написания программного кода в модуле отчета. В конструкторе СКД на закладке "Параметры" есть колонка "Выражение". Мы можем прописать там логику получения ссылки по коду:
Справочники.Номенклатура.НайтиПоКоду("000000001")
Если нам нужно передать список кодов, мы можем воспользоваться подзапросом прямо в тексте основного запроса, чтобы не зависеть от внешних параметров, которые пользователь может случайно очистить:
ГДЕ Номенклатура В ИЕРАРХИИ (
ВЫБРАТЬ Ссылка
ИЗ Справочник.Номенклатура
ГДЕ Код В ("УТ-0001", "УТ-0005", "УТ-0010")
)
Рассмотрим ситуацию под другим углом. Если иерархия справочника часто меняется (товары перемещаются между папками), то привязка логики к родителям становится хрупкой. В современных конфигурациях (на базе БСП, таких как ERP, УТ 11, КА) правильнее использовать Дополнительные реквизиты.
Создадим для номенклатуры дополнительный реквизит "Категория для отчета" (тип: Булево или Справочник). Тогда в запросе нам не нужно будет проверять В ИЕРАРХИИ. Мы просто проверим значение этого реквизита. Это гораздо надежнее, так как товар может находиться в любой папке, но сохранять свою логическую категорию.
Если же условия задачи требуют жесткой привязки к списку групп, и вы не хотите, чтобы пользователь видел эти параметры на форме, воспользуйтесь модулем объекта отчета. В процедуре ПриКомпоновкеРезультата мы можем программно заполнить список:
Процедура ПриКомпоновкеРезультата(ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Создаем список групп
СписокГрупп = Новый СписокЗначений;
СписокГрупп.Добавить(Справочники.Номенклатура.НайтиПоКоду("001"));
СписокГрупп.Добавить(Справочники.Номенклатура.НайтиПоКоду("042"));
// Устанавливаем параметр в настройках
ПараметрСКД = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("СписокГрупп");
Если ПараметрСКД <> Неопределено Тогда
ПараметрСКД.Значение = СписокГрупп;
ПараметрСКД.Использование = Истина;
КонецЕсли;
// Продолжаем стандартный вывод
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(Результат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
Проанализировав все способы, можно составить иерархию "правильности" решений:
СправочникСсылка или СписокЗначений с оператором В ИЕРАРХИИ.Выбирайте метод исходя из того, насколько часто в вашей базе меняется структура справочника Номенклатура и насколько критична скорость выполнения запроса.