Как запустить СКД из модуля обработки

· 10 мин

Содержание

Чтобы собрать данные системой компоновки в обработке, нужны четыре объекта: СхемаКомпоновкиДанных, КомпоновщикМакетаКомпоновкиДанных, ПроцессорКомпоновкиДанных и один из процессоров вывода. Схему хранят в макете обработки, настройки берут из неё же, а запускают всю цепочку из модуля — на сервере.

Это рабочий способ, когда отчёт как объект метаданных заводить не хочется: разовая выгрузка, сервисная обработка, заполнение таблицы значений перед записью документа. Макет схемы живёт внутри обработки, компоновщик настроек собирает макет компоновки, процессор отдаёт результат в табличный документ, таблицу значений или дерево.

Ниже — полный код запуска, передача параметров и отбора, три варианта вывода результата на форму и разбор того, почему компоновка иногда отдаёт пустой результат или работает долго.

Почему компоновка в обработке ведёт себя не как в отчёте

В отчёте платформа делает за вас почти всё: хранит схему, рисует форму настроек, сама вызывает компоновщик при нажатии «Сформировать». В обработке этого механизма нет — вы собираете цепочку руками.

Отсюда три практических следствия:

  • 🧩 Схему нужно откуда-то взять. Обычно это макет обработки с типом «Схема компоновки данных». Реже схему строят в коде через Новый СхемаКомпоновкиДанных, но это редкий случай.
  • ⚙️ Настройки вы загружаете сами. Форма настроек СКД, как в отчёте, в обработке не появляется автоматически — её либо не показывают вовсе, либо выносят на форму отдельным реквизитом.
  • 🖥️ Весь запуск идёт на сервере. Объекты компоновки не передаются между клиентом и сервером, поэтому процедура формирования помечается &НаСервере (или живёт в модуле объекта обработки, который и так исполняется на сервере).

Если задача — именно интерактивный отчёт с настройками, которые крутит пользователь, честнее сделать объект «Отчёт». Обработку с СКД берут, когда результат нужен коду: записать в документ, выгрузить в файл, передать во внешнюю систему.

Добавляем макет со схемой компоновки

Схема — это описание запроса (или нескольких наборов данных), полей, ресурсов и настроек по умолчанию. Хранить её удобнее всего в макете.

Порядок действий в конфигураторе:

  1. Откройте дерево обработки, встаньте на ветку Макеты, нажмите «Добавить».
  2. В окне выбора типа макета укажите Схема компоновки данных. Откроется конструктор схемы.
  3. На закладке Наборы данных добавьте набор типа «Запрос» и соберите текст запроса конструктором или руками.
  4. На закладке Ресурсы отметьте поля, которые нужно сворачивать (суммы, количества).
  5. На закладке Настройки задайте структуру по умолчанию: группировки, выбранные поля, отборы. Это и будут НастройкиПоУмолчанию.

Простой запрос для набора данных:

ВЫБРАТЬ
    ПродажиОбороты.Номенклатура КАК Номенклатура,
    ПродажиОбороты.КоличествоОборот КАК Количество,
    ПродажиОбороты.ВыручкаОборот КАК Выручка
ИЗ
    РегистрНакопления.Продажи.Обороты(
        &НачалоПериода,
        &КонецПериода,
        ,
        Организация = &Организация) КАК ПродажиОбороты

Параметры &НачалоПериода, &КонецПериода, &Организация попадут в ПараметрыДанных схемы — именно их вы потом заполняете из кода. Поля Количество и Выручка стоит пометить ресурсами, чтобы в группировках считались итоги.

Имена полей из запроса (КАК Количество) — это и есть имена полей компоновки. Если позже переименуете поле в запросе, ссылки на него в настройках и в коде вывода оборвутся молча: результат просто станет пустым.

Запускаем компоновку из модуля: полный код

Базовый шаблон, который формирует результат из макета. Он работает и в модуле объекта обработки, и в процедуре &НаСервере формы.

Процедура СформироватьРезультат() Экспорт

    // 1. Берём схему из макета
    СхемаКД = ПолучитьМакет("ОсновнаяСхема");

    // 2. Загружаем настройки по умолчанию
    Компоновщик = Новый КомпоновщикНастроекКомпоновкиДанных;
    Компоновщик.Инициализировать(
        Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКД));
    Компоновщик.ЗагрузитьНастройки(СхемаКД.НастройкиПоУмолчанию);
    Настройки = Компоновщик.Настройки;

    // 3. Собираем макет компоновки
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКД = КомпоновщикМакета.Выполнить(СхемаКД, Настройки);

    // 4. Инициализируем процессор компоновки
    Процессор = Новый ПроцессорКомпоновкиДанных;
    Процессор.Инициализировать(МакетКД);

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

КонецПроцедуры

