При разработке отчетов в системе компоновки данных (СКД) в формате кросс-таблиц (где присутствуют и строки, и динамические колонки) программисты регулярно сталкиваются с двумя неочевидными проблемами. Первая — как обратиться к значению ресурса из предыдущей колонки (например, получить остаток или курс за предыдущий день). Вторая — как программно или интерактивно оформить (или очистить) горизонтальные итоги в колонке «Итого», если стандартное условное оформление СКД для общих итогов упорно отказывается работать.
В этой статье мы подробно разберем обе проблемы, изучим причины их возникновения и реализуем надежные, проверенные практикой решения.
Для вычисления значений по соседним строкам многие разработчики успешно используют функцию ВычислитьВыражение. Однако, когда дело доходит до горизонтальных группировок (колонок), стандартный подход часто вызывает затруднения. Если написать выражение без указания конкретной группировки, система начнет искать «предыдущую» запись по вертикали, что приведет к неверным расчетам.
Давайте разберем, как заставить СКД анализировать именно горизонтальную ось отчета. Для этого нам понадобится правильно настроить параметры функции ВычислитьВыражение.
Синтаксис функции выглядит следующим образом:
ВычислитьВыражение(Выражение, Группировка, ОбластьВычисления, Начало, Конец)
Чтобы получить данные из предыдущей колонки, мы должны жестко привязать вычисление к имени нашей горизонтальной группировки. Настроим выражение ресурса на вкладке «Ресурсы» схемы компоновки данных:
ЕстьNull(ВычислитьВыражение("Сумма(ИмяРесурса)", "ИмяГруппировкиКолонок", , "Предыдущая", "Предыдущая"), 0)
Проанализируем ключевые параметры этого выражения подробнее:
"Сумма(ИмяРесурса)") — это выражение, которое мы хотим вычислить. Обратите внимание, что имя ресурса обязательно должно быть обернуто в агрегатную функцию (например, Сумма, Максимум, Среднее)."ИмяГруппировкиКолонок") — критически важный параметр. Здесь мы передаем строковое имя нашей группировки колонок (например, "ПериодДень" или "Номенклатура"), заданное в настройках СКД на вкладке «Структура». Именно этот параметр заставляет систему двигаться по горизонтали, а не по строкам.ОбластьВычисления) — оставляем пустым (пропускаем), так как расчет происходит в пределах текущей группировки."Предыдущая", "Предыдущая") — указывают границы расчета. В данном случае мы берем строго одну предыдущую колонку.ЕстьNull(..., 0) — необходима для обработки первой колонки отчета. Поскольку у самого первого дня (или первой колонки) нет предыдущей, функция вернет Null. Чтобы избежать пустых ячеек в отчете, мы заменяем их на нули или любое другое дефолтное значение.Используя этот метод, вам не придется писать громоздкий код постобработки в таблице значений. Все вычисления СКД сделает самостоятельно «на лету» с высокой производительностью.
Перейдем ко второй проблеме. Допустим, перед нами стоит задача: очистить или скрыть значение ресурса в итоговой колонке («Общие итоги» справа), но только для определенных строк (например, для показателя «Остаток на начало дня», так как суммировать начальные остатки за разные дни в общем итоге методологически неверно).
Интуитивно разработчики пытаются решить это через стандартное Условное оформление в СКД:
"").ВидОборотов Равно "Остаток на начало дня".Однако при формировании отчета выясняется, что оформление не применяется к правой колонке итогов. Почему так происходит? Дело в архитектурной особенности платформы 1С: область использования условного оформления «В общем итоге» в понимании СКД относится исключительно к вертикальным итогам (расположенным в самом низу таблицы). Горизонтальные же итоги (колонка «Итого» справа) система считает частью обычной группировки строк, поэтому стандартный отбор для итогов здесь не срабатывает.
Если применить оформление ко всей строке, то очистятся данные и в самих колонках по дням, что нам категорически не подходит.
Чтобы обойти это ограничение платформы без использования жестких макетов оформления и без написания кода, мы воспользуемся изящным приемом — созданием специального поля-маркера, которое будет определять, находится ли система в данный момент в процессе вывода горизонтального итога.
Рассмотрим пошагово, как реализовать этот алгоритм:
Шаг 1. Создание вычисляемого поля
Перейдем на вкладку «Вычисляемые поля» нашей схемы компоновки данных. Добавим новую строку со следующими параметрами:
ОбластьИтоговОбласть итоговШаг 2. Раздельный расчет ресурса
Теперь перейдем на вкладку «Ресурсы». Нам нужно добавить поле ОбластьИтогов в список ресурсов дважды с разными выражениями расчета для разных группировок. Это ключевой момент схемы!
Добавим первую строку ресурса:
ОбластьИтогов"ОбычнаяЯчейка" (обязательно в кавычках, как строковое значение).Номенклатура, ПериодДень). Не добавляйте сюда общие итоги!Добавим вторую строку ресурса:
ОбластьИтогов"ГоризонтальныйИтог" (в кавычках).Общие итоги.Благодаря такой настройке, при выводе обычных ячеек на пересечении строк и колонок ресурс ОбластьИтогов будет принимать значение "ОбычнаяЯчейка". Но как только СКД начнет рассчитывать и выводить колонку горизонтального общего итога, значение ресурса изменится на "ГоризонтальныйИтог".
Шаг 3. Настройка условного оформления
Теперь мы можем легко настроить точечное условное оформление. Перейдем на вкладку «Настройки», выберем вкладку «Условное оформление» и добавим новое правило:
Текст равным пустой строке "" (или настройте любой другой визуал: цвет фона, шрифт).ОбластьИтогов Равно "ГоризонтальныйИтог"ВидОборотов Равно "Остаток на начало дня" (условие по вашей аналитике строк, если очистка нужна выборочно).Везде.Сформируем отчет и проверим результат. Система безошибочно определила ячейки горизонтального итога для нужной нам строки и скрыла в них данные, оставив показатели в колонках по дням нетронутыми.
Если метод с полем-маркером по каким-то причинам вам не подходит, проанализируем еще два альтернативных варианта решения проблемы с горизонтальными итогами.
Если итоги по ресурсу не нужны вообще ни для каких строк в итоговой колонке, мы можем полностью отключить их расчет в настройках ресурсов. На вкладке «Ресурсы» для целевого числового показателя в колонке «Рассчитывать по» необходимо явно перечислить только те группировки, в которых должны выводиться данные, намеренно не добавляя туда строку Общие итоги. В таком случае колонка «Итого» справа останется пустой изначально.
Для сложных случаев, когда логика оформления зависит от внешних параметров, можно прибегнуть к программному обходу сформированного табличного документа. Для этого переопределим процедуру ПриКомпоновкеРезультата в модуле объекта отчета:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Инициализируем схему, настройки и компоновщик макета
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
// Проводим компоновку
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
// Выводим результат в табличный документ
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
// Программный обход ячеек для очистки горизонтального итога
Для НомерСтроки = 1 По ДокументРезультат.ВысотаТаблицы Цикл
// Ищем строку с нужным нам показателем
ТекстГруппировки = ДокументРезультат.Область(НомерСтроки, 1).Текст;
Если ТекстГруппировки = "Остаток на начало дня" Тогда
// Очищаем ячейку в последней колонке (где находится итог)
ШиринаТаблицы = ДокументРезультат.ШиринаТаблицы;
ДокументРезультат.Область(НомерСтроки, ШиринаТаблицы).Текст = "";
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Программный метод дает стопроцентную гибкость, однако его следует использовать с осторожностью, поскольку при изменении структуры отчета пользователем (например, при добавлении новых группировок или колонок) жестко прописанные индексы строк и колонок могут сместиться.
Именно поэтому использование вычисляемого поля-маркера, рассмотренное в третьей части статьи, считается наиболее универсальным, "красивым" и стабильным решением в рамках декларативного подхода разработки на СКД.