Разработка отчетов на Системе компоновки данных (СКД) в 1С — это мощный инструмент, который, однако, скрывает в себе множество неочевидных нюансов. Один из таких подводных камней — совместное использование Выражения представления для вычисляемого поля и расчет Итогов (Ресурсов) по этому же полю. Многие разработчики сталкиваются с ситуацией, когда при добавлении функции форматирования в выражение представления итоги по группировкам начинают рассчитываться некорректно — СКД как будто выводит значение только по первой строке группировки или вовсе ломает математические расчеты. В этой статье мы подробно разберем, почему так происходит, и рассмотрим эффективные способы решения этой проблемы.
Рассмотрим типичный сценарий. В отчете СКД создается вычисляемое поле, например, ПродолжительностьРемонта. В самом выражении вычисляемого поля рассчитывается разность дат в секундах:
РАЗНОСТЬДАТ(ДатаНачала, ДатаОкончания, "СЕКУНДА")
Чтобы вывести эти секунды пользователю в удобном и красивом виде (например, "2 дн. 4 ч. 15 мин."), разработчик заполняет колонку Выражение представления для этого поля, вызывая функцию общего модуля:
ПродолжительностьВДнях(ПродолжительностьРемонта)
Далее это же поле добавляется на вкладку Ресурсы, чтобы получить суммарное время ремонта по группировкам. В поле выражения ресурса пишется формула:
ПродолжительностьВДнях(Сумма(ПродолжительностьРемонта))
На первый взгляд логика безупречна. Однако при формировании отчета оказывается, что общие итоги и итоги по группировкам рассчитываются неверно. Вместо суммы секунд всех ремонтов, преобразованной в дни, СКД выводит представление, соответствующее только первой строке в группировке. Если же убрать выражение представления у вычисляемого поля, то числовые итоги (секунды) начинают суммироваться абсолютно правильно.
Выясним причину такого поведения платформы 1С. Дело в том, как СКД обрабатывает приоритеты вычислений. Когда для поля задано выражение представления, СКД пытается использовать его не только для детальных записей, но и для расчета представления итогов на уровне группировок. При расчете итогов группировки СКД обращается к значению вычисляемого поля. Так как это детальное поле, на уровне группировки оно не имеет единственного значения (их там множество). В этот момент система берет значение из первой попавшейся строки группировки, применяет к нему выражение представления и выводит результат в качестве итога. Таким образом, математический расчет ресурса игнорируется, и мы получаем неверные данные.
Проанализируем доступные и наиболее эффективные варианты решения этой проблемы.
Самый простой и архитектурно правильный способ — разделить хранение числовых данных и их визуальное отображение. Для этого нам нужно отказаться от использования выражения представления в самом вычисляемом поле и перенести всю логику форматирования непосредственно в настройки ресурсов.
Выполним следующие шаги:
ПродолжительностьРемонта и полностью очистим колонку Выражение представления. Теперь это поле на уровне детальных записей будет возвращать обычное число (секунды).ПродолжительностьРемонта в колонке Выражение укажем формулу, которая сначала агрегирует (суммирует) числовые данные, а затем преобразует их с помощью функции общего модуля:
ПродолжительностьВДнях(Сумма(ПродолжительностьРемонта))
При таком подходе СКД сначала математически точно сложит все секунды на уровне группировки, а затем передаст полученное итоговое число в функцию общего модуля ПродолжительностьВДнях, которая вернет красивую строку для вывода в отчет.
Если вам по каким-то причинам критически важно иметь в схеме как чистое числовое значение, так и его строковое представление (например, для последующей сортировки, построения диаграмм или условного оформления), мы можем разделить их на два отдельных вычисляемых поля.
Рассмотрим этот алгоритм:
ПродолжительностьЧисло. В выражении укажем разность дат в секундах. Это поле мы будем использовать только для математических расчетов и вывода итогов.ПродолжительностьСтрока. В выражении представления этого поля укажем вызов нашей функции общего модуля: ПродолжительностьВДнях(ПродолжительностьЧисло).ПродолжительностьЧисло с выражением:
ПродолжительностьВДнях(Сумма(ПродолжительностьЧисло))
ПродолжительностьСтрока, а для группировок — ресурс ПродолжительностьЧисло.Этот способ позволяет избежать конфликтов типов в СКД, так как строковое представление применяется только там, где это действительно необходимо, не ломая математику суммирования.
Использование макетов полей — это профессиональный подход, который позволяет полностью отделить логику получения данных от дизайна интерфейса отчета. Этот метод незаменим, если вы хотите, чтобы в самой модели данных СКД ресурс оставался числом (чтобы по нему работала стандартная сортировка, строились графики), но на уровне отображения в таблице выводилась отформатированная строка.
Разберем по шагам, как настроить макет оформления для вывода представления:
ПродолжительностьРемонта обычным числовым ресурсом с выражением Сумма(ПродолжительностьРемонта). Не пишите никаких функций общего модуля ни в выражении представления, ни в выражении ресурса.ПродолжительностьРемонта. Если необходимо форматировать и группировки, укажем нужный тип области (например, ОбщийИтог или конкретную группировку).ЗначениеСекунд.ЗначениеСекунд укажем выражение, вызывающее нашу функцию общего модуля:
ИмяОбщегоМодуля.ПродолжительностьВДнях(ЗначениеСекунд)
При формировании отчета СКД выполнит все арифметические операции в числовом формате, а на этапе рендеринга таблицы перехватит значение ресурса, передаст его в макет и отобразит результат работы функции общего модуля. Это гарантирует максимальную производительность и корректность расчетов.
Иногда использование функций общих модулей нежелательно или невозможно (например, в базовых версиях или при жестких требованиях к производительности). Посмотрим на пример, как можно преобразовать разность дат в секундах в удобный временной формат (например, привести к дате или выделить дни) непосредственно встроенными средствами языка выражений СКД.
Для простых вычислений и приведения секунд к эквиваленту даты/времени можно использовать следующее выражение в СКД:
ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), "Секунда", РАЗНОСТЬДАТ(ДатаНачала, ДатаОкончания, "Секунда"))
Полученное значение будет иметь тип Дата. В условном оформлении или в формате самого поля мы можем задать маску отображения, например, ДФ='ЧЧ:мм:сс'. Это позволит вывести время красиво, а СКД сможет без проблем агрегировать такие данные на уровне ресурсов.
Подводя итог, отметим, что для корректного расчета ресурсов в СКД всегда важно контролировать типы данных. Если ваше выражение представления возвращает строку, СКД не сможет математически сложить эти значения на уровне группировок. Используйте перенос форматирующих функций в выражения ресурсов или настраивайте макеты оформления — это позволит вам создавать красивые, функциональные и, главное, математически точные отчеты.