Как запустить СКД из модуля обработки
Содержание
Чтобы собрать данные системой компоновки в обработке, нужны четыре объекта: СхемаКомпоновкиДанных, КомпоновщикМакетаКомпоновкиДанных, ПроцессорКомпоновкиДанных и один из процессоров вывода. Схему хранят в макете обработки, настройки берут из неё же, а запускают всю цепочку из модуля — на сервере.
Это рабочий способ, когда отчёт как объект метаданных заводить не хочется: разовая выгрузка, сервисная обработка, заполнение таблицы значений перед записью документа. Макет схемы живёт внутри обработки, компоновщик настроек собирает макет компоновки, процессор отдаёт результат в табличный документ, таблицу значений или дерево.
Ниже — полный код запуска, передача параметров и отбора, три варианта вывода результата на форму и разбор того, почему компоновка иногда отдаёт пустой результат или работает долго.
Почему компоновка в обработке ведёт себя не как в отчёте
В отчёте платформа делает за вас почти всё: хранит схему, рисует форму настроек, сама вызывает компоновщик при нажатии «Сформировать». В обработке этого механизма нет — вы собираете цепочку руками.
Отсюда три практических следствия:
- 🧩 Схему нужно откуда-то взять. Обычно это макет обработки с типом «Схема компоновки данных». Реже схему строят в коде через
Новый СхемаКомпоновкиДанных, но это редкий случай. - ⚙️ Настройки вы загружаете сами. Форма настроек СКД, как в отчёте, в обработке не появляется автоматически — её либо не показывают вовсе, либо выносят на форму отдельным реквизитом.
- 🖥️ Весь запуск идёт на сервере. Объекты компоновки не передаются между клиентом и сервером, поэтому процедура формирования помечается
&НаСервере(или живёт в модуле объекта обработки, который и так исполняется на сервере).
Если задача — именно интерактивный отчёт с настройками, которые крутит пользователь, честнее сделать объект «Отчёт». Обработку с СКД берут, когда результат нужен коду: записать в документ, выгрузить в файл, передать во внешнюю систему.
Добавляем макет со схемой компоновки
Схема — это описание запроса (или нескольких наборов данных), полей, ресурсов и настроек по умолчанию. Хранить её удобнее всего в макете.
Порядок действий в конфигураторе:
- Откройте дерево обработки, встаньте на ветку
Макеты, нажмите «Добавить». - В окне выбора типа макета укажите Схема компоновки данных. Откроется конструктор схемы.
- На закладке
Наборы данныхдобавьте набор типа «Запрос» и соберите текст запроса конструктором или руками. - На закладке
Ресурсыотметьте поля, которые нужно сворачивать (суммы, количества). - На закладке
Настройкизадайте структуру по умолчанию: группировки, выбранные поля, отборы. Это и будутНастройкиПоУмолчанию.
Простой запрос для набора данных:
ВЫБРАТЬ
ПродажиОбороты.Номенклатура КАК Номенклатура,
ПродажиОбороты.КоличествоОборот КАК Количество,
ПродажиОбороты.ВыручкаОборот КАК Выручка
ИЗ
РегистрНакопления.Продажи.Обороты(
&НачалоПериода,
&КонецПериода,
,
Организация = &Организация) КАК ПродажиОбороты
Параметры &НачалоПериода, &КонецПериода, &Организация попадут в ПараметрыДанных схемы — именно их вы потом заполняете из кода. Поля Количество и Выручка стоит пометить ресурсами, чтобы в группировках считались итоги.
Имена полей из запроса (КАК Количество) — это и есть имена полей компоновки. Если позже переименуете поле в запросе, ссылки на него в настройках и в коде вывода оборвутся молча: результат просто станет пустым.
Запускаем компоновку из модуля: полный код
Базовый шаблон, который формирует результат из макета. Он работает и в модуле объекта обработки, и в процедуре &НаСервере формы.
Процедура СформироватьРезультат() Экспорт
// 1. Берём схему из макета
СхемаКД = ПолучитьМакет("ОсновнаяСхема");
// 2. Загружаем настройки по умолчанию
Компоновщик = Новый КомпоновщикНастроекКомпоновкиДанных;
Компоновщик.Инициализировать(
Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКД));
Компоновщик.ЗагрузитьНастройки(СхемаКД.НастройкиПоУмолчанию);
Настройки = Компоновщик.Настройки;
// 3. Собираем макет компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКД = КомпоновщикМакета.Выполнить(СхемаКД, Настройки);
// 4. Инициализируем процессор компоновки
Процессор = Новый ПроцессорКомпоновкиДанных;
Процессор.Инициализировать(МакетКД);
// 5. Выводим результат в табличный документ
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ТабДок = Новый ТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабДок);
ПроцессорВывода.Вывести(Процессор);
КонецПроцедуры
Разберём пять шагов по порядку:
ПолучитьМакетотдаёт объектСхемаКомпоновкиДанных. Метод доступен в серверном контексте обработки.КомпоновщикНастроекКомпоновкиДанныххранит настройки отдельно от схемы — так их можно менять, не трогая макет.ЗагрузитьНастройкиподтягивает структуру с закладки «Настройки».КомпоновщикМакетаКомпоновкиДанных.Выполнитьпревращает схему плюс настройки в исполняемыйМакетКомпоновкиДанных. Это самый тяжёлый шаг: платформа строит окончательный запрос.ПроцессорКомпоновкиДанных.Инициализироватьготовит процессор к построчной выдаче.- Процессор вывода «проливает» результат в приёмник — здесь в
ТабличныйДокумент.
Четвёртый параметр Выполнить отвечает за проверку доступности полей, пятый — за тип генератора (о нём ниже, в разделе про вывод). Для простого случая их опускают.
Передаём параметры и накладываем отбор из кода
Параметры запроса (&НачалоПериода и т. д.) и отбор задают до шага 3 — до вызова КомпоновщикМакета.Выполнить. После того как макет компоновки собран, менять настройки поздно.
Установка параметров данных:
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("НачалоПериода", НачалоМесяца(ТекущаяДата()));
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("КонецПериода", КонецМесяца(ТекущаяДата()));
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Организация", ВыбраннаяОрганизация);
УстановитьЗначениеПараметра сам находит параметр по имени и включает его использование. Если параметра с таким именем в схеме нет, метод тихо ничего не сделает — опечатка в имени не вызовет ошибку, но период не применится.
Когда период в схеме оформлен одним параметром типа СтандартныйПериод, передавайте в него не две даты, а сам стандартный период — платформа сама разложит его на начало и конец:
Период = Новый СтандартныйПериод;
Период.Вариант = ВариантСтандартногоПериода.ЭтотМесяц;
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Период", Период);
Так параметр и отбор по периоду остаются согласованными: пользователь видит привычный выбор «этот месяц / прошлый квартал», а запрос получает корректные границы.
Отбор добавляют в коллекцию Настройки.Отбор.Элементы:
ЭлементОтбора = Настройки.Отбор.Элементы.Добавить(
Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Номенклатура");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
ЭлементОтбора.ПравоеЗначение = СписокТоваров;
ЭлементОтбора.Использование = Истина;
Несколько важных моментов про отбор:
ЛевоеЗначение— это поле компоновки, то есть имя из настроек, а не из запроса напрямую. Для реквизитов через точку пишутНовый ПолеКомпоновкиДанных("Номенклатура.ВидНоменклатуры").Использованиенадо явно ставить вИстина, иначе добавленная строка отбора не сработает.- Группу отбора с «И»/«ИЛИ» создают через
ГруппаЭлементовОтбораКомпоновкиДанных, добавляя её в ту же коллекцию.
Отбор компоновки и условие в самом запросе (Организация = &Организация) — это два разных уровня. Если условие уже зашито параметром в запрос, дублировать его отбором не нужно.
Выводим результат на форму: документ, таблица, дерево
Приёмник результата зависит от того, что вы собираетесь с данными делать. Процессор компоновки один, а процессоров вывода три.
| Нужен результат | Процессор вывода | Тип генератора (5-й параметр Выполнить) |
|---|---|---|
| Печатная/экранная форма | ...ВТабличныйДокумент | по умолчанию (не указывать) |
| Данные для кода | ...ВКоллекциюЗначений | ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений |
| Иерархия группировок | ...ВКоллекциюЗначений + ДеревоЗначений | ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений |
Для вывода в таблицу или дерево значений обязателен специальный тип генератора — иначе макет компоновки соберётся «под табличный документ», и УстановитьОбъект отдаст пустой результат.
Вывод в таблицу значений для дальнейшей обработки кодом:
МакетКД = КомпоновщикМакета.Выполнить(СхемаКД, Настройки, , ,
Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
Процессор = Новый ПроцессорКомпоновкиДанных;
Процессор.Инициализировать(МакетКД);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
Таблица = Новый ТаблицаЗначений;
ПроцессорВывода.УстановитьОбъект(Таблица);
ПроцессорВывода.Вывести(Процессор);
// дальше с Таблицей работаем как обычно
Для Каждого Строка Из Таблица Цикл
Сообщить(Строка.Номенклатура);
КонецЦикла;
Чтобы показать табличный документ на управляемой форме, заведите на форме реквизит типа ТабличныйДокумент (например, Результат), а в серверной процедуре присвойте в него собранный ТабДок:
&НаСервере
Процедура СформироватьНаСервере()
ТабДок = Новый ТабличныйДокумент;
// ... сборка компоновки ...
ПроцессорВывода.УстановитьДокумент(ТабДок);
ПроцессорВывода.Вывести(Процессор);
Результат = ТабДок; // Результат — реквизит формы
КонецПроцедуры
Для дерева значений приёмником служит Новый ДеревоЗначений, а в настройках компоновки должна быть иерархическая структура (вложенные группировки) — иначе вернётся плоский список.
Подаём в компоновку готовую таблицу значений
Иногда данные уже собраны в коде — например, обработка прочитала файл или получила таблицу из внешней системы, — и нужно только сгруппировать их и вывести. Запрос к базе тут не нужен: в схему добавляют набор данных типа Объект, а саму таблицу передают в процессор.
Шаги отличаются от запроса в двух местах:
- В конструкторе схемы на закладке
Наборы данныхдобавьте набор типа «Объект». В полеИмя объектазадайте произвольное имя, напримерВнешниеДанные, и опишите поля (имя и тип) вручную — конструктор их из запроса не возьмёт. - При инициализации процессора передайте соответствие «имя набора → таблица значений».
ВнешниеНаборы = Новый Соответствие;
ВнешниеНаборы.Вставить("ВнешниеДанные", МояТаблицаЗначений);
Процессор = Новый ПроцессорКомпоновкиДанных;
Процессор.Инициализировать(МакетКД, ВнешниеНаборы, , Истина);
Второй параметр Инициализировать — это как раз соответствие с внешними наборами. Имя в Вставить должно в точности совпадать с «Именем объекта» из схемы, а колонки таблицы значений — с описанными полями набора.
Поля во внешнем наборе данных платформа не угадывает. Если колонка таблицы называется Сумма, а в схеме поле описано как СуммаДокумента, компоновка её не увидит — строки получатся с пустыми значениями.
Этот приём удобно сочетать с выводом в таблицу значений: на входе плоские данные, на выходе — те же данные, сгруппированные и с итогами по ресурсам.
Отладка и ускорение компоновки в обработке
Чаще всего компоновка в обработке даёт один из двух результатов: пусто или долго. Разберём оба.
Пустой результат. Проверьте в таком порядке:
- 🔍 Имена полей в коде и в настройках совпадают с именами из запроса (
КАК ...). - 🔍 Параметры заполнены именно теми именами, что в схеме. Опечатка в
УстановитьЗначениеПараметране ошибка, а молчаливый пропуск. - 🔍 У добавленных элементов отбора стоит
Использование = Истина. - 🔍 Для вывода в коллекцию указан генератор
...ДляКоллекцииЗначений.
Долгая компоновка. Самый тяжёлый шаг — КомпоновщикМакета.Выполнить: он строит итоговый запрос. Ускоряют так:
- Отсекайте данные параметрами и отбором на уровне запроса, а не выводите всё и фильтруете потом.
- Не тащите в выборку поля, которые не нужны результату, — лишние реквизиты через точку порождают соединения.
- Для больших выгрузок выводите в таблицу значений, а не в табличный документ: рисование большого
ТабличногоДокументасамо по себе медленное.
Чтобы увидеть, какой запрос реально выполняется, выгрузите настройки в XML и посмотрите собранный макет:
Сообщить(КомпоновщикМакета.СообщениеОбОшибке);
Если Выполнить падает с ошибкой, текст окажется в СообщениеОбОшибке — это первое, что стоит вывести при отладке.
Расшифровка и условное оформление результата
Две вещи, которые часто забывают при ручном запуске, — расшифровка ячеек и условное оформление. В отчёте они работают сами, в обработке их надо не потерять.
Расшифровка. Чтобы по двойному клику на ячейке табличного документа открывались исходные данные, заведите объект расшифровки и передайте его и в сборку макета, и в инициализацию процессора:
ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
МакетКД = КомпоновщикМакета.Выполнить(СхемаКД, Настройки, ДанныеРасшифровки);
Процессор = Новый ПроцессорКомпоновкиДанных;
Процессор.Инициализировать(МакетКД, , ДанныеРасшифровки);
Третий параметр и у Выполнить, и у Инициализировать — один и тот же объект расшифровки. Если передать его только в одно место, расшифровка работать не будет.
Условное оформление. Выделение цветом, шрифтом или рамкой задаётся на закладке Настройки в разделе «Условное оформление». Для вывода в табличный документ ничего дополнительно в коде делать не нужно — оформление применяется автоматически при Вывести. А вот в таблицу значений оформление не переносится: это свойство ячеек документа, а не данных.
Если нужно раскрасить строки таблицы значений на форме, оформление настраивают уже на самом поле формы через условное оформление формы, а не через СКД.
Итог по цепочке запуска: схема из макета → компоновщик настроек с параметрами и отбором → макет компоновки → процессор → процессор вывода. Меняя только приёмник на последнем шаге, вы получаете из одной схемы и печатную форму, и данные для кода.
Частые вопросы
Можно ли запустить СКД без макета, прямо из кода?
Новый СхемаКомпоновкиДанных, в неё программно добавляются наборы данных и поля. Но это объёмный код — для стабильного запроса проще держать схему в макете, а программную сборку применять, когда структура меняется на лету.Почему форма настроек СКД не появляется в обработке сама?
НастройкиКомпоновкиДанных и привязывают к нему поле настроек вручную.В чём разница между НастройкиПоУмолчанию и Настройки компоновщика?
НастройкиПоУмолчанию — это то, что сохранено в схеме на закладке «Настройки», только для чтения. Компоновщик.Настройки — рабочая копия, которую вы меняете из кода (параметры, отбор, структура), не затрагивая макет.Как получить сразу несколько таблиц из одной компоновки?
Работает ли этот код во внешней обработке?
ПолучитьМакет доступен в её модуле объекта. Ограничения те же, что и у встроенной: сборка идёт на сервере.