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