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

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

При формировании нестандартных отчетов и печатных форм часто возникает задача сгруппировать выводимые строки по иерархии справочника, например, по папкам номенклатуры с возможностью сворачивания и разворачивания узлов. Однако при попытке вручную соединить секцию итогов в запросе и методы группировки строк табличного документа разработчики нередко сталкиваются с пустыми строками, отсутствием древовидной структуры или неработающими кнопками раскрытия («плюсиками»). Разберем по шагам, почему возникают эти ошибки и как правильно реализовать вывод данных по группам.

Анализ типичных ошибок исходного кода

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

  1. Некорректный синтаксис упорядочивания. Конструкция вида УПОРЯДОЧИТЬ ПО ТабИнвентаризация.Номенклатура.ЭтоГруппа ИЕРАРХИЯ ошибочна. Ключевое слово ИЕРАРХИЯ используется либо при упорядочивании непосредственно по ссылочному полю (УПОРЯДОЧИТЬ ПО Номенклатура ИЕРАРХИЯ), либо в секции ИТОГИ.
  2. Пустые значения при добавлении секции итогов. Если в запрос просто добавить фразу ИТОГИ ПО Номенклатура, не указав агрегатные функции над числовыми полями, то для группировочных строк все остальные поля вернут NULL или пустые значения. В секции итогов обязательно нужно перечислять поля суммирования.
  3. Ошибочный вызов автогруппировки. Метод НачатьАвтогруппировкуСтрок() принадлежит объекту ТабличныйДокумент, а не отдельной области макета. Вызывать его внутри цикла для области ОбластьГруппа.НачатьАвтогруппировкуСтрок() бессмысленно и ошибочно. Кроме того, чтобы автогруппировка заработала, методу Вывести() необходимо передавать уровень вложенности строки.
  4. Плоский обход выборки. Использование единого цикла без проверки типа записи выборки приводит к тому, что на каждом шаге программа пытается вывести сразу и шапку группы, и строку данных, что искажает визуальное представление отчета.
  5. Жесткая привязка к родителям. Выражение Номенклатура.Родитель.Родитель жестко завязано на конкретную глубину вложенности. Если товар находится в корне каталога или глубже третьего уровня, логика рушится. Штатный механизм иерархии решает эту проблему универсально.

Решение 1. Использование секции ИТОГИ и автогруппировки строк табличного документа

Рассмотрим правильный подход к построению отчета с использованием иерархических итогов запроса и автоматической группировки строк. Для этого скорректируем текст запроса, добавив расчет итогов с ключевым словом ИЕРАРХИЯ, и перепишем алгоритм вывода данных.

Посмотрим на пример правильного формирования запроса и вывода в табличный документ:


ТабличныйДокумент = ЭлементыФормы.ПолеТабличногоДокумента1;
ТабличныйДокумент.Очистить();

