Как использовать ВычислитьВыражение в СКД для расчета переходящих остатков

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Управленческий учет IT и автоматизация бизнеса
← На главную

В разработке отчетов на системе компоновки данных (СКД) часто возникает задача, когда значение в текущей строке должно зависеть от результата вычислений в предыдущей строке. Классический пример — расчет «входящего» остатка, который равен «исходящему» остатку предыдущего периода или документа. В этой статье мы подробно разберем, как использовать мощную функцию ВычислитьВыражение() для решения подобных задач на примере отчета по расходам и оплатам.

Постановка задачи: логика переходящего остатка

Рассмотрим ситуацию, когда у нас есть три колонки в отчете: ПоступилоРасходов, Оплачено и Неоплачено. Наша цель — реализовать следующую математическую схему:

  1. Для первой строки: Неоплачено = ПоступилоРасходов - Оплачено.
  2. Для второй строки: значение ПоступилоРасходов должно стать равным значению Неоплачено из первой строки.
  3. Для всех последующих строк: исходящий остаток (Неоплачено) предыдущей записи становится входящим остатком (ПоступилоРасходов) текущей.

Проанализируем данные. Если в первой строке мы имели поступление 937 873,61 и оплату 296 283,05, то остаток составит 641 590,56. Этот остаток должен перекочевать в поле поступления следующей строки. Традиционными средствами запроса SQL реализовать такую «шахматку» бывает сложно, поэтому мы обратимся к ресурсам СКД.

Разбор функции ВычислитьВыражение

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


ВычислитьВыражение(Выражение, Группировка, ОбластьВычисления, Начало, Конец, Сортировка)

Для нашей задачи критически важны параметры Начало и Конец. Они определяют диапазон строк, по которым будет собираться агрегатная функция (например, сумма). Мы можем использовать ключевые слова:

Решение через расчет нарастающего итога

Хотя интуитивно хочется просто взять «значение из предыдущей строки», в СКД более стабильным и правильным методом является расчет через общую сумму от начала. Выясним причину: если мы будем просто ссылаться на предыдущую строку, которая сама является вычисляемой, может возникнуть рекурсия или ошибка последовательности расчета. Надежнее вычитать из общего прихода общую сумму всех предыдущих оплат.

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

Для поля Оплачено (в контексте входящего остатка) формула будет выглядеть так:


ВычислитьВыражение("Сумма(ПоступилоРасходов)", "ОбщаяГруппировка") - ЕстьNULL(ВычислитьВыражение("Сумма(Оплачено)", , , "Первая", "Предыдущая"), 0)

А для поля Неоплачено (текущий исходящий остаток):


ВычислитьВыражение("Сумма(ПоступилоРасходов)", "ОбщаяГруппировка") - ВычислитьВыражение("Сумма(Оплачено)", , , "Первая", "Текущая")

Проанализируем ситуацию: в первой формуле мы берем общую сумму и вычитаем из нее все оплаты до текущей строки. Это и дает нам «входящий» остаток. Во второй формуле мы вычитаем оплаты включая текущую строку, получая «исходящий» остаток.

Практический пример реализации в СКД

Посмотрим на пример настройки ресурсов, который помогает добиться корректного отображения данных, как в сообщениях форума:

  1. Откройте вкладку Ресурсы в схеме компоновки данных.
  2. Для поля ПоступилоРасходов укажите выражение:

ЕстьNull(ВычислитьВыражение("Неоплачено", "ДетальныеЗаписи", , "Предыдущая", "Предыдущая"), Сумма(ПоступилоРасходов))

Здесь мы используем функцию ЕстьNull(), чтобы для самой первой строки, где нет «предыдущей», подставилось исходное значение из запроса.

  1. Для поля Неоплачено укажите:

ЕстьNull(ВычислитьВыражение("Неоплачено", "ДетальныеЗаписи", , "Предыдущая", "Предыдущая"), Сумма(ПоступилоРасходов)) - Сумма(Оплачено)

Важное замечание: Чтобы такая схема заработала, необходимо правильно указать второй параметр функции — имя группировки (например, "ДокументОплаты" или "ДетальныеЗаписи"). Если оставить его пустым, расчет будет производиться в контексте текущей строки, что не всегда дает нужный результат при наличии иерархии.

Почему расчет может «идти криво»?

Разберем типичную проблему: первые две записи считаются верно, а далее начинаются ошибки. Это часто происходит из-за сортировки. Функция ВычислитьВыражение() крайне чувствительна к порядку строк. Если в настройках отчета пользователь изменит сортировку (например, по алфавиту вместо даты), логика «предыдущей» строки нарушится.

Чтобы зафиксировать логику расчета, рекомендуется использовать шестой параметр функции — поле сортировки. Например:


ВычислитьВыражение("Сумма(Оплачено)", , , "Первая", "Текущая", "ДатаДокумента Возр")

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

Использование в вычисляемых полях vs Ресурсы

Многие начинающие разработчики пытаются прописать эти формулы в Вычисляемых полях. Однако стоит помнить, что ВычислитьВыражение() наиболее эффективно работает именно в Ресурсах. В вычисляемых полях она выполняется на этапе компоновки результата и имеет доступ к ограниченному набору данных, тогда как в ресурсах она отрабатывает при расчете итогов по группировкам.

Если вам нужно, чтобы расчет велся по детальным записям, убедитесь, что в колонке «Рассчитывать по...» в настройках ресурсов выбраны именно детальные записи или все уровни группировок.

Подведем итоги

Мы рассмотрели, как реализовать сложную логику переходящих остатков в СКД. Подведем краткий итог по шагам:

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

← На главную