Как программно изменить макет компоновки данных в 1С или получить из него схему СКД?

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

Разработчики, работающие с типовыми конфигурациями на платформе «1С:Предприятие 8.3» (особенно с решениями на базе «1С:Зарплата и управление персоналом 3.1» и «1С:ERP Управление предприятием»), часто сталкиваются со следующей проблемой. При попытке изменить макет или схему компоновки данных (СКД) какого-либо стандартного отчета или печатной формы, внесенные изменения упорно не отображаются при формировании. Система продолжает выводить отчет в старом виде, игнорируя новые выбранные поля и настройки.

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

Разбор понятий: Схема компоновки данных против Макета компоновки данных

Для начала давайте разберем важную теоретическую часть, без понимания которой невозможно двигаться дальше. Очень часто разработчики путают или объединяют понятия «Схема компоновки данных» и «Макет компоновки данных». Однако это принципиально разные объекты платформы 1С.

Схема компоновки данных (СхемаКомпоновкиДанных) — это декларативное описание того, откуда и как нужно получать данные, какие существуют связи между наборами данных, какие параметры доступны пользователю, какие роли определены для полей и какова структура отчета по умолчанию. Схему можно сравнить с исходным кодом программы.

Макет компоновки данных (МакетКомпоновкиДанных) — это результат «компиляции» схемы компоновки данных и конкретных настроек (переданных пользователем или установленных по умолчанию). Процесс генерации макета выполняет специальный объект платформы — КомпоновщикМакетаКомпоновкиДанных.

Разберем подробнее, почему макет компоновки — это «билет в один конец»:

  1. В процессе компоновки макета платформа объединяет текст запроса из схемы, наложенные пользователем отборы, выбранные поля и структуру вывода в единый, оптимизированный SQL-подобный запрос к СУБД.
  2. В макете больше нет информации об исходных таблицах схемы, которые не были задействованы, нет описания доступных полей, связей наборов данных и других метаданных СКД.
  3. Макет содержит уже готовые шаблоны табличного документа (области, ячейки, параметры макета) для вывода конкретного результата.

Таким образом, восстановить исходный объект СхемаКомпоновкиДанных из готового скомпилированного объекта МакетКомпоновкиДанных невозможно. В нем просто физически отсутствуют исходные данные. Программное изменение самого макета (например, добавление новых полей в сформированные области) чрезвычайно затруднено из-за его сложной низкоуровневой структуры. Любые манипуляции с полями и настройками необходимо производить исключительно на уровне схемы СКД и настроек компоновщика до момента генерации макета.

Почему изменения в ЗУП 3.1 не вступают в силу? Механизм кэширования

В конфигурации «1С:Зарплата и управление персоналом 3.1» (и в некоторых других современных конфигурациях) для ускорения работы системы печатные формы документов и отчеты часто формируются с использованием механизма кэширования. Компоновка сложного отчета (например, расчетного листка или кадрового приказа) — это операция, требующая больших вычислительных ресурсов процессора.

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

  1. При первом обращении к отчету система берет исходную схему и настройки, компонует готовый МакетКомпоновкиДанных.
  2. Этот готовый макет сериализуется и записывается в регистр сведений МакетыКомпоновкиДанных в виде ресурса с типом ХранилищеЗначения.
  3. При последующих вызовах печати или отчета система не выполняет компоновку заново. Она делает быстрый запрос к регистру сведений, считывает готовый макет из кэша и сразу передает его в ПроцессорКомпоновкиДанных.

Именно поэтому, какие бы изменения вы ни вносили в схему компоновки отчета в конфигураторе или через расширение, система будет игнорировать их до тех пор, пока в регистре сведений хранится старый кэшированный макет.

Способ 1. Ручной сброс кэша макетов в режиме «1С:Предприятие»

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

Проанализируем по шагам, как это сделать:

  1. Запустите информационную базу в режиме «1С:Предприятие» с правами администратора.
  2. Откройте функции для технического специалиста (в старых версиях — «Все функции»).
  3. Найдите в списке разделов Регистры сведений и перейдите к регистру Макеты компоновки данных. Альтернативный вариант — перейти по прямой ссылке: e1cib/list/РегистрСведений.МакетыКомпоновкиДанных.
  4. В открывшемся списке найдите строку, соответствующую вашему изменяемому отчету или печатной форме. Ориентируйтесь по имени объекта.
  5. Удалите эту запись из регистра (если кнопка удаления заблокирована, нажмите Еще — Разблокировать форму/редактирование).

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

Способ 2. Программная очистка кэша при обновлении

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

Рассмотрим пример кода, который можно поместить в обработчик обновления информационной базы или в процедуру при начале работы системы (с проверкой версии):


Процедура СброситьКэшМакетаКомпоновки(ИмяОтчета) Экспорт
    
    НаборЗаписей = РегистрыСведений.МакетыКомпоновкиДанных.СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.ИмяОбъекта.Установить(ИмяОтчета);
    
    Попытка
        НаборЗаписей.Записать();
        ЗаписьЖурналаРегистрации("ОбновлениеМакетовСКД",
            УровеньЖурналаРегистрации.Информация,
            ,
            ,
            "Успешно очищен кэш макета для отчета: " + ИмяОтчета);
    Исключение
        ЗаписьЖурналаРегистрации("ОбновлениеМакетовСКД",
            УровеньЖурналаРегистрации.Ошибка,
            ,
            ,
            "Ошибка при очистке кэша макета для отчета: " + ИмяОтчета + ". Описание: " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;
    
КонецПроцедуры

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

Способ 3. Перехват логики и принудительное формирование макета

В некоторых случаях вам может потребоваться полностью обойти механизм кэширования макетов — например, если структура отчета динамически меняется в зависимости от сложных внешних факторов, и кэшировать его в принципе нельзя. Для этого мы можем перехватить процесс получения макета с помощью механизма расширений 1С.

Выясним, как выглядит стандартный программный обход кэша. Вместо вызова типовой функции, возвращающей макет из регистра, мы пишем собственную процедуру генерации макета «на лету»:


Функция ПолучитьАктуальныйМакетКомпоновки(ИмяОтчета, НастройкиОтчета) Экспорт
    
    // Получаем исходную схему напрямую из метаданных отчета, минуя любые регистры
    СхемаСКД = Отчеты[ИмяОтчета].ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    
    // Инициализируем компоновщик макета
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    
    // Выполняем компоновку схемы с переданными настройками
    Попытка
        МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаСКД, НастройкиОтчета);
        Возврат МакетКомпоновки;
    Исключение
        ВызватьИсключение "Не удалось скомпоновать макет отчета. Описание ошибки: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
    КонецПопытки;
    
КонецФункции

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

← На главную