Разберём пять шагов по порядку:

  • ПолучитьМакет отдаёт объект СхемаКомпоновкиДанных. Метод доступен в серверном контексте обработки.
  • КомпоновщикНастроекКомпоновкиДанных хранит настройки отдельно от схемы — так их можно менять, не трогая макет. ЗагрузитьНастройки подтягивает структуру с закладки «Настройки».
  • КомпоновщикМакетаКомпоновкиДанных.Выполнить превращает схему плюс настройки в исполняемый МакетКомпоновкиДанных. Это самый тяжёлый шаг: платформа строит окончательный запрос.
  • ПроцессорКомпоновкиДанных.Инициализировать готовит процессор к построчной выдаче.
  • Процессор вывода «проливает» результат в приёмник — здесь в ТабличныйДокумент.

Четвёртый параметр Выполнить отвечает за проверку доступности полей, пятый — за тип генератора (о нём ниже, в разделе про вывод). Для простого случая их опускают.

Передаём параметры и накладываем отбор из кода

Параметры запроса (&НачалоПериода и т. д.) и отбор задают до шага 3 — до вызова КомпоновщикМакета.Выполнить. После того как макет компоновки собран, менять настройки поздно.

Установка параметров данных:

Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("НачалоПериода", НачалоМесяца(ТекущаяДата()));
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("КонецПериода",  КонецМесяца(ТекущаяДата()));
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Организация",   ВыбраннаяОрганизация);

УстановитьЗначениеПараметра сам находит параметр по имени и включает его использование. Если параметра с таким именем в схеме нет, метод тихо ничего не сделает — опечатка в имени не вызовет ошибку, но период не применится.

Когда период в схеме оформлен одним параметром типа СтандартныйПериод, передавайте в него не две даты, а сам стандартный период — платформа сама разложит его на начало и конец:

Период = Новый СтандартныйПериод;
Период.Вариант = ВариантСтандартногоПериода.ЭтотМесяц;
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Период", Период);

Так параметр и отбор по периоду остаются согласованными: пользователь видит привычный выбор «этот месяц / прошлый квартал», а запрос получает корректные границы.

Отбор добавляют в коллекцию Настройки.Отбор.Элементы:

ЭлементОтбора = Настройки.Отбор.Элементы.Добавить(
    Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение  = Новый ПолеКомпоновкиДанных("Номенклатура");
ЭлементОтбора.ВидСравнения   = ВидСравненияКомпоновкиДанных.ВСписке;
ЭлементОтбора.ПравоеЗначение = СписокТоваров;
ЭлементОтбора.Использование  = Истина;

Несколько важных моментов про отбор:

  • ЛевоеЗначение — это поле компоновки, то есть имя из настроек, а не из запроса напрямую. Для реквизитов через точку пишут Новый ПолеКомпоновкиДанных("Номенклатура.ВидНоменклатуры").
  • Использование надо явно ставить в Истина, иначе добавленная строка отбора не сработает.
  • Группу отбора с «И»/«ИЛИ» создают через ГруппаЭлементовОтбораКомпоновкиДанных, добавляя её в ту же коллекцию.

Отбор компоновки и условие в самом запросе (Организация = &Организация) — это два разных уровня. Если условие уже зашито параметром в запрос, дублировать его отбором не нужно.

Выводим результат на форму: документ, таблица, дерево

Приёмник результата зависит от того, что вы собираетесь с данными делать. Процессор компоновки один, а процессоров вывода три.

Нужен результатПроцессор выводаТип генератора (5-й параметр Выполнить)
Печатная/экранная форма...ВТабличныйДокументпо умолчанию (не указывать)
Данные для кода...ВКоллекциюЗначенийГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений
Иерархия группировок...ВКоллекциюЗначений + ДеревоЗначенийГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений

Для вывода в таблицу или дерево значений обязателен специальный тип генератора — иначе макет компоновки соберётся «под табличный документ», и УстановитьОбъект отдаст пустой результат.

Вывод в таблицу значений для дальнейшей обработки кодом:

МакетКД = КомпоновщикМакета.Выполнить(СхемаКД, Настройки, , ,
    Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));

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

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

// дальше с Таблицей работаем как обычно
Для Каждого Строка Из Таблица Цикл
    Сообщить(Строка.Номенклатура);
КонецЦикла;

Чтобы показать табличный документ на управляемой форме, заведите на форме реквизит типа ТабличныйДокумент (например, Результат), а в серверной процедуре присвойте в него собранный ТабДок:

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

Для дерева значений приёмником служит Новый ДеревоЗначений, а в настройках компоновки должна быть иерархическая структура (вложенные группировки) — иначе вернётся плоский список.

Подаём в компоновку готовую таблицу значений

Иногда данные уже собраны в коде — например, обработка прочитала файл или получила таблицу из внешней системы, — и нужно только сгруппировать их и вывести. Запрос к базе тут не нужен: в схему добавляют набор данных типа Объект, а саму таблицу передают в процессор.

Шаги отличаются от запроса в двух местах:

  1. В конструкторе схемы на закладке Наборы данных добавьте набор типа «Объект». В поле Имя объекта задайте произвольное имя, например ВнешниеДанные, и опишите поля (имя и тип) вручную — конструктор их из запроса не возьмёт.
  2. При инициализации процессора передайте соответствие «имя набора → таблица значений».
