При разработке отчетов на базе системы компоновки данных (СКД) разработчики часто используют вызовы экспортных функций общих модулей в выражениях вычисляемых полей или пользовательских полей. В типовом интерактивном режиме такой отчет может работать безупречно. Однако при переходе к программному формированию (например, в процедуре ПриКомпоновкеРезультата) разработчик сталкивается с непредвиденной ошибкой на этапе итерации по процессору компоновки данных.
Проанализируем типовую ситуацию, выясним внутреннюю причину такого поведения платформы 1С:Предприятие и рассмотрим способы устранения проблемы, а также альтернативные архитектурные решения.
Рассмотрим пример: в схеме компоновки данных создано вычисляемое поле, где объединяются две даты, а между ними вставляется перенос строки с помощью функции общего модуля:
Строка(Формат(ГоденОт, "ДФ = дд.ММ.гг")) + КДВНашеВсяко.СимволыПС() + Строка(Формат(ГоденДо, "ДФ = дд.ММ.гг"))
В интерактивном режиме отчет успешно выводится на экран. Однако как только мы переопределяем стандартную обработку в модуле отчета для вставки горизонтальных разделителей страниц или кастомной постобработки табличного документа, при вызове ПроцессорКомпоновки.Следующий() возникает исключение:
Ошибка исполнения отчета
по причине:
Ошибка при вызове метода контекста (Следующий)
по причине:
Ошибка компоновки данных
по причине:
Ошибка получения данных
по причине:
Ошибка в выражении
по причине:
Синтаксическая ошибка "КДВНашеВсяко.СимволыПС"
Выясним причину: почему платформа воспринимает имя общего модуля как синтаксическую ошибку? Дело в том, что в целях безопасности вызов внешних функций встроенного языка из выражений СКД по умолчанию заблокирован. Когда отчет строится платформой автоматически (стандартная обработка не отключена), система компоновки данных неявно инициализирует процессор компоновки с разрешением на вызов внешних функций. Но когда разработчик создает объект ПроцессорКомпоновкиДанных вручную, вступает в силу значение по умолчанию соответствующего параметра инициализации.
Разберем синтаксис метода Инициализировать объекта ПроцессорКомпоновкиДанных. Данный метод принимает следующие параметры:
Ложь.Именно четвертый параметр отвечает за то, разрешено ли СКД обращаться к функциям общих модулей конфигурации. Если его не указать, СКД считает вызов КДВНашеВсяко.СимволыПС() недопустимым выражением и выдает ошибку синтаксиса.
Посмотрим на исправленный фрагмент кода процедуры ПриКомпоновкеРезультата:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
// Явно передаем четвертый параметр Истина:
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.НачатьВывод();
ЭлементРезультата = ПроцессорКомпоновки.Следующий();
Пока ЭлементРезультата <> Неопределено Цикл
Если ЭлементРезультата.ЗначенияПараметров.Количество() = 1 Тогда
Если ЭлементРезультата.ЗначенияПараметров[0].Значение = "Разорвать" Тогда
ДокументРезультат.ВывестиГоризонтальныйРазделительСтраниц();
КонецЕсли;
КонецЕсли;
ПроцессорВывода.ВывестиЭлемент(ЭлементРезультата);
ЭлементРезультата = ПроцессорКомпоновки.Следующий();
КонецЦикла;
ПроцессорВывода.ЗакончитьВывод();
ДокументРезультат.АвтоМасштаб = Истина;
КонецПроцедуры
Обратите внимание: даже если в коде используется пакетный вывод через метод ПроцессорВывода.Вывести(ПроцессорКомпоновки), параметр ВозможностьИспользованияВнешнихФункций всё равно необходимо передавать при инициализации процессора компоновки.
Для корректного вызова функции из схемы компоновки данных необходимо соблюдать ряд системных требований к самому общему модулю:
Экспорт.ИмяМодуля.ИмяФункции(Параметры).Вызов процедур и функций конфигурации из СКД снижает общую производительность отчета, так как требует переключения контекстов и исключает оптимизацию на уровне СУБД. Вставить перевод строки можно стандартными возможностями самой схемы компоновки:
Enter внутри строковых кавычек. Платформа воспринимает перенос строки внутри литерала как полноценный символ перевода каретки:
Строка(Формат(ГоденОт, "ДФ = дд.ММ.гг")) + "
" + Строка(Формат(ГоденДо, "ДФ = дд.ММ.гг"))
СимволПС, отключить его видимость для пользователя, а в колонке «Выражение» указать Символы.ПС. После этого в выражении вычисляемого поля достаточно написать:
Строка(Формат(ГоденОт, "ДФ = дд.ММ.гг")) + &СимволПС + Строка(Формат(ГоденДо, "ДФ = дд.ММ.гг"))
В исходном примере программный вывод использовался ради вставки горизонтального разделителя страниц. Однако во многих случаях в СКД это можно настроить декларативно без написания кода в ПриКомпоновкеРезультата:
Перед группировкой или После группировки.Использование типовых механизмов разрыва страниц позволяет оставить СтандартнаяОбработка = Истина, избежав ручного обхода элементов в цикле и связанных с этим ошибок инициализации.