Иерархию подразделений в отчёте ЗУП 3 удобнее всего получать не новым запросом в каждом отчёте, а собственным представлением в механизме общих наборов данных ЗарплатаКадрыОбщиеНаборыДанных. Уровень подразделения считается по регистру сведений ПодчиненностьПодразделенийОрганизаций как количество вышестоящих подразделений, а предки раскладываются по колонкам Уровень1…УровеньN. После этого в любом отчёте на СКД достаточно сослаться на временную таблицу Представления_ИерархияПодразделений и соединиться с ней по подразделению.

Ниже: как устроен механизм представлений, запрос иерархии, подключение своего представления расширением и использование в СКД.

Задача: структура по уровням в одной строке

Руководители почти всегда хотят видеть не только подразделение сотрудника, но и всю цепочку: дирекция → департамент → отдел → группа. В справочнике это дерево, а в отчёте нужна плоская таблица:

ПодразделениеУровень 1Уровень 2Уровень 3Уровень 4
ДирекцияДирекция
Коммерческий департаментДирекцияКоммерческий департамент
Отдел продажДирекцияКоммерческий департаментОтдел продаж
Группа оптаДирекцияКоммерческий департаментОтдел продажГруппа опта

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

Как работает механизм представлений ЗУП

Кто писал отчёты в ЗУП 3, видел в схемах запросы к таблицам вида Представления_КадровыеДанныеСотрудников или Представления_ПлановыеНачисленияСотрудников. Таких таблиц в базе нет: перед выполнением отчёт вызывает

1С
ЗарплатаКадрыОбщиеНаборыДанных.ЗаполнитьОбщиеИсточникиДанныхОтчета(ЭтотОбъект);

и механизм заменяет каждую «представленческую» временную таблицу настоящим запросом. Параметры представлению передаются прямо в тексте запроса СКД — условиями вида "ИмяПараметра" = Значение в ГДЕ. Подбор запроса по имени представления выполняет функция ПолучитьЗапросПоПредставлению модуля ЗарплатаКадрыОбщиеНаборыДанныхРасширенный.

В типовой поставке уже есть представления для штатного расписания, текущей кадровой расстановки, фактических отпусков, плановых начислений и удержаний, стажей, кадровых данных сотрудников и физлиц, данных учёта времени, начисленных доходов НДФЛ, а также универсальные ТаблицаРегистра, СрезПоследних, СрезПервых. Иерархии подразделений среди них нет — добавим.

Запрос иерархии подразделений

Регистр ПодчиненностьПодразделенийОрганизаций хранит для каждого подразделения всех его вышестоящих. Значит, глубина подразделения — это количество записей с ним в измерении Подразделение.

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

// 2. Все предки подразделения плюс оно само
ВЫБРАТЬ
	Подчиненность.Подразделение КАК Подразделение,
	Подчиненность.ВышестоящееПодразделение КАК Предок
ПОМЕСТИТЬ ВТПредки
ИЗ
	РегистрСведений.ПодчиненностьПодразделенийОрганизаций КАК Подчиненность

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	Подразделения.Ссылка,
	Подразделения.Ссылка
ИЗ
	Справочник.ПодразделенияОрганизаций КАК Подразделения
;

// 3. Раскладываем предков по колонкам уровней
ВЫБРАТЬ
	Предки.Подразделение КАК Подразделение,
	МАКСИМУМ(ВЫБОР КОГДА Глубина.Глубина = 0 ТОГДА Предки.Предок КОНЕЦ) КАК Уровень1,
	МАКСИМУМ(ВЫБОР КОГДА Глубина.Глубина = 1 ТОГДА Предки.Предок КОНЕЦ) КАК Уровень2,
	МАКСИМУМ(ВЫБОР КОГДА Глубина.Глубина = 2 ТОГДА Предки.Предок КОНЕЦ) КАК Уровень3
ПОМЕСТИТЬ Представления_ИерархияПодразделений
ИЗ
	ВТПредки КАК Предки
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТГлубина КАК Глубина
		ПО Предки.Предок = Глубина.Подразделение
СГРУППИРОВАТЬ ПО
	Предки.Подразделение
ИНДЕКСИРОВАТЬ ПО
	Подразделение

Перед использованием проверьте на своей базе, не хранит ли регистр запись подразделения «на само себя»: если хранит, глубину нужно уменьшить на единицу, а второй блок ОБЪЕДИНИТЬ ВСЕ убрать.

