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