Как в отчете 1С выводить разные формулы в колонках группировок и в общих итогах?

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

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

Рассмотрим причины ограничений стандартных механизмов и разберем подробные способы реализации такого поведения как в Системе компоновки данных (СКД), так и в отчетах на базе Построителя отчета (Универсального отчета).

Почему в Построителе отчета и Универсальном отчете нельзя задать разные формулы штатно

Проанализируем архитектуру механизма ПостроительОтчета. В языке запросов 1С и механизме построителя агрегатные функции секции ИТОГИ применяются единообразно ко всей выборке. Нельзя в рамках единого текста запроса указать одну формулу расчета для группировки по колонкам и другую — для уровня ОБЩИЕ.

Кроме того, ПостроительОтчета не разделяет контекст вычисления ресурсов по горизонтали и вертикали кросс-таблицы. Если требуется сохранить стандартную форму Универсального отчета, приходится применять обходные пути.

Решение 1. Настройка различных формул для ресурса в СКД

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

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

  1. Откроем схему компоновки данных и перейдем на вкладку Ресурсы.
  2. Добавим требуемое поле из окна Доступные поля в правую таблицу ресурсов первый раз.
  3. В колонке Выражение пропишем стандартную формулу для периодов (например, Сумма(СуммаОборот)).
  4. В колонке Рассчитывать по... отметим флажками конкретные группировки строк и группировку колонок (например, Период), оставив поле ОбщиеИтоги выключенным.
  5. Добавим это же поле в список ресурсов повторно второй строкой.
  6. В колонке Выражение второй строки укажем формулу, которая должна действовать для итоговой колонки (например, 0, Среднее(СуммаОборот) или вызов экспортной функции общего модуля).
  7. В колонке Рассчитывать по... второй строки выберем исключительно ОбщиеИтоги (или нужную итоговую группировку).

СКД автоматически объединит вывод этого поля в одну и ту же колонку макета: внутри периодов будет применяться первое выражение, а в итоговых столбцах — второе.

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

МойМодульСервер.РассчитатьИтог(Сумма(СуммаОборот), Количество(Ссылка))

Решение 2. Программная постобработка табличного документа

Если переделывать отчет на СКД нельзя из-за требований интерфейса или жесткой привязки к Универсальному отчету, применим постобработку сформированного табличного документа.

Посмотрим на пример алгоритма постобработки:

  1. Формируем отчет штатным методом построителя в ТабличныйДокумент.
  2. Определяем номера колонок с общими итогами (через поиск заголовка с помощью ТабличныйДокумент.НайтиТекст() или по именам областей макета).
  3. Обходим строки табличного документа в цикле, считываем значения из ячеек детальных периодов, производим расчет по формуле и перезаписываем ячейку итога.

Рассмотрим пример кода постобработки ячеек итогового столбца:


// Предположим, что колонка итогов найдена и имеет номер НомерКолонкиИтога
// ПерваяКолонкаПериода и ПоследняяКолонкаПериода - границы колонок с данными

Для НомерСтроки = НачальнаяСтрокаДанных По ТабличныйДокумент.ВысотаТаблицы Цикл
    ОбластьИтога = ТабличныйДокумент.Область(НомерСтроки, НомерКолонкиИтога);
    
    СуммаПериодов = 0;
    КоличествоЗаполненных = 0;
    
    Для НомерКолонки = ПерваяКолонкаПериода По ПоследняяКолонкаПериода Цикл
        ЗначениеЯчейки = ТабличныйДокумент.Область(НомерСтроки, НомерКолонки).Значение;
        Если ТипЗнч(ЗначениеЯчейки) = Тип("Число") И ЗначениеЯчейки <> 0 Тогда
            СуммаПериодов = СуммаПериодов + ЗначениеЯчейки;
            КоличествоЗаполненных = КоличествоЗаполненных + 1;
        КонецЕсли;
    КонецЦикла;
    
    // Рассчитываем значение по специальной формуле (например, среднее)
    Если КоличествоЗаполненных > 0 Тогда
        ИтоговоеЗначение = СуммаПериодов / КоличествоЗаполненных;
    Иначе
        ИтоговоеЗначение = 0;
    КонецЕсли;
    
    // Перезаписываем значение и текст ячейки
    ОбластьИтога.Значение = ИтоговоеЗначение;
    ОбластьИтога.Текст = Формат(ИтоговоеЗначение, "ЧДЦ=2");
КонецЦикла;

Решение 3. Ручной вывод результата построителя отчета

Вместо прямого вызова ПостроительОтчета.Вывести(ТабличныйДокумент) можно использовать метод ПостроительОтчета.Выполнить(). Полученный объект РезультатЗапроса обходится выборками по группировкам:


Выборка = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока Выборка.Следующий() Цикл
    // Программный вывод строк и расчет нестандартных итогов перед выводом области в ТабличныйДокумент
КонецЦикла;

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

← На главную