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