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