Разработчики, работающие с типовыми конфигурациями на платформе «1С:Предприятие 8.3» (особенно с решениями на базе «1С:Зарплата и управление персоналом 3.1» и «1С:ERP Управление предприятием»), часто сталкиваются со следующей проблемой. При попытке изменить макет или схему компоновки данных (СКД) какого-либо стандартного отчета или печатной формы, внесенные изменения упорно не отображаются при формировании. Система продолжает выводить отчет в старом виде, игнорируя новые выбранные поля и настройки.
Выясняется, что платформа берет макет не напрямую из метаданных отчета, а считывает его из специального регистра сведений, где хранятся предварительно скомпилированные макеты. В этой статье мы подробно разберем, как устроен этот механизм, можно ли «декомпилировать» объект МакетКомпоновкиДанных обратно в СхемаКомпоновкиДанных, и рассмотрим практические способы решения этой задачи.
Для начала давайте разберем важную теоретическую часть, без понимания которой невозможно двигаться дальше. Очень часто разработчики путают или объединяют понятия «Схема компоновки данных» и «Макет компоновки данных». Однако это принципиально разные объекты платформы 1С.
Схема компоновки данных (СхемаКомпоновкиДанных) — это декларативное описание того, откуда и как нужно получать данные, какие существуют связи между наборами данных, какие параметры доступны пользователю, какие роли определены для полей и какова структура отчета по умолчанию. Схему можно сравнить с исходным кодом программы.
Макет компоновки данных (МакетКомпоновкиДанных) — это результат «компиляции» схемы компоновки данных и конкретных настроек (переданных пользователем или установленных по умолчанию). Процесс генерации макета выполняет специальный объект платформы — КомпоновщикМакетаКомпоновкиДанных.
Разберем подробнее, почему макет компоновки — это «билет в один конец»:
Таким образом, восстановить исходный объект СхемаКомпоновкиДанных из готового скомпилированного объекта МакетКомпоновкиДанных невозможно. В нем просто физически отсутствуют исходные данные. Программное изменение самого макета (например, добавление новых полей в сформированные области) чрезвычайно затруднено из-за его сложной низкоуровневой структуры. Любые манипуляции с полями и настройками необходимо производить исключительно на уровне схемы СКД и настроек компоновщика до момента генерации макета.
В конфигурации «1С:Зарплата и управление персоналом 3.1» (и в некоторых других современных конфигурациях) для ускорения работы системы печатные формы документов и отчеты часто формируются с использованием механизма кэширования. Компоновка сложного отчета (например, расчетного листка или кадрового приказа) — это операция, требующая больших вычислительных ресурсов процессора.
Чтобы исключить повторную компиляцию при каждой печати документа, разработчики 1С применили следующий алгоритм:
МакетКомпоновкиДанных.МакетыКомпоновкиДанных в виде ресурса с типом ХранилищеЗначения.ПроцессорКомпоновкиДанных.Именно поэтому, какие бы изменения вы ни вносили в схему компоновки отчета в конфигураторе или через расширение, система будет игнорировать их до тех пор, пока в регистре сведений хранится старый кэшированный макет.
Если вам нужно применить изменения схемы один раз в процессе разработки или при обновлении базы данных у клиента, самым простым и безопасным решением будет ручное удаление записи из кэширующего регистра.
Проанализируем по шагам, как это сделать:
e1cib/list/РегистрСведений.МакетыКомпоновкиДанных.При следующем формировании отчета система обнаружит, что кэшированного макета в регистре нет. Она автоматически обратится к вашей новой измененной схеме компоновки, сгенерирует актуальный макет, запишет его в кэш и выведет верный результат на экран.
Если вы разрабатываете тиражное решение или расширение конфигурации, заставлять пользователей вручную чистить регистры сведений — плохая практика. В таком случае необходимо автоматизировать процесс очистки кэша при первом запуске новой версии вашей доработки.
Рассмотрим пример кода, который можно поместить в обработчик обновления информационной базы или в процедуру при начале работы системы (с проверкой версии):
Процедура СброситьКэшМакетаКомпоновки(ИмяОтчета) Экспорт
НаборЗаписей = РегистрыСведений.МакетыКомпоновкиДанных.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ИмяОбъекта.Установить(ИмяОтчета);
Попытка
НаборЗаписей.Записать();
ЗаписьЖурналаРегистрации("ОбновлениеМакетовСКД",
УровеньЖурналаРегистрации.Информация,
,
,
"Успешно очищен кэш макета для отчета: " + ИмяОтчета);
Исключение
ЗаписьЖурналаРегистрации("ОбновлениеМакетовСКД",
УровеньЖурналаРегистрации.Ошибка,
,
,
"Ошибка при очистке кэша макета для отчета: " + ИмяОтчета + ". Описание: " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
Этот код создает пустой набор записей с отбором по имени вашего отчета и записывает его, тем самым полностью удаляя старый кэшированный макет из регистра. При первом же открытии отчета пользователем система выполнит перекомпиляцию на основе новой схемы.
В некоторых случаях вам может потребоваться полностью обойти механизм кэширования макетов — например, если структура отчета динамически меняется в зависимости от сложных внешних факторов, и кэшировать его в принципе нельзя. Для этого мы можем перехватить процесс получения макета с помощью механизма расширений 1С.
Выясним, как выглядит стандартный программный обход кэша. Вместо вызова типовой функции, возвращающей макет из регистра, мы пишем собственную процедуру генерации макета «на лету»:
Функция ПолучитьАктуальныйМакетКомпоновки(ИмяОтчета, НастройкиОтчета) Экспорт
// Получаем исходную схему напрямую из метаданных отчета, минуя любые регистры
СхемаСКД = Отчеты[ИмяОтчета].ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
// Инициализируем компоновщик макета
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
// Выполняем компоновку схемы с переданными настройками
Попытка
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаСКД, НастройкиОтчета);
Возврат МакетКомпоновки;
Исключение
ВызватьИсключение "Не удалось скомпоновать макет отчета. Описание ошибки: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
КонецФункции
При использовании данного способа следует учитывать, что время формирования отчета может незначительно увеличиться, так как компиляция макета будет выполняться при каждом запуске. Однако это гарантирует стопроцентную актуальность выводимых данных и структуры отчета при любых изменениях в схеме компоновки.