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