При создании сложных отчетов в Системе компоновки данных (СКД) разработчики часто сталкиваются с необходимостью вычисления производных показателей. Типичный пример — расчет финансового результата: сначала мы вычисляем прибыль как разницу между продажами и себестоимостью, а затем на основе прибыли хотим рассчитать рентабельность. Однако при попытке сослаться на уже созданное вычисляемое поле «Прибыль» в формуле поля «Рентабельность» система выдает критическую ошибку: «Поле не найдено "Прибыль"».
В этой статье мы подробно разберем, почему возникает эта ошибка, рассмотрим платформенные ограничения СКД, научимся правильно обходить их без дублирования кода, защитим наши отчеты от деления на ноль и выясним, как правильно рассчитывать подобные показатели на уровне группировок и итогов.
Ограничение на использование одного вычисляемого поля внутри другого — это базовое архитектурное правило платформы 1С. Процессор компоновки данных рассчитывает все вычисляемые поля на одном этапе — при обходе детальных записей выборки. На этом этапе вычисляемые поля еще не зарегистрированы в контексте расчета как доступные поля схемы для других выражений этого же уровня.
Это ограничение разработано разработчиками платформы целенаправленно для защиты от циклической зависимости (когда поле А ссылается на поле Б, а поле Б в свою очередь зависит от поля А), что привело бы к бесконечному циклу расчета и падению приложения.
Рассмотрим два основных и наиболее эффективных способа решения этой проблемы.
Самый простой и быстрый способ, который решает проблему «здесь и сейчас» — это подстановка исходного выражения вместо имени вычисляемого поля. Вместо использования имени Прибыль мы полностью дублируем его формулу в выражении рентабельности.
Проанализируем базовую формулу рентабельности продаж:
(СуммаПродажи - Себестоимость) / Себестоимость * 100
Этот способ прекрасно работает на уровне детальных записей, однако он имеет существенный недостаток: если формула прибыли усложнится, нам придется вручную менять ее во всех зависимых полях, что увеличивает вероятность совершения ошибки при поддержке отчета.
Мало кто знает, но в СКД существует штатный механизм, позволяющий ссылаться на созданные вычисляемые поля. Этот механизм — Пользовательские поля. Настроить его можно непосредственно в режиме конфигуратора или в режиме «1С:Предприятие» в настройках отчета.
Разберем по шагам, как это сделать:
Прибыль. Формула будет выглядеть так: Прибыль / Себестоимость * 100.Платформа вычисляет пользовательские поля на более позднем этапе компоновки, поэтому на момент их расчета все вычисляемые поля уже инициализированы и доступны для использования.
При расчете рентабельности по формуле деления на себестоимость всегда существует риск возникновения серьезной ошибки — деления на ноль. Это может произойти, если товар был списан без себестоимости, продана услуга, у которой нет материальной себестоимости, или допущена ошибка при ведении партионного учета.
Если в знаменателе окажется 0, отчет либо выдаст ошибку, либо выведет пустые значения. Чтобы избежать этого, мы обязательно должны использовать условную конструкцию ВЫБОР языка выражений СКД.
Рассмотрим правильный и безопасный вариант написания выражения:
Выбор
Когда Себестоимость = 0 Тогда 0
Иначе (СуммаПродажи - Себестоимость) / Себестоимость * 100
Конец
Этот код гарантирует стабильную работу отчета при любых исходных данных в информационной базе.
Распространенная ошибка начинающих разработчиков заключается в том, что они переносят формулу вычисляемого поля на вкладку «Ресурсы» и оставляют для нее стандартное выражение расчета итогов — Сумма(Рентабельность) или Среднее(Рентабельность). Это приводит к грубейшим математическим и экономическим ошибкам:
Сумма система просто сложит проценты рентабельности по всем строкам. На выходе мы получим бессмысленное число (например, 25% + 40% + 15% = 80%).Среднее система посчитает среднее арифметическое. Однако это не учитывает объемы продаж. Сделка на 100 рублей с рентабельностью 50% и сделка на 1 000 000 рублей с рентабельностью 10% в среднем дадут 30%, хотя реальная общая рентабельность всего оборота будет находиться на уровне чуть более 10%.Чтобы рассчитать рентабельность на уровне группировок корректно, мы должны использовать агрегатные функции для каждого показателя отдельно внутри самого выражения ресурса. Перейдем на вкладку «Ресурсы», добавим наше поле рентабельности и напишем следующее выражение:
Выбор
Когда Сумма(Себестоимость) = 0 Тогда 0
Иначе (Сумма(СуммаПродажи) - Сумма(Себестоимость)) / Сумма(Себестоимость) * 100
Конец
При такой настройке СКД сначала правильно просуммирует показатели продаж и себестоимости по всей группировке (или общему итогу отчета) и только потом произведет деление результирующих сумм. Именно такой подход является математически и экономически верным.
Часто расчетные показатели выводят бесконечную дробную часть (например, 233.3333333333...). В процессе обсуждения на форумах часто предлагают использовать функцию языка выражений СКД ОКР(). Давайте проанализируем, почему этот подход хуже, чем стандартное оформление.
Функция ОКР() физически изменяет числовое значение на этапе расчета в памяти компьютера. Если округленное значение в дальнейшем будет использоваться для расчета других показателей (например, распределения налогов, долей рынка или плановых коэффициентов), возникнет накопительная погрешность округления, и итоговые суммы в отчете перестанут «сходиться».
Правильный подход — использование системного свойства «Формат» в оформлении поля:
ЧДЦ=2; ЧЦ=15 (где ЧДЦ — число десятичных знаков, а ЧЦ — общая длина числа).В этом случае число визуально отобразится пользователю округленным до двух знаков после запятой, но в оперативной памяти компьютера оно сохранится со всей исходной точностью, что исключит любые погрешности в сопутствующих расчетах.
Если же вам действительно необходимо физически округлить число на уровне бизнес-логики, используйте правильный синтаксис функции ОКР в СКД:
Окр((СуммаПродажи - Себестоимость) / Себестоимость * 100, 2)
Обратите внимание, что указывать лишние запятые в конце функции (как часто ошибочно делают на форумах, например, Окр(Выражение, 2, )) категорически нельзя — это вызовет синтаксическую ошибку компиляции выражения СКД.