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