Каталог решений - Применение рекурсивных функций при построении отчета с иерархией

Применение рекурсивных функций при построении отчета с иерархией

Применение рекурсивных функций при построении отчета с иерархией

В наличии

Особенностью справочников в восьмерке является возможность их неограниченной иерархии. Тот, кто имел дело только с 7.7, столкнувшись с теоретической возможностью сколь угодного числа вложений, может стать в тупик: как организовать обход группировок, когда заранее не известно их число…

Категория:

Описание

Сформулируем задачу: имеются некие данные, сгруппированные по значению справочника, например, регистр «ПартииТоваровНаСкладах» с измерением типа «Номенклатура». Нам необходимо вывести отчет с отражением иерархической структуры этого справочника, т.е., в нашем примере, сгруппировать остатки по группам и подгруппам товаров.

Особенностью справочников в восьмерке является возможность их неограниченной иерархии. Тот, кто имел дело только с 7.7, столкнувшись с теоретической возможностью сколь угодного числа вложений, может стать в тупик: как организовать обход группировок, когда заранее не известно их число?

Не буду рассматривать вариант с построителем отчета: делаем все вручную.

Посмотрим на задачу в общем: для каждого товара его иерархия – это некая последовательность данных, которую необходимо всю обойти, не зная заранее ее длины. Собственно, это классическая задача рекурсивного обхода. К сожалению, молодые программисты порой не понимают и боятся рекурсивных вызовов, но не мы с вами!

Строим процедуру на кнопке «Сформировать»:

Процедура

ДействияФормыСформировать

(

Кнопка

)

ТекстЗапроса 

= «ВЫБРАТЬ

|	ПартииТоваровНаСкладахОстатки

.

Номенклатура

,

|	ПартииТоваровНаСкладахОстатки

.

Номенклатура

.

Родитель

,

|	ПартииТоваровНаСкладахОстатки

.

КоличествоОстаток
|ИЗ
|	РегистрНакопления

.

ПартииТоваровНаСкладах

.

Остатки КАК ПартииТоваровНаСкладахОстатки

«; Запрос =

Новый 

Запрос(

ТекстЗапроса

)

;
Товары

=

З

.

Выполнить

().

Выгрузить

()

;

Итак, у нас имеется таблица остатков товаров. Добавим в нее и заполним свою колонку «Уровень»

Товары

.

Колонки

.

Добавить

(«Уровень»)

;

Для

Каждого Стр Из Товары 

Цикл

Стр

.

Уровень

=

Стр

.

Номенклатура

.

Уровень;

КонецЦикла

;

Подготовим такую же таблицу, только с остатками для всевозможных групп товаров:

Группы

=

Товары

.

СкопироватьКолонки

()

;

Для

Каждого Стр Из Товары 

Цикл

Родитель

=

Стр

.

Номенклатура

.

Родитель;
  

Пока

Родитель

<>

Справочники

.

Номенклатура

.

ПустаяСсылка

() Цикл

Нов

=

Группы

.

Добавить

()

;
    Нов

.

Номенклатура

=

Родитель;
    Нов

.

Родитель

=

Родитель

.

Родитель;
    Нов

.

Уровень

=

Родитель

.

Уровень

()

;
    Нов

.

КоличествоОстаток

=

Стр

.

КоличествоОстаток;
    Родитель

=

Родитель

.

Родитель;
  

КонецЦикла

;

КонецЦикла

;

(Понимаем, что этот модуль можно было объединить с предыдущим, но для наглядности разделяем)

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

Группы

.

Свернуть

(«Номенклатура,Родитель,Уровень»,«КоличествоОстаток»)

;

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

Макет

=

ПолучитьМакет

(«Макет»)

;
Область

=

Макет

.

ПолучитьОбласть

(«Шапка»)

;
ЭлементыФормы

.Таблица.

Вывести

(

Область

)

;

Родитель

=

Справочники

.

Номенклатура

.

ПустаяСсылка

()

;
ВывестиНоменклатуру

(

Макет

,0,

Родитель 

,

Группы

,

Товары

)

;

Область

=

Макет

.

ПолучитьОбласть

(«Подвал»)

;
ЭлементыФормы

.Таблица.

Вывести

(

Область

)

;

КонецПроцедуры

Сама функция «ВывестиНоменклатуру», как и подобает рекурсии, состоит всего из нескольких строк. Структура ее проста. Предполагается, что на текущем уровне рекурсии мы находимся в начале некоторой группы, содержащей элементы и другие подгруппы. Вначале мы выводим все товары из нашей группы, затем — рекурсивно все подгруппы.

Процедура

ВывестиНоменклатуру 

(

Макет

,

Уровень

,

Родитель

,

Группы

,

Товары

) // выводит товары для группы Родитель на текущем уровне Для

Каждого Стр Из Рез 

Цикл Если (

Стр

.

Уровень

=

Уровень

)

и

(

Стр

.

Родитель

=

Родитель

) Тогда

ВывестиСтрокуТовара

(

Макет

,

Стр

)

;
    

КонецЕсли

;
  

КонецЦикла // выводит рекурсивно подгруппы товаров для группы Родитель на текущем уровне Для

Каждого Стр Из Группы 

Цикл Если (

Стр

.

Уровень

=

Уровень

)

и

(

Стр

.

Родитель

=

Родитель

) Тогда

ВывестиСтрокуГруппы

(

Макет

,

Стр

)

;
      ВывестиНоменклатуру 

(

Макет

,

Уровень

,

Родитель

,

Группы

,

Товары

)

;
    

КонецЕсли

;
  

КонецЦикла

;

КонецПроцедуры

Стоит доопределить элементарные функции вывода строк таблицы на печать «ВывестиСтрокуТовара» и «ВывестиСтрокуГруппы», и задача решена полностью.

Напоследок, в качестве изюминки хочу предложить обратить внимание, что достаточно легко связать окраску строки группы товаров, ее название в макете с уровнем вложенности, как, например, показано на этом рисунке:

has been added to your cart:
Оформление заказа