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