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