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