ВнешниеНаборы = Новый Соответствие;
ВнешниеНаборы.Вставить("ВнешниеДанные", МояТаблицаЗначений);

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

Второй параметр Инициализировать — это как раз соответствие с внешними наборами. Имя в Вставить должно в точности совпадать с «Именем объекта» из схемы, а колонки таблицы значений — с описанными полями набора.

Поля во внешнем наборе данных платформа не угадывает. Если колонка таблицы называется Сумма, а в схеме поле описано как СуммаДокумента, компоновка её не увидит — строки получатся с пустыми значениями.

Этот приём удобно сочетать с выводом в таблицу значений: на входе плоские данные, на выходе — те же данные, сгруппированные и с итогами по ресурсам.

Отладка и ускорение компоновки в обработке

Чаще всего компоновка в обработке даёт один из двух результатов: пусто или долго. Разберём оба.

Пустой результат. Проверьте в таком порядке:

  • 🔍 Имена полей в коде и в настройках совпадают с именами из запроса (КАК ...).
  • 🔍 Параметры заполнены именно теми именами, что в схеме. Опечатка в УстановитьЗначениеПараметра не ошибка, а молчаливый пропуск.
  • 🔍 У добавленных элементов отбора стоит Использование = Истина.
  • 🔍 Для вывода в коллекцию указан генератор ...ДляКоллекцииЗначений.

Долгая компоновка. Самый тяжёлый шаг — КомпоновщикМакета.Выполнить: он строит итоговый запрос. Ускоряют так:

  • Отсекайте данные параметрами и отбором на уровне запроса, а не выводите всё и фильтруете потом.
  • Не тащите в выборку поля, которые не нужны результату, — лишние реквизиты через точку порождают соединения.
  • Для больших выгрузок выводите в таблицу значений, а не в табличный документ: рисование большого ТабличногоДокумента само по себе медленное.

Чтобы увидеть, какой запрос реально выполняется, выгрузите настройки в XML и посмотрите собранный макет:

Сообщить(КомпоновщикМакета.СообщениеОбОшибке);

Если Выполнить падает с ошибкой, текст окажется в СообщениеОбОшибке — это первое, что стоит вывести при отладке.

Чек-лист запуска СКД из обработки
Выполнено: 0 / 6

Расшифровка и условное оформление результата

Две вещи, которые часто забывают при ручном запуске, — расшифровка ячеек и условное оформление. В отчёте они работают сами, в обработке их надо не потерять.

Расшифровка. Чтобы по двойному клику на ячейке табличного документа открывались исходные данные, заведите объект расшифровки и передайте его и в сборку макета, и в инициализацию процессора:

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

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

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

Третий параметр и у Выполнить, и у Инициализировать — один и тот же объект расшифровки. Если передать его только в одно место, расшифровка работать не будет.

Условное оформление. Выделение цветом, шрифтом или рамкой задаётся на закладке Настройки в разделе «Условное оформление». Для вывода в табличный документ ничего дополнительно в коде делать не нужно — оформление применяется автоматически при Вывести. А вот в таблицу значений оформление не переносится: это свойство ячеек документа, а не данных.

Если нужно раскрасить строки таблицы значений на форме, оформление настраивают уже на самом поле формы через условное оформление формы, а не через СКД.

Итог по цепочке запуска: схема из макета → компоновщик настроек с параметрами и отбором → макет компоновки → процессор → процессор вывода. Меняя только приёмник на последнем шаге, вы получаете из одной схемы и печатную форму, и данные для кода.

Частые вопросы

Можно ли запустить СКД без макета, прямо из кода?
Да. Создаётся Новый СхемаКомпоновкиДанных, в неё программно добавляются наборы данных и поля. Но это объёмный код — для стабильного запроса проще держать схему в макете, а программную сборку применять, когда структура меняется на лету.
Почему форма настроек СКД не появляется в обработке сама?
Платформа строит её автоматически только для объекта «Отчёт». В обработке настройки либо не показывают, либо выносят на форму реквизитом типа НастройкиКомпоновкиДанных и привязывают к нему поле настроек вручную.
В чём разница между НастройкиПоУмолчанию и Настройки компоновщика?
НастройкиПоУмолчанию — это то, что сохранено в схеме на закладке «Настройки», только для чтения. Компоновщик.Настройки — рабочая копия, которую вы меняете из кода (параметры, отбор, структура), не затрагивая макет.
Как получить сразу несколько таблиц из одной компоновки?
Если в структуре настроек несколько группировок верхнего уровня или таблиц, они все попадут в один результат. Для раздельных коллекций удобнее запустить компоновку несколько раз с разными настройками или разобрать готовое дерево значений по уровням.
Работает ли этот код во внешней обработке?
Да, схема точно так же хранится в макете внешней обработки, а ПолучитьМакет доступен в её модуле объекта. Ограничения те же, что и у встроенной: сборка идёт на сервере.