Как сделать динамические колонки по месяцам в отчете 1С без использования СКД

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

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

В этой статье мы проанализируем ситуацию, когда у нас есть таблица значений с датами платежей и суммами, и нам нужно развернуть эти данные по месяцам в горизонтальной плоскости. Мы изучим два основных подхода: классический ручной вывод областей макета с помощью методов Вывести() и Присоединить(), а также альтернативный быстрый способ с использованием механизма ПостроительОтчета.

Подход 1: Ручной вывод динамических колонок с использованием областей макета

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

Рассмотрим подробнее, как правильно подготовить макет в конфигураторе. Нам необходимо настроить именованные области так, чтобы они разделяли таблицу как по горизонтали (строки), так и по вертикали (колонки):

  1. Создаем горизонтальные области: Выделяем строки целиком и создаем область Шапка (для заголовков таблицы) и область Строка (для вывода основных данных).
  2. Создаем вертикальные области: Выделяем колонки целиком и создаем область Старт (для статичных левых колонок, например, номенклатуры или контрагента) и область Динамическая (для колонок, которые будут размножаться по месяцам).

В результате на пересечении этих областей мы получаем четыре квадранта. В коде мы сможем обращаться к ним, используя конструкцию со специальным символом "вертикальный слэш": ПолучитьОбласть("ИмяСтроки|ИмяКолонки").

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

Посмотрим на пример программной реализации этого алгоритма:


// Шаг 1. Подготовка уникального списка месяцев для колонок отчета
ТаблицаМесяцев = ИсточникДанных.Скопировать();
ТаблицаМесяцев.Колонки.Добавить("ПериодМесяц", Новый ОписаниеТипов("Дата"));

Для Каждого СтрокаДанных Из ТаблицаМесяцев Цикл
    СтрокаДанных.ПериодМесяц = НачалоМесяца(СтрокаДанных.ДатаПлатежа);
КонецЦикла;

// Оставляем только уникальные даты месяцев и сортируем их по возрастанию
ТаблицаМесяцев.Свернуть("ПериодМесяц");
ТаблицаМесяцев.Сортировать("ПериодМесяц Возр");

// Шаг 2. Инициализация результирующего табличного документа и макета
ТабДок = Новый ТабличныйДокумент;
МакетОтчета = ПолучитьМакет("Макет");

// Шаг 3. Вывод шапки таблицы
// Выводим левую статическую часть шапки (например, заголовок "Контрагент")
ОбластьШапкаСтарт = МакетОтчета.ПолучитьОбласть("Шапка|Старт");
ТабДок.Вывести(ОбластьШапкаСтарт);

// Присоединяем динамические колонки месяцев в шапку справа
ОбластьШапкаДинамическая = МакетОтчета.ПолучитьОбласть("Шапка|Динамическая");
Для Каждого СтрМесяц Из ТаблицаМесяцев Цикл
    // Форматируем дату для вывода в формате "май.2022"
    ПредставлениеМесяца = Формат(СтрМесяц.ПериодМесяц, "ДФ='МММ.гггг'");
    ОбластьШапкаДинамическая.Параметры.ИмяМесяца = ПредставлениеМесяца;
    ТабДок.Присоединить(ОбластьШапкаДинамическая);
КонецЦикла;

// Шаг 4. Вывод строк с данными
// Получаем уникальный список ключевых объектов (например, Контрагентов)
ТаблицаСтрок = ИсточникДанных.Скопировать();
ТаблицаСтрок.Свернуть("Контрагент");

ОбластьСтрокаСтарт = МакетОтчета.ПолучитьОбласть("Строка|Старт");
ОбластьСтрокаДинамическая = МакетОтчета.ПолучитьОбласть("Строка|Динамическая");

