Как вывести результат отчета СКД в две параллельные вертикальные группировки?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет IT и автоматизация бизнеса
← На главную

При разработке печатных форм и аналитических отчетов в 1С (например, инвентаризационных описей, списков номенклатуры с остатками или ценников) часто возникает задача так называемой «газетной верстки». Она заключается в том, чтобы вывести один плоский список данных не в одну длинную колонку, а разбить его на две или более параллельные вертикальные группировки, расположенные рядом. Рассмотрим подробнее, какими способами можно реализовать такое поведение средствами системы компоновки данных (СКД).

Способ 1. Использование структуры «Таблица» в СКД с расчетом координат

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

  1. Нумерация строк в запросе: Сформируем во временной таблице набор данных с порядковым номером каждой строки. Для этого проанализируем запрос с автонумерацией через соединение:
    
    ВЫБРАТЬ
        Остатки.Номенклатура КАК Номенклатура,
        Остатки.КоличествоОстаток КАК Количество
    ПОМЕСТИТЬ ВТ_Остатки
    ИЗ
        РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК Остатки
    ;
    
    ВЫБРАТЬ
        Т1.Номенклатура КАК Номенклатура,
        Т1.Количество КАК Количество,
        КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Т2.Номенклатура) КАК НомерСтроки
    ИЗ
        ВТ_Остатки КАК Т1
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Остатки КАК Т2
            ПО Т1.Номенклатура >= Т2.Номенклатура
    СГРУППИРОВАТЬ ПО
        Т1.Номенклатура,
        Т1.Количество
    
  2. Вычисление координат в «Вычисляемых полях» СКД: Перейдем на вкладку «Вычисляемые поля» и добавим два служебных поля:

    Поле НомерКолонки — определяет, в какую из колонок попадет запись (для 2 колонок):

    (НомерСтроки - 1) % 2

    Поле НомерСтрокиВКолонке — определяет позицию строки по вертикали:

    (НомерСтроки - 1) / 2
  3. Настройка ресурсов: Чтобы поля Номенклатура и Количество корректно отображались в ячейках таблицы, назначим для них выражения ресурсов:

    Для Номенклатура: Максимум(Номенклатура)

    Для Количество: Сумма(Количество)

  4. Настройка структуры отчета:

    В схеме компоновки данных добавим элемент Таблица.

    В секцию Строки таблицы добавим группировку по полю НомерСтрокиВКолонке.

    В секцию Колонки таблицы добавим группировку по полю НомерКолонки.

    В выбранных полях таблицы укажем наши ресурсы: Номенклатура и Количество.

    В условном оформлении скрываем отображение служебных заголовков НомерКолонки и НомерСтрокиВКолонке, установив текст заголовка пустым или отключив их видимость.

Способ 2. Использование функции языка выражений СКД «ВычислитьВыражениеСГруппировкойМассив»

Рассмотрим применение мощной функции языка выражений СКД — ВычислитьВыражениеСГруппировкойМассив. Она позволяет собрать массив значений из всей выборки группировки и адресоваться к элементам со смещением.

Разберем по шагам алгоритм работы с данной функцией:

  1. В схеме создаем вычисляемое поле МассивНоменклатуры с выражением: ВычислитьВыражениеСГруппировкойМассив("Номенклатура", "Номенклатура")
  2. Для получения элементов второй колонки создаем пользовательское или вычисляемое поле НоменклатураКолонка2, извлекая элемент со сдвигом на половину длины массива: МассивНоменклатуры[НомерСтроки + Смещение]

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

Способ 3. Преобразование структуры данных в запросе (Самосоединение)

Проанализируем ситуацию, когда необходимо зафиксировать структуру еще до момента вывода СКД, сформировав строки вида Номенклатура1, Количество1, Номенклатура2, Количество2 прямо в источнике данных.

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

Способ 4. Программный вывод через событие «ПриКомпоновкеРезультата»

Если требуется полный контроль над шириной областей и переносом страниц при печати, используем программную компоновку отчета в модуле объекта:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Инициализируем схему и настройки
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
    
    // Выводим результат во временный табличный документ
    ВременныйТабДок = Новый ТабличныйДокумент;
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ВременныйТабДок);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
    // Рассчитываем разделение на 2 колонки
    ВсегоСтрок = ВременныйТабДок.ВысотаТаблицы;
    СтрокВКолонке = Окр(ВсегоСтрок / 2, 0, РежимОкругления.ОкруглениеВверх);
    
    // Переносим левый блок
    ОбластьЛево = ВременныйТабДок.Область(1, 1, СтрокВКолонке, ВременныйТабДок.ШиринаТаблицы);
    ДокументРезультат.ВставитьОбласть(ОбластьЛево, ДокументРезультат.Область(1, 1));
    
    // Переносим правый блок со смещением по колонкам
    СмещениеКолонки = ВременныйТабДок.ШиринаТаблицы + 2;
    ОбластьПраво = ВременныйТабДок.Область(СтрокВКолонке + 1, 1, ВсегоСтрок, ВременныйТабДок.ШиринаТаблицы);
    ДокументРезультат.ВставитьОбласть(ОбластьПраво, ДокументРезультат.Область(1, СмещениеКолонки));
    
КонецПроцедуры

Сравнение методов и рекомендации

Выясним причину выбора конкретного варианта в зависимости от условий задачи:

  1. Таблица СКД (Способ 1) — оптимальна, если нужно решение чисто в пользовательском режиме или типовой конфигурации без внесения изменений в код модулей.
  2. Самосоединение в запросе (Способ 3) — наилучший выбор по быстродействию и удобству для последующего экспорта в сторонние форматы.
  3. Программный вывод (Способ 4) — рекомендуется, если отчет формирует специализированную печатную форму со строгими требованиями к разрывам страниц и макету.
← На главную