Макет = ПолучитьМакет("Макет");
ОбластьШапка      = Макет.ПолучитьОбласть("Шапка");
ОбластьЗаголовок  = Макет.ПолучитьОбласть("Заголовок");
ОбластьЗаголовок1 = Макет.ПолучитьОбласть("Заголовок1");
ОбластьДанные     = Макет.ПолучитьОбласть("Данные");
ОбластьГруппа     = Макет.ПолучитьОбласть("Группа");

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ИнвентаризацияТовары.Номенклатура КАК Номенклатура,
    |    СУММА(ИнвентаризацияТовары.КоличествоКнижн) КАК КоличествоКнижн,
    |    СУММА(ИнвентаризацияТовары.СуммаКнижн) КАК СуммаКнижн,
    |    СУММА(ИнвентаризацияТовары.КоличествоФакт) КАК КоличествоФакт,
    |    СУММА(ИнвентаризацияТовары.СуммаФакт) КАК СуммаФакт,
    |    СУММА(ВЫБОР
    |            КОГДА ИнвентаризацияТовары.КоличествоКнижн > ИнвентаризацияТовары.КоличествоФакт
    |                ТОГДА ИнвентаризацияТовары.КоличествоКнижн - ИнвентаризацияТовары.КоличествоФакт
    |            ИНАЧЕ 0
    |        КОНЕЦ) КАК Недостача,
    |    СУММА(ВЫБОР
    |            КОГДА ИнвентаризацияТовары.КоличествоКнижн < ИнвентаризацияТовары.КоличествоФакт
    |                ТОГДА ИнвентаризацияТовары.КоличествоФакт - ИнвентаризацияТовары.КоличествоКнижн
    |            ИНАЧЕ 0
    |        КОНЕЦ) КАК Излишки
    |ПОМЕСТИТЬ ТабИнвентаризация
    |ИЗ
    |    Документ.Инвентаризация.Товары КАК ИнвентаризацияТовары
    |ГДЕ
    |    ИнвентаризацияТовары.Ссылка = &Документ
    |СГРУППИРОВАТЬ ПО
    |    ИнвентаризацияТовары.Номенклатура
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |    ОстаткиТоваровКомпании.Номенклатура КАК Номенклатура,
    |    СУММА(ОстаткиТоваровКомпании.Количество) КАК Количество,
    |    СУММА(ОстаткиТоваровКомпании.СуммаРозн) КАК СуммаРозн
    |ПОМЕСТИТЬ ТабПревышения
    |ИЗ
    |    РегистрНакопления.ОстаткиТоваровКомпании КАК ОстаткиТоваровКомпании
    |ГДЕ
    |    ОстаткиТоваровКомпании.Период МЕЖДУ &НачалоПериода И &КонецПериода
    |    И ОстаткиТоваровКомпании.ХозОперация = &ХозОперация
    |    И ОстаткиТоваровКомпании.Номенклатура В ИЕРАРХИИ(&Номенклатура)
    |    И ОстаткиТоваровКомпании.СкладКомпании = &Склад
    |СГРУППИРОВАТЬ ПО
    |    ОстаткиТоваровКомпании.Номенклатура
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |    ТабИнвентаризация.Номенклатура КАК Номенклатура,
    |    ТабИнвентаризация.КоличествоКнижн КАК КоличествоКнижн,
    |    ТабИнвентаризация.СуммаКнижн КАК СуммаКнижн,
    |    ТабИнвентаризация.КоличествоФакт КАК КоличествоФакт,
    |    ТабИнвентаризация.СуммаФакт КАК СуммаФакт,
    |    ТабИнвентаризация.Недостача КАК Недостача,
    |    ТабИнвентаризация.Излишки КАК Излишки,
    |    ЕСТЬNULL(ТабПревышения.Количество, 0) КАК КоличествоПревышения,
    |    ЕСТЬNULL(ТабПревышения.СуммаРозн, 0) КАК СуммаПревышения
    |ИЗ
    |    ТабИнвентаризация КАК ТабИнвентаризация
    |        ЛЕВОЕ СОЕДИНЕНИЕ ТабПревышения КАК ТабПревышения
    |        ПО ТабИнвентаризация.Номенклатура = ТабПревышения.Номенклатура
    |ИТОГИ
    |    СУММА(КоличествоКнижн),
    |    СУММА(СуммаКнижн),
    |    СУММА(КоличествоФакт),
    |    СУММА(СуммаФакт),
    |    СУММА(Недостача),
    |    СУММА(Излишки),
    |    СУММА(КоличествоПревышения),
    |    СУММА(СуммаПревышения)
    |ПО
    |    Номенклатура ИЕРАРХИЯ";

Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода",  КонецПериода);
Запрос.УстановитьПараметр("ХозОперация",   Справочники.ХозОперации.НайтиПоКоду("020503"));
Запрос.УстановитьПараметр("Номенклатура",  СписокНоменклатуры);
Запрос.УстановитьПараметр("Документ",      Документ);
Запрос.УстановитьПараметр("Склад",         Склад);

// Вывод шапки отчета
ТабличныйДокумент.Вывести(ОбластьШапка);
ТабличныйДокумент.Вывести(ОбластьЗаголовок);
ТабличныйДокумент.Вывести(ОбластьЗаголовок1);

// Настройка отображения группировок
ТабличныйДокумент.ОтображатьГруппировки = Истина;
ТабличныйДокумент.НачатьАвтогруппировкуСтрок();

// Выборка с учетом иерархии
Выборка = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);

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

ТабличныйДокумент.ЗакончитьАвтогруппировкуСтрок();
ТабличныйДокумент.ПоказатьУровеньГруппировокСтрок(1);

Разберем важные особенности этого механизма:

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

Решение 2. Ручное управление структурой с помощью НачатьГруппуСтрок

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

Рассмотрим пример использования методов НачатьГруппуСтрок и ЗакончитьГруппуСтрок при обходе подчиненных выборок:


ТабличныйДокумент.Очистить();
ТабличныйДокумент.ОтображатьГруппировки = Истина;

ВыборкаГруппы = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаГруппы.Следующий() Цикл
    // Выводим заголовок группы
    ОбластьГруппа.Параметры.Группа = ВыборкаГруппы.Номенклатура;
    ТабличныйДокумент.Вывести(ОбластьГруппа);
    
    // Открываем новую группу строк (второй параметр - признак свернутости)
    ТабличныйДокумент.НачатьГруппуСтрок(Строка(ВыборкаГруппы.Номенклатура), Истина);
    
    // Получаем детальные записи группы
    ВыборкаДетали = ВыборкаГруппы.Выбрать();
    Пока ВыборкаДетали.Следующий() Цикл
        ЗаполнитьЗначенияСвойств(ОбластьДанные.Параметры, ВыборкаДетали);
        ТабличныйДокумент.Вывести(ОбластьДанные);
    КонецЦикла;
    
    // Закрываем группу строк
    ТабличныйДокумент.ЗакончитьГруппуСтрок();
КонецЦикла;

Ограничения платформы

При проектировании отчетов с группировками необходимо помнить о следующих ограничениях платформы 1С:

  1. Предел вложенности: табличный документ поддерживает не более 7 уровней вложенности группировок. Если иерархия справочника превышает 7 уровней, все более глубокие узлы объединяются на седьмом уровне.
  2. Автоотступ в макете: для того чтобы текст в ячейке автоматически смещался вправо в зависимости от уровня иерархии, в свойствах соответствующей ячейки макета необходимо установить флаг АвтоОтступ.
  3. Экспорт данных: при выгрузке сформированного табличного документа в сторонние табличные форматы интерактивная структура группировок может теряться в зависимости от версии платформы и формата файла.
← На главную