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