Почему возникает синтаксическая ошибка при вызове функции общего модуля в вычисляемом поле СКД и как получить значение из структуры?

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

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

Разберем детально, почему парсер языка выражений СКД выдает такую ошибку, какие системные настройки платформы за это отвечают и как правильно извлекать данные из структур.

Причина 1: Отключение внешних функций в Процессоре компоновки данных

Проанализируем базовый механизм работы СКД. По умолчанию платформа 1С в целях безопасности и производительности отключает вызов внешних процедур и функций общих модулей из выражений схемы компоновки данных. Это поведение управляется четвертым параметром метода Инициализировать() объекта ПроцессорКомпоновкиДанных.

Синтаксис метода выглядит следующим образом:

ПроцессорКомпоновкиДанных.Инициализировать(<Макет>, <ВнешниеНаборыДанных>, <ДанныеРасшифровки>, <ВозможностьИспользованияВнешнихФункций>)

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

Для программного формирования отчета с поддержкой функций общих модулей необходимо явно передавать Истина:


ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(
    МакетКомпоновки, 
    ВнешниеНаборыДанных, 
    ДанныеРасшифровки, 
    Истина // ВозможностьИспользованияВнешнихФункций
);

ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(Результат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);

Причина 2: Ограничения языка выражений СКД и вложенные вызовы

Язык выражений СКД — это специализированный встроенный интерпретатор, синтаксис которого существенно отличается от обычного языка 1С:Предприятия. Рассмотрим, с какими жесткими ограничениями сталкивается разработчик:

  1. Отсутствие поддержки обращения по индексу или через точку к результатам вычислений: конструкции вида Модуль.ПолучитьСтруктуру().ЮридическийАдрес или Модуль.ПолучитьСтруктуру()["ЮридическийАдрес"] вызывают ошибку синтаксиса.
  2. Сложности с вложенными вызовами: конструкция вида Модуль1.Функция1(Модуль2.Функция2(Поле1, Поле2), "Ключ") часто не проходит грамматический анализатор выражений СКД в зависимости от версии платформы и режима совместимости.
  3. Свойства общих модулей: если общий модуль имеет флаг Глобальный, его функции вызываются без имени модуля (только по имени функции). Если модуль не глобальный, имя модуля обязательно. При этом модуль должен быть серверным (флаг Сервер).

Способ 1: Создание функции-обертки (Рекомендуемое решение для вычисляемых полей)

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

Посмотрим на пример кода серверного модуля (например, Мой_ОбщийМодульСервер):


// Функция возвращает юридический адрес контрагента на указанную дату
Функция ПолучитьЮридическийАдресКонтрагента(Контрагент, ДатаСведений) Экспорт
    
    Если Не ЗначениеЗаполнено(Контрагент) Тогда
        Возврат "";
    КонецЕсли;
    
    Сведения = БухгалтерскийУчетПереопределяемый.СведенияОЮрФизЛице(Контрагент, ДатаСведений);
    
    Если ТипЗнч(Сведения) = Тип("Структура") И Сведения.Свойство("ЮридическийАдрес") Тогда
        Возврат Сведения.ЮридическийАдрес;
    КонецЕсли;
    
    Возврат "";
    
КонецФункции

Теперь перейдем в схему компоновки данных на вкладку Вычисляемые поля и зададим простое, прямое выражение:

Мой_ОбщийМодульСервер.ПолучитьЮридическийАдресКонтрагента(Получатель, ДатаОтправки)

Такой вызов легко разбирается парсером СКД, не требует вложенных конструкций и гарантирует корректный тип возвращаемого значения.

Способ 2: Оптимизация производительности (Кеширование и соединения)

Вызов функций общих модулей в вычисляемых полях для каждой строки отчета приводит к проблеме N+1 запросов. Если в отчете выводится 10 000 строк, функция будет вызвана 10 000 раз, что существенно замедлит формирование отчета. Разберем, как оптимизировать этот процесс:

  1. Повторное использование возвращаемых значений: если функция обращается к данным часто повторяющихся контрагентов, разместим функцию в общем модуле с установленным свойством Повторное использование возвращаемых значений в положение На время вызова или На время сеанса.
  2. Получение данных в основном запросе: наиболее производительным решением является отказ от функций общих модулей в пользу левого соединения с регистром сведений КонтактнаяИнформация прямо в тексте запроса СКД.
  3. Использование связи наборов данных: если информацию нельзя получить одним запросом, создадим второй набор данных-запрос в СКД и настроим параметры связи по контрагенту. В этом случае компоновщик данных выполнит пакетное соединение значительно быстрее построчных вызовов функции.
← На главную