Как программно сформировать отчет СКД на основе динамической таблицы значений и дополнительных реквизитов

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке отчетов в 1С:Предприятие 8.3 часто возникает ситуация, когда структура данных заранее неизвестна. Классический пример — вывод дополнительных реквизитов номенклатуры. Поскольку пользователь может в любой момент добавить новое свойство (например, «Цвет» или «Размер»), мы не можем жестко прописать эти поля в схеме компоновки данных (СКД) на этапе проектирования в конфигураторе. В данной статье мы подробно разберем, как реализовать полностью динамический отчет, используя программное создание полей и наборов данных.

Проблема статических схем при работе с доп. реквизитами

Если мы создадим обычный запрос в СКД, нам придется вручную выбирать каждое свойство из таблицы дополнительных реквизитов. Это неудобно, так как при добавлении нового свойства придется переписывать отчет. Нам же нужно, чтобы система сама анализировала состав свойств и превращала их в колонки отчета. Для этого мы проанализируем подход, основанный на программной модификации текста запроса и структуры полей СхемыКомпоновкиДанных.

Шаг 1. Формирование динамического текста запроса

Первым делом нам необходимо подготовить текст запроса, который будет «собирать» данные. Разберем логику построения такого запроса. Мы будем использовать базовую таблицу (например, справочник Номенклатура) и присоединять к ней таблицу дополнительных реквизитов столько раз, сколько у нас есть уникальных свойств.

Рассмотрим пример кода, который динамически формирует текст запроса, подставляя ЛЕВОЕ СОЕДИНЕНИЕ для каждого свойства:


ТекстЗапроса = "ВЫБРАТЬ РАЗЛИЧНЫЕ
|    Номенклатура.Ссылка КАК Ссылка,
|    Номенклатура.Артикул КАК Артикул,
|    0=0 
|ИЗ
|    Справочник.Номенклатура КАК Номенклатура";

// Получаем список всех доступных свойств
ЗапросСвойств = Новый Запрос;
ЗапросСвойств.Текст = "ВЫБРАТЬ РАЗЛИЧНЫЕ Свойство.Имя КАК Имя Из Справочник.Номенклатура.ДополнительныеРеквизиты";
Выборка = ЗапросСвойств.Выполнить().Выгрузить();

Индекс = 0;
Для каждого Стр Из Выборка Цикл
    ИмяПоля = Стр.Имя;
    // Заменяем заглушку 0=0 на новое поле и новую заглушку
    СтрокаЗамены = "НоменклатураДоп" + Индекс + ".Значение КАК " + ИмяПоля + ", 0=0";
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "0=0", СтрокаЗамены);
    
    // Добавляем соединение
    ТекстЗапроса = ТекстЗапроса + Символы.ПС + 
        "ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура.ДополнительныеРеквизиты КАК НоменклатураДоп" + Индекс +
        " ПО Номенклатура.Ссылка = НоменклатураДоп" + Индекс + ".Ссылка 
        И НоменклатураДоп" + Индекс + ".Свойство.Имя = """ + ИмяПоля + """";
    Индекс = Индекс + 1;
КонецЦикла;

// Убираем лишнюю запятую и заглушку в конце
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, ", 0=0", "");

В данном примере мы используем конструкцию 0=0 как маркер места, куда будут вставляться новые поля. Это позволяет избежать сложных манипуляций со строками при добавлении запятых.

Шаг 2. Программное добавление полей в набор данных СКД

После того как текст запроса сформирован, СКД «не узнает» о новых полях автоматически, если мы просто подставим текст. Нам нужно прописать эти поля в объекте НаборДанныхСхемыКомпоновкиДанных. Разберем, как это сделать в процедуре ПриКомпоновкеРезультата модуля объекта отчета.

Выясним причину, по которой это важно: если поле не описано в наборе данных схемы, компоновщик настроек не позволит пользователю выбрать это поле в настройках (в группировках или выбранных полях).


// Предположим, ТЗ — это таблица с колонками, которые мы хотим добавить в СКД
Для каждого Колонка Из ТЗ.Колонки Цикл
    // Проверяем, нет ли уже такого поля в наборе данных
    ПолеСКД = СхемаКомпоновкиДанных.НаборыДанных.НаборДанных1.Поля.Найти(Колонка.Имя);
    
    Если ПолеСКД = Неопределено Тогда
        ПолеСКД = СхемаКомпоновкиДанных.НаборыДанных.НаборДанных1.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
        ПолеСКД.ПутьКДанным = Колонка.Имя;
        ПолеСКД.Поле = Колонка.Имя;
        ПолеСКД.Заголовок = Колонка.Имя; // Можно задать более понятное имя
        ПолеСКД.ТипЗначения = Колонка.ТипЗначения;
    КонецЕсли;
КонецЦикла;

Важный нюанс: свойство ПутьКДанным должно быть уникальным идентификатором без пробелов. Если имя дополнительного реквизита содержит спецсимволы, обязательно очищайте их или заменяйте на подчеркивания при формировании ПутьКДанным, оставляя читаемое название только в свойстве Заголовок.

Шаг 3. Автоматическое добавление в «Выбранные поля»

Просто добавить поле в схему недостаточно — оно появится в списке доступных, но не выведется в отчет автоматически. Чтобы избавить пользователя от необходимости каждый раз заходить в настройки, добавим эти поля в выбранные поля программно.

Проанализируем работу с компоновщиком настроек:


Настройки = КомпоновщикНастроек.Настройки;
Для каждого Колонка Из ТЗ.Колонки Цикл
    ВыбранноеПоле = Настройки.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
    ВыбранноеПоле.Поле = Новый ПолеКомпоновкиДанных(Колонка.Имя);
    ВыбранноеПоле.Использование = Истина;
КонецЦикла;

Шаг 4. Использование внешнего набора данных (Набор данных - объект)

Если вы решили не динамически менять текст запроса, а сначала выгрузить данные в Таблицу Значений (ТЗ), а затем передать её в СКД, схема работы немного меняется. В конфигураторе вы создаете «Набор данных - объект» и указываете ему имя (например, ВнешниеДанные).

В коде процедуры ПриКомпоновкеРезультата необходимо связать вашу ТЗ с этим именем:


ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ВнешниеДанные", Тз); // Тз — ваша сформированная таблица

ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;

МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, 
    КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);

ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);

Альтернативный подход: Механизм «Характеристики»

Рассмотрим более элегантный способ, который предоставляет платформа 1С «из коробки» без написания сложного кода по соединению таблиц. В СКД на вкладке «Наборы данных» есть кнопка «Характеристики».

Посмотрим на алгоритм настройки характеристик:

  1. Укажите тип объектов (например, СправочникСсылка.Номенклатура).
  2. Выберите таблицу, где хранятся виды характеристик (свойства).
  3. Выберите таблицу, где хранятся значения этих характеристик.
  4. Укажите поля связи (обычно это Ссылка и Свойство).

После этой настройки СКД сама при выполнении запроса проанализирует все доступные дополнительные реквизиты и добавит их в список доступных полей отчета. Это наиболее производительный и правильный метод с точки зрения архитектуры 1С.

Советы по оптимизации и типизации

При программном формировании отчетов следует учитывать несколько критических моментов:

Таким образом, мы разобрали основные способы работы с динамическими данными в СКД. Выбор между программным изменением схемы и механизмом характеристик зависит от сложности вашей задачи, но понимание того, как программно добавлять поля (объекты ПолеНабораДанныхСхемыКомпоновкиДанных), является обязательным навыком для продвинутого разработчика 1С.

← На главную