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