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

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

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

Анализ проблемы и выбор метода решения

Основная сложность состоит в том, что СКД обрабатывает данные последовательно. Когда выводится заголовок группировки, система еще не знает, какие строки войдут в эту группу и какими будут итоговые значения. Прямое обращение к ресурсу (итоговому полю) из макета заголовка вернет либо ошибку, либо пустое значение.

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

Рассмотрим пошаговый алгоритм решения этой задачи.

Шаг 1: Подготовка макета в СКД

Первым делом необходимо подготовить сам отчет в конфигураторе.

  1. Откройте схему компоновки данных вашего отчета.
  2. Перейдите на вкладку "Макеты".
  3. Создайте макет заголовка для той группировки, в которую нужно вывести итог. Для этого выделите нужную группировку в структуре отчета (на вкладке "Настройки"), нажмите правую кнопку мыши и выберите "Новый макет заголовка".
  4. В созданном макете определите ячейку, где будет отображаться итоговое значение. Задайте для этой ячейки параметр. Например, назовем его СуммаИтогПоГруппировке. Важно, чтобы у этой ячейки в свойствах было установлено свойство "Заполнение" = "Параметр".

Теперь СКД знает, что в эту ячейку при формировании отчета нужно будет подставить значение параметра СуммаИтогПоГруппировке. Наша задача — вычислить это значение и передать его в ячейку.

Шаг 2: Программная обработка результата отчета

Всю основную логику мы реализуем в коде модуля формы отчета. Нам понадобится обработчик события ПриКомпоновкеРезультата. Это событие срабатывает как раз в тот момент, когда данные уже скомпонованы, но результат еще не выведен на экран.

Давайте проанализируем код, который решает нашу задачу.


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    // Отменяем стандартную обработку, так как мы будем формировать результат сами
    СтандартнаяОбработка = Ложь;

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

Процедура УстановитьПараметрыМакета(Элемент, ДокументРезультат)
    
    // Если у текущего элемента есть вложенные элементы (т.е. это группировка)
    Если Элемент.Элементы.Количество() > 0 Тогда
    
        // 4. Вычисляем итог для текущей группировки
        // Рассчитываем значение ресурса "Сумма" для текущей группировки
        МассивИтогов = Элемент.ВычислитьВыражениеСГруппировкойМассив("Сумма(СуммаДокумента)", "Контрагент");
        
        // Проверяем, что результат получен
        Если МассивИтогов.Количество() > 0 Тогда
            ИтоговаяСумма = МассивИтогов[0].Значение;
            
            // 5. Находим ячейку в табличном документе и устанавливаем параметр
            // Обходим все области макета, связанные с текущим элементом
            Для Каждого Область Из Элемент.ПолучитьОбласти() Цикл
                Если Область.ТипМакета = ТипМакетаКомпоновкиДанных.ЗаголовокГруппировки Тогда
                    // Ищем нашу ячейку по имени параметра
                    НайденнаяЯчейка = Область.Область.НайтиТекст("СуммаИтогПоГруппировке");
                    Если НайденнаяЯчейка <> Неопределено Тогда
                        // Устанавливаем вычисленное значение
                        НайденнаяЯчейка.Параметр = "СуммаИтогПоГруппировке";
                        НайденнаяЯчейка.Текст = Формат(ИтоговаяСумма, "ЧДЦ=2; ЧН=0.00");
                    КонецЕсли;
                КонецЕсли;
            КонецЦикла;
        КонецЕсли;
    
        // 6. Рекурсивно обходим дочерние элементы
        Для Каждого ВложенныйЭлемент Из Элемент.Элементы Цикл
            УстановитьПараметрыМакета(ВложенныйЭлемент, ДокументРезультат);
        КонецЦикла;
    КонецЕсли;

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

Разбор кода по шагам

Давайте подробнее разберем, что происходит в приведенном коде.

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

    МассивИтогов = Элемент.ВычислитьВыражениеСГруппировкойМассив("Сумма(СуммаДокумента)", "Контрагент");

    Разберем её параметры:

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

    Функция возвращает массив, так как группировок с таким именем может быть несколько. В нашем случае для каждой итерации элемента мы получаем итог именно по текущей группировке, поэтому берем первый элемент массива МассивИтогов[0].Значение.

  5. Поиск и заполнение ячейки: Получив итоговое значение, мы должны найти соответствующую ячейку в уже сформированном табличном документе. Мы перебираем области макета, связанные с текущим элементом (Элемент.ПолучитьОбласти()), находим макет заголовка (ТипМакета = ТипМакетаКомпоновкиДанных.ЗаголовокГруппировки) и в нем ищем ячейку по тексту-имени параметра, который мы задали на Шаге 1. Найдя ячейку, мы заменяем её текст на отформатированное итоговое значение.
  6. Рекурсия: Процедура вызывает саму себя для всех вложенных элементов. Это позволяет обработать все уровни вложенности группировок в отчете.

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

← На главную