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