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