При разработке отчетов на базе Системы компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда отчет прекрасно работает при нажатии стандартной кнопки «Сформировать», но выдает ошибку при попытке программного вывода через ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент. Одна из самых неприятных ошибок — «Ошибка получения данных в выражении», часто указывающая на математические операторы, например, символ умножения *.
В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем программный код вывода и рассмотрим пошаговые инструкции по исправлению выражений в вычисляемых полях и ресурсах.
Для начала рассмотрим типовой код программного формирования отчета, который обычно приводит к возникновению ошибки. Проанализируем последовательность действий в коде:
ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
// Создаем макет компоновки с помощью компоновщика макета
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
// Инициализируем процессор компоновки
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
// Вывод в табличный документ
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
Результат = Новый ТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(Результат);
Попытка
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;
Проблема заключается в том, что при программном исполнении ПроцессорКомпоновкиДанных работает более строго, чем стандартный механизм платформы. Если в интерактивном режиме СКД может «простить» неопределенные значения или пустые ссылки, то при использовании метода Вывести() любая некорректная операция с данными в выражении приводит к исключению.
Выясним основную причину ошибки в выражении типа ВНаличии * Объем. Если в базе данных для какой-либо позиции номенклатуры не заполнен остаток или не указан объем, соответствующее поле будет содержать значение NULL.
В языке выражений СКД операция умножения числа на NULL дает NULL, но на определенных этапах компоновки макета, особенно при расчете итогов по группировкам, это вызывает сбой получения данных. Чтобы избежать этого, нам необходимо гарантировать, что в выражении всегда участвуют числа.
Решение: Используем функцию ЕСТЬNULL. Изменим выражение в вычисляемом поле следующим образом:
ЕСТЬNULL(ВНаличии, 0) * ЕСТЬNULL(Объем, 0)
Это обеспечит корректное вычисление даже в тех строках, где данные заполнены частично.
Проанализируем ситуацию, когда вычисляемое поле выводится не только в детальных записях, но и в итогах (группировках). Если мы просто добавили вычисляемое поле, но не описали его на вкладке «Ресурсы», СКД попытается применить выражение ВНаличии * Объем напрямую к итогам. Это логическая ошибка: система не понимает, нужно ли ей перемножить сумму остатков на сумму объемов (что неверно) или сложить результаты произведений каждой строки.
Рассмотрим правильную настройку ресурсов:
ОбщийОбъем).Сумма(ЕСТЬNULL(ВНаличии, 0) * ЕСТЬNULL(Объем, 0)).Такой подход гарантирует, что на уровне итогов значения будут суммироваться корректно, а процессор компоновки не встретит неопределенности при расчете макета.
Важный нюанс работы СКД: вычисляемое поле не может ссылаться на другое вычисляемое поле в своем выражении. Рассмотрим пример: у нас есть вычисляемое поле Цена и мы хотим создать второе поле Стоимость, написав Цена * Количество. Это приведет к ошибке получения данных, так как на момент расчета Стоимости значение Цены еще не определено в контексте процессора данных.
Как правильно поступить в этой ситуации:
(СуммаДокумента / Коэффициент) * Количество.Иногда ошибка возникает из-за того, что поля, участвующие в выражении, не включены в итоговый макет или имеют неподходящий тип. Например, если Объем является дополнительным сведениям с типом данных «Значение свойств объектов», он может возвращать строку или неопределено.
Проверим типы данных. В наборе данных (запросе) рекомендуется принудительно приводить числовые показатели к нужному типу:
ВЫБРАТЬ
ВЫРАЗИТЬ(Таблица.Объем КАК ЧИСЛО(15, 3)) КАК Объем,
Таблица.ВНаличии КАК ВНаличии
ИЗ
...
Также убедимся, что поля ВНаличии и Объем доступны для системы. Если вы используете собственный макет оформления, проверьте, что эти поля присутствуют в выбранных полях компоновщика настроек. Если поля не выбраны, процессор компоновки не сможет получить их значения для вычисления формулы «на лету».
Обратим внимание на четвертый параметр метода Инициализировать() объекта ПроцессорКомпоновкиДанных. В коде автора он установлен в Истина:
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
Этот параметр отвечает за возможность использования внешних функций (функций общих модулей). Если ваше выражение вызывает какую-то функцию, которая недоступна на сервере или в контексте которой возникла ошибка, это также приведет к сбою. Если вычисления простые (математические), попробуйте временно установить этот параметр в Ложь, чтобы исключить влияние внешних вызовов.
Подводя итог, пройдемся по пунктам, которые помогут нам избавиться от ошибки «*» при программном выводе:
ЕСТЬNULL(Поле, 0).Неопределено.Соблюдение этих правил позволит вашему отчету работать стабильно как в интерактивном, так и в программном режиме формирования.