Для Каждого СтрОбъект Из ТаблицаСтрок Цикл
    // Выводим левую статическую часть строки
    ОбластьСтрокаСтарт.Параметры.Контрагент = СтрОбъект.Контрагент;
    ТабДок.Вывести(ОбластьСтрокаСтарт);
    
    // В цикле по всем месяцам ищем сумму платежа и присоединяем ячейки справа
    Для Каждого СтрМесяц Из ТаблицаМесяцев Цикл
        ПараметрыОтбора = Новый Структура;
        ПараметрыОтбора.Вставить("Контрагент", СтрОбъект.Contragent);
        ПараметрыОтбора.Вставить("ПериодМесяц", СтрМесяц.ПериодМесяц);
        
        НайденныеСтроки = ИсточникДанных.НайтиСтроки(ПараметрыОтбора);
        СуммаОплаты = 0;
        Если НайденныеСтроки.Количество() > 0 Тогда
            СуммаОплаты = НайденныеСтроки[0].СуммаОплаты;
        КонецЕсли;
        
        // Заполняем параметр области и присоединяем ячейку к текущей строке
        ОбластьСтрокаДинамическая.Параметры.Сумма = СуммаОплаты;
        ТабДок.Присоединить(ОбластьСтрокаДинамическая);
    КонецЦикла;
КонецЦикла;

// Показываем готовый отчет пользователю
ТабДок.Показать();

Обратите внимание на ключевой момент алгоритма: метод ТабДок.Вывести() всегда начинает вывод новой строки табличного документа с левого края, в то время как метод ТабДок.Присоединить() дописывает ячейки в ту же самую строку справа. Комбинируя эти методы при обходе коллекций в циклах, мы получаем аккуратную динамическую таблицу.

Подход 2: Использование Построителя отчета для автоматического формирования шахматки

Проанализируем альтернативный вариант, который позволяет избежать сложной ручной работы с областями макета и написания вложенных циклов. Если ваш отчет не использует СКД, но вам все равно нужно быстро построить кросс-таблицу, на помощь приходит объект ПостроительОтчета. Этот объект является предшественником СКД, но до сих пор отлично работает в платформе 1С 8.3.

Построитель отчета умеет самостоятельно транспонировать строки в колонки, рассчитывать общие итоги по горизонтали и вертикали, а также автоматически форматировать вывод. Для этого достаточно передать ему правильный текст запроса и настроить группировки.

Разберем по шагам, как настроить вывод динамических колонок с помощью построителя:


// Создаем объект ПостроительОтчета
Построитель = Новый ПостроительОтчета;

// Пишем запрос, группирующий данные по периоду (месяцу)
Построитель.Текст = 
    "ВЫБРАТЬ
    |	Оплата.Контрагент КАК Контрагент,
    |	НАЧАЛОПЕРИОДА(Оплата.ДатаПлатежа, МЕСЯЦ) КАК ПериодМесяц,
    |	Оплата.СуммаОплаты КАК СуммаОплаты
    |ИЗ
    |	РегистрНакопления.Взаиморасчеты КАК Оплата
    |ИТОГИ
    |	СУММА(СуммаОплаты)
    |ПО
    |	ОБЩИЕ,
    |	Контрагент,
    |	ПериодМесяц";

// Заполняем настройки построителя
Построитель.ЗаполнитьНастройки();

// Добавляем группировку строк
ГруппировкаСтроки = Построитель.ИзмеренияСтроки.Добавить("Контрагент");

// Добавляем группировку колонок - именно это действие создаст динамические столбцы
ГруппировкаКолонки = Построитель.ИзмеренияКолонки.Добавить("ПериодМесяц");

// Выполняем расчет и выводим результат напрямую в табличный документ
ТабДок = Новый ТабличныйДокумент;
Построитель.Вывести(ТабДок);
ТабДок.Показать();

Преимущества использования Построителя отчета:

Таким образом, для простых задач ручной отрисовки макета отлично подойдет первый вариант с методами Вывести() и Присоединить(). Он дает полную свободу в оформлении ячеек и рамок. Если же вам требуется классическая сводная таблица с итогами, и вы хотите сэкономить время на разработку — смело используйте ПостроительОтчета.

← На главную