Часто при работе с Системой Компоновки Данных (СКД) возникает ситуация, когда итоговые суммы корректно отображаются для самых нижних уровней группировки, но для родительских групп и общих итогов ячейки остаются пустыми. Первое, что приходит на ум, — проверить настройки ресурсов в СКД. Однако причина может быть и не в них. Рассмотрим подробно, почему так происходит и как найти источник проблемы, особенно в случаях, когда отчет выводится не стандартным образом, а через программную обработку.
Проанализируем типичный случай: в отчете есть иерархия группировок, например, Организация -> Вид денежных средств -> Банковский счет. Итоги по сумме выводятся для каждого банковского счета, а вот для "Вида денежных средств" и "Организации" — нет. Давайте разберемся в возможных причинах и способах их устранения.
Прежде чем погружаться в код, всегда стоит начать с базовых проверок в самой схеме компоновки данных. Это наиболее частая причина отсутствия итогов. Откроем схему и перейдем на вкладку "Ресурсы".
Выражение ресурса. Убедимся, что в поле "Выражение" указано именно то поле, которое нужно суммировать (например, СуммаОборот), а не агрегатная функция вроде СУММА(СуммаОборот). СКД сама применяет нужную функцию (Сумма, Количество, Среднее и т.д.) к указанному полю при расчете итогов.
Поле "Рассчитывать по...". Это ключевая настройка для управления итогами. Она указывает СКД, для каких группировок необходимо вычислять данный ресурс.
Обработка значений NULL. Если в данных могут встречаться неопределенные значения (NULL), это может влиять на расчет итогов. Например, при левом соединении наборов данных числовые поля из правой таблицы могут быть NULL. СКД может по-разному их обрабатывать. Чтобы избежать проблем, рекомендуется оборачивать такие поля в функцию ЕСТЬNULL() прямо в тексте запроса или в вычисляемом поле. Например: ЕСТЬNULL(ТаблицаОстатков.Сумма, 0) КАК Сумма. Это гарантирует, что все строки будут участвовать в расчете.
Если после тщательной проверки этих настроек итоги так и не появились, значит, проблема, скорее всего, находится глубже — на уровне программного кода, который выводит результат СКД.
Очень часто СКД используется не для прямого вывода отчета на форму, а как мощный конструктор запросов. Программист получает результат компоновки в виде таблицы или дерева значений, а затем программно обрабатывает эти данные и выводит их в свой элемент управления на форме, например, в ДеревоЗначений. В этом случае ответственность за расчет и отображение итогов полностью ложится на код разработчика, а настройки ресурсов в СКД могут вообще не использоваться. Для изучения примеров программного формирования отчетов можно использовать подборку примеров программной работы с СКД.
В рассматриваемой нами теме автор предоставил фрагмент кода, который подтверждает именно такой сценарий. Давайте его проанализируем.
// ... код после получения данных из СКД ...
//VID( считаем итоги по добавленным колонкам,13.11.202
Для Каждого ПериодКолонка Из ДанныеФормы.КолонкиПериодов Цикл
найдКолонка = ДанныеФормы.ДеревоСчета.Колонки.Найти(ПериодКолонка.Представление);
Если найдКолонка = Неопределено Тогда
//Сообщить("Колонка не найдена!");
Иначе
СчитатьСуммы(ДанныеФормы.ДеревоСчета.Строки, ПериодКолонка.Представление);
КонецЕсли;
КонецЦикла;
//VID)-----------------------------------------------------------------------
Возврат ДанныеФормы;
Процедура СчитатьСуммы(Строки, Колонка)
Для Каждого СтрокаДерева Из Строки Цикл
// Если мы в строке, у неё нет итогов, пропустим
Если СтрокаДерева.Строки.Количество() = 0 Тогда
Продолжить;
КонецЕсли;
СчитатьСуммы(СтрокаДерева.Строки,Колонка);
// Для текущей записи вычислим сумму строк колонки
СтрокаДерева[Колонка] = СтрокаДерева.Строки.Итог(Колонка);
КонецЦикла;
КонецПроцедуры
Разберем, что здесь происходит:
СчитатьСуммы.СчитатьСуммы использует рекурсию. Она обходит дерево "снизу вверх". Сначала она вызывает саму себя для дочерних строк (СчитатьСуммы(СтрокаДерева.Строки,Колонка);).СтрокаДерева.Строки.Итог(Колонка) и записывается в соответствующую ячейку.Этот механизм должен корректно рассчитывать все итоги. Если он не работает, значит, где-то в логике есть ошибка. Проблема уже не в СКД, а в этом конкретном алгоритме.
Когда мы поняли, что проблема в коде, а не в настройках, нужно приступить к его отладке. Вот пошаговый план действий.
Найти точку входа. В первую очередь, нужно найти место в коде, где результат работы СКД преобразуется и помещается в ДеревоЗначений на форме. Это поможет понять, в каком виде данные приходят из компоновщика и как строится первоначальная иерархия в дереве.
Поставить точку останова. Установим точку останова внутри процедуры СчитатьСуммы, прямо на строке СтрокаДерева[Колонка] = СтрокаДерева.Строки.Итог(Колонка);.
Запустить отладку. Сформируем отчет и дождемся, когда выполнение остановится на нашей точке. Теперь мы можем проанализировать переменные.
СтрокаДерева. Какая именно строка сейчас обрабатывается? Это строка нижнего уровня или группировка?СтрокаДерева.Строки. Есть ли у текущей строки дочерние элементы? Если это группировка, для которой не считается итог, то, возможно, эта коллекция по какой-то причине пуста, хотя должна содержать дочерние строки.СтрокаДерева.Строки.Итог(Колонка). Можно сделать это в окне "Вычислить выражение" (Shift+F9). Какое значение возвращает этот метод? Если 0, то либо в дочерних строках нет числовых данных, либо произошла ошибка.Проверить типы данных. Важный момент: чтобы метод Итог() сработал корректно, колонка в ДеревеЗначений, по которой считается сумма, должна иметь числовой тип. Если при создании колонок дерева ей по ошибке был назначен строковый тип, метод Итог() вернет 0. Убедимся, что тип данных колонки — Число.
Проверить логику условия. В коде есть проверка: Если СтрокаДерева.Строки.Количество() = 0 Тогда Продолжить; КонецЕсли;. Она пропускает строки самого нижнего уровня (детальные записи), что правильно. Но, возможно, из-за ошибки при заполнении дерева у некоторых группировок верхнего уровня коллекция дочерних строк Строки оказывается пустой, и тогда для них расчет итога просто не выполняется.
Итог: Пройдясь по этим шагам с отладчиком, вы с высокой вероятностью обнаружите, почему рекурсивная процедура не отрабатывает для верхних уровней иерархии. Проблема может быть в неверном построении самого дерева, в неправильных типах данных колонок или в логической ошибке внутри самого алгоритма подсчета сумм.