Как динамически изменить схему компоновки данных (СКД) в отчете 1С и избежать ошибки "Не установлена схема компоновки данных"?

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

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

Однако при попытке реализовать такую подмену в управляемом приложении программисты регулярно сталкиваются с каскадом ошибок: от банального нарушения контекста выполнения до системного сбоя "Не установлена схема компоновки данных" или внезапного исчезновения панели параметров с формы отчета. В этой статье мы подробно разберем, почему возникают эти проблемы, как правильно организовать архитектуру динамического отчета и какие альтернативные (и более изящные) пути решения существуют в платформе 1С.

Почему возникает ошибка "Не установлена схема компоновки данных" и пропадают параметры?

Проанализируем механику работы управляемой формы отчета. Когда пользователь открывает отчет, платформа автоматически инициализирует форму и связанный с ней компоновщик настроек на основе основной схемы компоновки данных, указанной в метаданных объекта. Если мы пытаемся подменить макет схемы в модуле объекта в событии ПриКомпоновкеРезультата, происходит рассинхронизация:

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

Кроме того, часто допускаются грубые контекстные ошибки, такие как попытка обращения к элементам управляемой формы из серверного модуля объекта, или неверное использование метода РеквизитФормыВЗначение.

---

Шаг 1. Исправление контекстных ошибок работы с формой и реквизитами

Выясним причину первой частой ошибки. Попытка вызвать метод ПолучитьФорму() или обратиться к свойству ЭлементыФормы внутри модуля объекта (например, в процедуре ПриКомпоновкеРезультата) обречена на провал. Модуль объекта выполняется строго на сервере, и он ничего "не знает" об интерфейсе и открытых формах клиента.

Чтобы управлять выбором схемы компоновки, необходимо перенести управляющий флаг (например, флажок Алименты) из разряда простого элемента управления формы в Реквизиты отчета. Сделать это очень просто в конфигураторе на вкладке "Данные" вашего отчета. После этого данный реквизит станет доступен в модуле объекта напрямую по имени.

Вторая распространенная ошибка — неверное обращение к объекту отчета из модуля формы. Посмотрим на этот пример кода:


// Ошибочный вариант
СхемаКомпоновкиДанных = РеквизитФормыВЗначение("Объект").ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");

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


// Правильный вариант
СхемаКомпоновкиДанных = РеквизитФормыВЗначение("Отчет").ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");

---

Шаг 2. Правильный алгоритм динамической смены СКД на форме

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

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


&НаСервере
Процедура ОбновитьСхемуИНастройкиНаСервере()
    
    // 1. Получаем объект отчета, чтобы добраться до его макетов
    ОтчетОбъект = РеквизитФормыВЗначение("Отчет");
    
    // 2. Выбираем нужный макет в зависимости от реквизита "Алименты"
    Если Отчет.Алименты Тогда
        НоваяСхема = ОтчетОбъект.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    Иначе
        НоваяСхема = ОтчетОбъект.ПолучитьМакет("Без_удержания");
    КонецЕсли;
    
    // 3. Помещаем схему во временное хранилище. 
    // Это критически важно для работы компоновщика в управляемых формах!
    АдресСхемы = ПоместитьВоВременноеХранилище(НоваяСхема, УникальныйИдентификатор);
    
    // 4. Создаем источник доступных настроек на основе адреса временного хранилища
    ИсточникДоступныхНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемы);
    
    // 5. Инициализируем компоновщик настроек формы новым источником
    Отчет.КомпоновщикНастроек.Инициализировать(ИсточникДоступныхНастроек);
    
    // 6. Загружаем настройки по умолчанию из новой схемы
    Отчет.КомпоновщикНастроек.ЗагрузитьНастройки(НоваяСхема.НастройкиПоУмолчанию);
    
    // 7. Важнейший шаг: принудительно обновляем пользовательские настройки на форме, 
    // чтобы параметры (Период, Организация) снова отобразились в панели отчета.
    Отчет.КомпоновщикНастроек.ЗагрузитьПользовательскиеНастройки(НоваяСхема.НастройкиПоУмолчанию.ПользовательскиеНастройки);
    
КонецПроцедуры

Этот метод полностью решает проблему "пропавших" параметров, так как мы явно принуждаем форму перестроить свое дерево настроек под структуру новой схемы.

---

Шаг 3. Обработка события в модуле объекта

Чтобы при непосредственном формировании отчета (по кнопке "Сформировать") система использовала именно выбранную схему, мы должны переопределить стандартную обработку в модуле объекта отчета:


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

---

Разбор ошибки "Поле не найдено Удержания.Результат"

Часто после успешной настройки переключения макетов разработчики сталкиваются с ошибками исполнения запроса, например: Поле не найдено "Удержания.Результат". Проанализируем, почему это происходит.

В СКД структура полей жестко завязана на текст SQL-запроса в наборе данных. Если в схеме "Без удержания" вы удалили или переименовали поле в запросе (например, заменили вложенную таблицу удержаний на левое соединение или убрали выборку результатов удержаний вовсе), но при этом само поле Удержания.Результат осталось упомянутым в настройках СКД, система выдаст ошибку.

Что нужно проверить для исправления ошибки:

  1. Откройте схему компоновки данных в конструкторе и перейдите на вкладку "Наборы данных". Убедитесь, что в списке доступных полей справа нет старых, удаленных из запроса путей к данным.
  2. Перейдите на вкладку "Настройки". Проверьте вкладку "Выбранные поля" для всего отчета и для каждой группировки в отдельности. Если там присутствует старое поле, удалите его.
  3. Проверьте вкладки "Поля группировок", "Сортировка" и "Условное оформление" — ссылки на несуществующие поля часто "прячутся" именно там.

---

Альтернативные лучшие практики (Best Practices)

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

Вариант 1. Использование вариантов отчета

Вместо создания двух разных схем компоновки данных, вы можете создать один макет СКД, но настроить в нем два разных Варианта отчета (например, вариант "С алиментами" и вариант "Без удержаний").

Вариант 2. Программное управление выбранными полями

Мы можем использовать одну схему компоновки, но программно отключать видимость колонок в зависимости от флага на форме. Рассмотрим пример кода, который можно поместить в процедуру ПриКомпоновкеРезультата:


// Находим поле "Удержание" в выбранных полях компоновщика
ПолеУдержания = КомпоновщикНастроек.Настройки.ВыбранныеПоля.Элементы.Найти("Удержание");
Если ПолеУдержания <> Неопределено Тогда
    // Включаем или выключаем вывод колонки на основе реквизита "Алименты"
    ПолеУдержания.Использование = Алименты;
КонецЕсли;

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

← На главную