При разработке отчетов в Системе компоновки данных (СКД) часто возникает задача вычисления входящих и исходящих остатков (нарастающего итога) по полям, которые не являются измерениями регистров накопления. Например, если группировка выполняется по реквизиту Склад, отсутствующему в измерениях виртуальной таблицы остатков, получение готовых остатков из регистра напрямую становится невозможным.
В этой статье мы подробно разберем, почему штатное применение функции ВычислитьВыражение для расчета сальдо может вызывать ошибки в итогах группировок, и проанализируем проверенные варианты решения этой задачи.
Рассмотрим стандартную попытку рассчитать нарастающий итог для детальных записей отчета. В СКД добавляют два вычисляемых поля — СальдоНаНачалоКоличество и СальдоНаКонецКоличество, назначив им следующие выражения в ресурсах:
Для начального остатка:
ВычислитьВыражение("Сумма(Количество)", , , "Первая", "Предыдущая")
Для конечного остатка:
ВычислитьВыражение("Сумма(Количество)", , , "Первая", "Текущая")
Для детальных записей отчета такие выражения строят красивую колонку нарастающего итога. Однако при вычислении итогов по группировке Склад возникают искажения: сальдо первого склада становится входящим сальдо для второго склада, накапливаясь нарастающим итогом по всему отчету. Указание явных параметров группировки, таких как ВычислитьВыражение("Количество", "Склад", "Группировка", "Текущая"), возвращает только отдельные записи, но не дает правильного свертывания конечных итогов по всей иерархии.
Проанализируем практический подход, который позволяет получить точный результат без сложного переноса остатков между детальными записями. Идея заключается в разделении начального сальдо и текущих оборотов еще на этапе формирования набора данных.
Разберем алгоритм по шагам:
Склад, Регистратор, Количество.
ВЫБРАТЬ
ТвояТаблица.Склад КАК Склад,
ТвояТаблица.Регистратор КАК Регистратор,
ТвояТаблица.Период КАК Период,
ВЫБОР
КОГДА ТвояТаблица.Период < &ДатаНачала
ТОГДА ТвояТаблица.Количество
ИНАЧЕ 0
КОНЕЦ КАК НачальныйОстатокКоличество,
ВЫБОР
КОГДА ТвояТаблица.Период >= &ДатаНачала
ТОГДА ТвояТаблица.Количество
ИНАЧЕ 0
КОНЕЦ КАК ОборотКоличество
ИЗ
РегистрНакопления.Продажи КАК ТвояТаблица
СальдоНаНачалоКоличество указываем выражение: Сумма(НачальныйОстатокКоличество)СальдоНаКонецКоровень вычисляем итоговый остаток как сумму входящего сальдо и всех оборотов: Сумма(НачальныйОстатокКоличество) + Сумма(ОборотКоличество)Рассмотрим стандартный механизм платформы 1С, предназначенный для автоматического расчета остатков по произвольным группировкам. Если набору данных передаются поля периода и сальдо, можно настроить правила их свертки на вкладке Наборы данных в колонке Роль.
НачальныйОстаток.КонечныйОстаток.Имя дополнительного поля связываем остатки с соответствующим полем периода (например, ПериодSec).При такой настройке платформа 1С автоматически корректно рассчитывает и сворачивает начальные и конечные остатки по любым произвольным группировкам отчета, включая реквизиты, не являющиеся измерениями регистра.
Если необходимо использовать функцию ВычислитьВыражение в вычисляемых полях или ресурсах, важно учитывать зависимость вычислений от порядка строк. Выражения с ключевыми словами Первая, Предыдущая или Текущая рассчитываются строго в текущем порядке сортировки записей.
Чтобы исключить ошибки при изменении пользовательской сортировки в отчете, всегда передавайте выражение явной сортировки в третьем параметре функции:
ВычислитьВыражение("Сумма(Количество)", , "Период Возр", "Первая", "Текущая")
Для корректного подсчета итогов в родительских группировках по нарастающим итогам дочерних элементов применяется двухуровневое агрегирование с помощью функции ВычислитьВыражениеСГруппировкойМассив:
Сумма(ВычислитьВыражениеСГруппировкойМассив("ВычислитьВыражение('Сумма(Количество)', , , 'Первая', 'Текущая')", "Регистратор"))
Выясним причины, по которым расчет сальдо через вычисляемые выражения ресурсов может давать непредсказуемый результат:
NULL (например, при левых соединениях или отсутствии движений), контекстное окно вычисления вызовет ошибку или вернет NULL для всего ресурса. Обрабатывайте такие значения функцией ЕСТЬNULL().ВычислитьВыражение внутрь другого. Для передачи вычисленных данных на верхние уровни иерархии используйте массив группировок.ВычислитьВыражение запрещено использовать в групповом отборе той группировки, по которой выполняется расчет.В сложных отчетах со множественными отборами и динамическими иерархиями самым надежным и производительным решением остается расчет сальдо на уровне запроса с помощью виртуальных таблиц остатков и оборотов.