Работа с Системой компоновки данных (СКД) часто требует выхода за рамки стандартных выражений языка запросов. Разработчики используют вычисляемые поля, чтобы внедрить сложную бизнес-логику, математические расчеты или обращения к функциям общих модулей. Однако при переходе от стандартного вывода отчета к программному формированию часто возникают трудночитаемые ошибки. Проанализируем основные причины возникновения сбоев в СКД и разберем пошаговое решение проблем, связанных с внешними функциями и типизацией данных.
Представим ситуацию: в схеме компоновки данных создано вычисляемое поле, выражение которого обращается к экспортной функции общего модуля, например: опМодуль.КореньКвадратный(Диаметр * 10). При формировании отчета через стандартную кнопку "Сформировать" все работает корректно, но стоит перенести код в модуль объекта для программного управления параметрами, как система выдает ошибку: "Синтаксическая ошибка: опМодуль.КореньКвадратный".
Выясним причину. При программном формировании отчета мы вручную создаем объекты ПроцессорКомпоновкиДанных и МакетКомпоновкиДанных. По умолчанию система безопасности 1С ограничивает вызов внешних функций из кода СКД, если это не разрешено явно. Разберем, как правильно инициализировать процессор компоновки.
Рассмотрим стандартный (нерабочий в данном контексте) код инициализации:
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
Для того чтобы функции общих модулей стали доступны, необходимо использовать четвертый параметр метода Инициализировать. Этот параметр называется ВозможностьИспользованияВнешнихФункций. Рассмотрим исправленный вариант кода:
// Параметры метода:
// 1. МакетКомпоновки
// 2. ВнешниеНаборыДанных (необязательно)
// 3. ДанныеРасшифровки (необязательно)
// 4. ВозможностьИспользованияВнешнихФункций (Истина для разрешения вызовов)
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, , , Истина);
После установки этого флага в значение Истина, движок СКД получит разрешение на обращение к серверным методам конфигурации. Важно помнить, что функция в общем модуле должна иметь признак Экспорт, а сам модуль должен быть доступен на сервере.
Даже если функция успешно вызывается, можно столкнуться со следующей ошибкой: "Ошибка в выражении: Неверные параметры '*'". Проанализируем ситуацию: выражение вида Утечка * опМодуль.КореньКвадратный(Давление) внезапно перестает работать, хотя по отдельности поля выводятся нормально.
Причина кроется в типах данных. В 1С функции общих модулей часто используются не только для расчетов, но и для форматирования вывода. Рассмотрим типичную ошибку внутри общего модуля:
Функция КореньКвадратный(Значение) Экспорт
Результат = Sqrt(Значение);
Возврат Формат(Результат, "ЧДЦ=2"); // ОШИБКА! Возвращается строка
КонецФункции
Функция Формат() всегда возвращает значение типа Строка. В языке выражений СКД невозможно умножить число (поле Утечка) на строку. Движок СКД ожидает, что результатом функции будет число, если оно участвует в математической операции. Чтобы решить проблему, необходимо разделять логику вычислений и логику оформления.
Рекомендуется возвращать из функции чистое числовое значение:
Функция КореньКвадратный(Значение) Экспорт
// Возвращаем только число
Возврат Sqrt(Число(Значение));
КонецФункции
Если же вам необходимо ограничить количество знаков после запятой в отчете, используйте вкладку "Наборы данных" или "Вычисляемые поля" в СКД, настроив свойство "Оформление" -> "Формат" для конкретного поля. Это позволит сохранить числовой тип данных для итогов и при этом красиво отобразить результат пользователю.
Проанализируем еще несколько моментов, которые помогут избежать ошибок и ускорить работу отчетов:
POW(Число, Степень). Корень квадратный — это возведение в степень 0.5. Запись POW(ПолеДавление, 0.5) будет работать быстрее, так как не требует переключения контекста выполнения между СКД и встроенным языком 1С.Давление придет NULL, внешняя функция может вызвать исключение. Используйте конструкцию ЕстьNull(Давление, 0) прямо в выражении вычисляемого поля.ИмяФункции(). Если модуль не глобальный, обращение идет через точку: ИмяМодуля.ИмяФункции().Таким образом, для корректной работы сложных вычисляемых полей при программном выводе необходимо соблюдать два правила: правильно инициализировать процессор компоновки и строго следить за тем, чтобы функции возвращали ожидаемые типы данных (числа для расчетов, а не отформатированные строки).