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