При создании внешних печатных форм часто возникает задача не просто вывести список товаров из документа, но и сгруппировать их по папкам (иерархии) справочника Номенклатура. Это делает форму более читаемой, особенно если в заказе или реализации десятки и сотни позиций. В этой статье мы разберем несколько способов реализации этой задачи: от классического использования запросов с итогами до применения современных возможностей системы компоновки данных (СКД).
Первый и самый важный шаг — это подготовка правильного запроса. Многие начинающие разработчики пытаются получить родителей номенклатуры «через точку», создавая конструкции вида Номенклатура.Родитель.Родитель. Это неэффективно, так как количество уровней вложенности может меняться, а такие обращения замедляют работу системы из-за лишних соединений в SQL.
Рассмотрим, как правильно использовать ключевое слово ИЕРАРХИЯ. Проанализируем пример кода, который позволяет получить дерево групп автоматически:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказТовары.Номенклатура КАК Номенклатура,
| ЗаказТовары.Количество КАК Количество,
| ЗаказТовары.Сумма КАК Сумма
|ИЗ
| Документ.ЗаказКлиента.Товары КАК ЗаказТовары
|ГДЕ
| ЗаказТовары.Ссылка В(&МассивОбъектов)
|ИТОГИ
| СУММА(Количество),
| СУММА(Сумма)
|ПО
| Номенклатура ИЕРАРХИЯ";
Запрос.УстановитьПараметр("МассивОбъектов", МассивОбъектов);
РезультатЗапроса = Запрос.Выполнить();
Использование ИТОГИ ПО Номенклатура ИЕРАРХИЯ заставляет платформу самостоятельно вычислить все родительские группы для каждой позиции товара и рассчитать по ним промежуточные суммы. Это избавляет нас от необходимости вручную перебирать дерево справочника.
После того как данные получены, их нужно вывести в ТабличныйДокумент. Чтобы пользователь мог сворачивать и разворачивать группы (видеть те самые «плюсики»), необходимо использовать методы НачатьГруппировкуСтрок и ЗакончитьГруппировкуСтрок. Разберем по шагам, как организовать этот процесс в цикле обхода результата запроса.
Для правильного вывода иерархии мы будем использовать специальный режим обхода — ОбходРезультатаЗапроса.ПоГруппировкамСИерархией. Проанализируем следующий алгоритм:
ВыборкаИерархия = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
Пока ВыборкаИерархия.Следующий() Цикл
// Если это группа (папка) или промежуточный итог иерархии
Если ВыборкаИерархия.ТипЗаписи() = ТипЗаписиЗапроса.ИтогПоИерархии Тогда
ОбластьГруппы = Макет.ПолучитьОбласть("СтрокаГруппы");
ОбластьГруппы.Параметры.НаименованиеГруппы = ВыборкаИерархия.Номенклатура;
ТабДок.Вывести(ОбластьГруппы, ВыборкаИерархия.Уровень());
// Начинаем визуальную группировку
ТабДок.НачатьГруппировкуСтрок(ВыборкаИерархия.Номенклатура, Ложь);
Иначе
// Это детальная запись (сам товар)
ОбластьСтроки = Макет.ПолучитьОбласть("СтрокаТаблицы");
ОбластьСтроки.Параметры.Заполнить(ВыборкаИерархия);
ТабДок.Вывести(ОбластьСтроки, ВыборкаИерархия.Уровень());
КонецЕсли;
// В рекурсивном или иерархическом обходе важно правильно закрывать группы
// В данном упрощенном примере мы полагаемся на автоматическое завершение при выводе следующей группы того же уровня
КонецЦикла;
Важные моменты при работе с группировками:
Вывести() вторым параметром принимает уровень (число). Это позволяет 1С автоматически определять отступы и структуру дерева.Ложь в методе НачатьГруппировкуСтрок означает, что по умолчанию группа будет развернута. Если установить Истина, отчет сформируется в свернутом виде.ТабДок.ТолькоПросмотр = Истина.Как отмечают опытные разработчики в обсуждении, самый прогрессивный метод для вывода иерархических структур — это использование СКД. Даже если вы делаете внешнюю печатную форму, вы можете программно вызвать схему компоновки.
Почему это удобно? Рассмотрим преимущества:
Выясним, как это выглядит в коде. Вместо ручного обхода выборки мы используем ПроцессорКомпоновкиДанных:
СхемаКомпоновки = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = СхемаКомпоновки.НастройкиПоУмолчанию;
// Передаем параметры (например, массив ссылок на документы)
ПараметрСсылки = Настройки.ПараметрыДанных.Элементы.Найти("МассивОбъектов");
ПараметрСсылки.Значение = МассивОбъектов;
ПараметрСсылки.Использование = Истина;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки, Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабличныйДокумент);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
В сложных случаях, когда стандартная иерархия 1С работает медленно или требуется специфическая логика (например, иерархия не по справочнику, а по кастомным связям), применяется метод «транзитивного замыкания». Суть его в том, чтобы создать временную таблицу, в которой для каждого элемента будут перечислены все его предки. Это позволяет строить отчеты по иерархии обычными плоскими запросами с высокой скоростью.
Проанализируем ситуацию с дополнительными реквизитами. Если вы выводите иерархию, помните, что у папок (групп) значения дополнительных реквизитов часто не заполнены. Проверяйте свойство ЭтоГруппа, чтобы в строках-заголовках не выводились пустые значения или «мусорные» данные от левых соединений.
Резюмируем: для простых печатных форм достаточно добавить ИТОГИ ПО Номенклатура ИЕРАРХИЯ и использовать метод ТабДок.Вывести(Область, Уровень). Для более сложных и интерактивных форм лучше один раз настроить схему компоновки данных, которая возьмет на себя всю рутину по отрисовке дерева групп.