Колонки уровней генерируются кодом — так их число задаётся параметром:

1С
// Возвращает текст полей Уровень1..УровеньN для запроса иерархии.
Функция ТекстПолейУровней(КоличествоУровней)

	Поля = Новый Массив;
	Для НомерУровня = 1 По КоличествоУровней Цикл
		Поля.Добавить(СтрШаблон(
			"МАКСИМУМ(ВЫБОР КОГДА Глубина.Глубина = %1 ТОГДА Предки.Предок КОНЕЦ) КАК Уровень%2",
			Формат(НомерУровня - 1, "ЧН=0; ЧГ="), Формат(НомерУровня, "ЧГ=")));
	КонецЦикла;

	Возврат СтрСоединить(Поля, "," + Символы.ПС);

КонецФункции

Для ограничения по правам добавьте РАЗРЕШЕННЫЕ в первый запрос пакета, если представление вызвано с параметром ТолькоРазрешенные.

Подключаем представление расширением

Типовой модуль править не нужно — делаем расширение, заимствуем общий модуль ЗарплатаКадрыОбщиеНаборыДанныхРасширенный и перехватываем функцию подбора запроса аннотацией &Вместо. Логика перехвата:

  1. Если имя временной таблицы — Представления_ИерархияПодразделений, собираем свой Запрос с текстом из предыдущего раздела, параметры читаем из переданной структуры (ТолькоРазрешенные, Уровень) через ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры.
  2. Иначе вызываем ПродолжитьВызов(...) с теми же параметрами — работает типовая реализация.

Сигнатуру перехватчика копируйте из функции своего релиза ЗУП один в один: состав параметров между релизами может отличаться, а расширение с несовпадающей сигнатурой не подключится.

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

Использование в отчёте на СКД

В запрос набора данных добавляем «заглушку» представления с параметрами в условии:

Запрос 1С
ВЫБРАТЬ
	ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка) КАК Подразделение,
	ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка) КАК Уровень1,
	ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка) КАК Уровень2,
	ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка) КАК Уровень3
ПОМЕСТИТЬ Представления_ИерархияПодразделений
ИЗ
	Справочник.ПодразделенияОрганизаций КАК Подразделения
ГДЕ
	"ТолькоРазрешенные" = ИСТИНА
	И "Уровень" = 3
;

Дальше соединяем основную выборку с Представления_ИерархияПодразделений по полю Подразделение, выводим Уровень1…Уровень3 и группируем по ним в настройках СКД. В модуле отчёта перед компоновкой вызываем ЗаполнитьОбщиеИсточникиДанныхОтчета — в типовых отчётах ЗУП это уже сделано, в своих не забудьте.

Сколько колонок закладывать

Можно генерировать колонки динамически под фактическую глубину структуры, но тогда придётся править и функцию замены представлений в тексте запроса — ещё одна точка перехвата. На практике я закладываю фиксированное число уровней с запасом (шесть–восемь) и в настройках отчёта не вывожу пустые колонки. Структуры глубже восьми уровней в реальных организациях почти не встречаются.

Типичные ошибки

  • Корневые подразделения выпадают. Глубину считают только по регистру, без левого соединения со справочником: у корня записей в регистре нет.
  • Сдвиг уровней на единицу. Регистр в вашем релизе может включать подразделение в его собственных вышестоящих — проверьте на данных.
  • Представление не подменяется. Имя временной таблицы в СКД не совпадает с обрабатываемым в расширении или отчёт не вызывает ЗаполнитьОбщиеИсточникиДанныхОтчета.
  • Расширение не применяется после обновления. Изменилась сигнатура типовой функции — сверяйте её при каждом обновлении ЗУП.

Такие отчёты для кадровиков и руководства я делаю в рамках доработки ЗУП; общий подход к построению сложных схем описан на странице отчётов на СКД.

Итог

  • Иерархию подразделений в ЗУП выгодно оформить как своё представление механизма общих наборов данных.
  • Уровень считается по регистру ПодчиненностьПодразделенийОрганизаций, предки раскладываются по колонкам через ВЫБОР по глубине.
  • Подключение — расширением с &Вместо и ПродолжитьВызов для остальных представлений.
  • В СКД достаточно «заглушки» Представления_ИерархияПодразделений с параметрами в ГДЕ и соединения по подразделению.
  • Фиксированное число уровней с запасом проще в сопровождении, чем динамические колонки.