Параметры СКД из кода: значения, списки, видимость и отладка

· 9 мин

Содержание

Программно параметр СКД задают одной строкой: Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Период", Дата). Весь вопрос в том, какие именно настройки вы меняете. Если поменять основные настройки компоновщика, а у пользователя этот параметр вынесен в быстрые настройки, отчёт возьмёт значение пользователя, и ваше просто потеряется.

Типичная ситуация: разработчик дописывает в отчёт параметр «ДатаОтчета», ставит его в коде, а отчёт упорно выдаёт Не установлено значение параметра "ДатаОтчета" или считает на старую дату. Причина почти всегда одна: значение записано не в тот уровень настроек системы компоновки данных.

Где хранятся параметры СКД: схема, настройки и пользовательские настройки

У параметра три уровня, и путаница между ними — источник большинства проблем.

УровеньОбъектЧто в нём
СхемаСхема.Параметры (ПараметрыСхемыКомпоновкиДанных)Описание: имя, тип, значение по умолчанию, выражение, флаги
НастройкиКомпоновщикНастроек.Настройки.ПараметрыДанныхЗначение и флаг Использование для варианта отчёта
Пользовательские настройкиКомпоновщикНастроек.ПользовательскиеНастройки.ЭлементыЗначения, которые пользователь ввёл в шапке отчёта

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

Элемент коллекции ПараметрыДанных — это ЗначениеПараметраНастроекКомпоновкиДанных. Главные свойства:

  • 🔹 Параметр — объект ПараметрКомпоновкиДанных, а не строка;
  • 🔹 Значение — само значение;
  • 🔹 Использование — если Ложь, параметр считается неустановленным;
  • 🔹 РежимОтображения и ИдентификаторПользовательскойНастройки — отвечают за показ в шапке отчёта.

УстановитьЗначениеПараметра сам выставляет Использование = Истина. При прямой записи в Значение флаг нужно включать вручную.

Как задать параметр СКД программно: три рабочих способа

Способ 1. В модуле отчёта, в ПриКомпоновкеРезультата

Самый надёжный вариант для отчёта на СКД. Отключаете стандартную обработку, берёте объединённые настройки и ставите параметры прямо в них. Пользовательские значения уже учтены, поэтому ничего не перетрётся.

Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)

    СтандартнаяОбработка = Ложь;

    Схема = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
    Настройки = КомпоновщикНастроек.ПолучитьНастройки();

    // Параметр, который пользователь не видит и не меняет
    Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("ДатаОтчета", ТекущаяДатаСеанса());

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

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

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

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

Обработчик выполняется на сервере, так что серверные функции доступны.

Способ 2. Полностью программная компоновка

Когда СКД нужна как «умный запрос» — например, получить таблицу значений для обработки — схема и настройки берутся без формы:

Схема = Отчеты.АнализПродаж.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = Схема.НастройкиПоУмолчанию;

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

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

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

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

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

Способ 3. Через пользовательские настройки

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

Процедура УстановитьПараметрОтчета(Компоновщик, ИмяПараметра, Значение)

    Параметр = Новый ПараметрКомпоновкиДанных(ИмяПараметра);

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

    Компоновщик.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра(ИмяПараметра, Значение);

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

Параметр типа «Стандартный период»

Для периода удобнее один параметр типа «Стандартный период», чем два поля даты. Из кода его заполняют объектом СтандартныйПериод:

Период = Новый СтандартныйПериод;
Период.ДатаНачала = НачалоКвартала(ТекущаяДатаСеанса());
Период.ДатаОкончания = КонецКвартала(ТекущаяДатаСеанса());

Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Период", Период);

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

Какой способ выбрать

СпособКогда подходитРиски
ПриКомпоновкеРезультатаСлужебные параметры: текущий пользователь, дата, настройки учётаПользователь не видит значение в шапке
Программная компоновкаДанные нужны коду, а не на экранФорма отчёта и варианты не участвуют
Пользовательские настройкиЗначение подставляется заранее и видно пользователюПользователь может его изменить

Передача списка значений в параметр СКД

Для отбора по нескольким складам или организациям параметру нужен список. Порядок такой:

  1. В конструкторе схемы на закладке «Параметры» у параметра включите флажок «Доступен список значений».
  2. В тексте запроса используйте условие В (&Склады), а не = &Склады.
  3. В коде передайте СписокЗначений.
Склады = Новый СписокЗначений;
Склады.Добавить(Справочники.Склады.НайтиПоНаименованию("Основной склад"));
Склады.Добавить(Справочники.Склады.НайтиПоНаименованию("Розничный склад"));

Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Склады", Склады);

Флажок можно включить и из кода, если схема собирается на лету: Схема.Параметры.Найти("Склады").ДоступенСписокЗначений = Истина.

Без флажка поле ввода в шапке отчёта позволит выбрать только одно значение, и пользователь не сможет набрать несколько складов.

Пустой список и необязательное условие

Если пользователь ничего не выбрал, условие В (&Склады) с пустым списком вернёт ноль строк. Чтобы при неустановленном параметре условие исчезало целиком, заключите его в фигурные скобки — это расширение языка запросов СКД:

ВЫБРАТЬ
    Остатки.Склад,
    Остатки.Номенклатура,
    Остатки.КоличествоОстаток
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(&ДатаОстатков, ) КАК Остатки
{ГДЕ
    Остатки.Склад В (&Склады)}

Когда у параметра Использование = Ложь, компоновщик выкинет условие из итогового запроса. Значит, для «всех складов» достаточно не включать параметр.

Видимость параметров в настройках отчёта

Не каждый параметр надо показывать пользователю. Управлять этим можно на двух уровнях.

В схеме. Флажок «Ограничение использования» (свойство ОграничениеИспользования) убирает параметр из настроек вовсе. Значение задаётся только кодом или выражением. Так прячут служебные параметры вроде «ДатаОтчета».

В настройках варианта. Свойство РежимОтображения определяет, где параметр виден:

  • 🔸 БыстрыйДоступ — в шапке формы отчёта;
  • 🔸 Обычный — в окне «Настройки…»;
  • 🔸 Недоступный — нигде, но значение работает.
Значение = КомпоновщикНастроек.Настройки.ПараметрыДанных.НайтиЗначениеПараметра(
    Новый ПараметрКомпоновкиДанных("Организация"));

Если Значение <> Неопределено Тогда
    Значение.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
КонецЕсли;

Удобное место для такого кода — обработчик формы отчёта ПриЗагрузкеВариантаНаСервере(Настройки): он срабатывает при каждой смене варианта. Например, если в базе одна организация, параметр «Организация» можно скрыть и подставить её автоматически.

Изменения основных настроек сами по себе не перестраивают уже созданные пользовательские настройки. Если параметр после правки не исчез из шапки, переинициализируйте компоновщик через КомпоновщикНастроек.ЗагрузитьНастройки(Настройки). Значения, которые пользователь ввёл в шапке, при этом сбросятся.

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

Параметр и отбор решают похожую задачу, но работают по-разному.

Параметр данныхОтбор
Где применяетсяВнутри запроса, в том числе в параметрах виртуальных таблицНа уровне СКД, компоновщик сам решает, перенести ли его в запрос
Нужно описывать в запросеДа, через &ИмяНет, хватает поля в наборе
Подходит дляДаты остатков, периода, служебных значенийГибких условий пользователя

Отбор из кода добавляется так:

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

Для условий «ИЛИ» добавьте сначала группу ГруппаЭлементовОтбораКомпоновкиДанных с ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИли, а элементы отбора кладите в её коллекцию Элементы.

Параметр, который зависит от другого

Классический пример — конец периода. Пользователь выбирает дату, а в запрос нужна дата с временем 23:59:59. Создайте в схеме параметр «КонецПериода» и в колонке «Выражение» укажите:

КОНЕЦПЕРИОДА(&ДатаОкончания, "ДЕНЬ")

Параметр с выражением вычисляется сам, ставить его из кода не нужно. Отметьте у него «Ограничение использования», чтобы пользователь не видел два поля даты.

Второй вариант — флаг-переключатель. Булев параметр «ТолькоПросроченные» включает или выключает условие:

ГДЕ
    (НЕ &ТолькоПросроченные ИЛИ Долги.СрокОплаты < &ДатаОтчета)

Тогда в коде достаточно поставить Истина или Ложь, текст запроса не меняется.

Вложенные схемы, внешний вызов и расширения

Вложенная схема

Параметры вложенной схемы живут в её собственных настройках. В конструкторе основной схемы, на закладке «Вложенные схемы», у вложенной схемы есть таблица параметров: там значение связывают с параметром или полем родителя выражением, например &Период. Если нужно задать значение кодом, найдите в структуре настроек элемент типа ВложенныйОбъектНастроекКомпоновкиДанных и работайте с его Настройки.ПараметрыДанных тем же УстановитьЗначениеПараметра.

Открытие отчёта с готовым параметром

Из другой формы отчёт открывают с параметром формы Отбор — структурой «имя → значение». Стандартная форма отчёта применяет её к параметрам данных и отборам с такими же именами:

ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Отбор", Новый Структура("Организация", Организация));
ПараметрыФормы.Вставить("СформироватьПриОткрытии", Истина);
ОткрытьФорму("Отчет.АнализПродаж.Форма", ПараметрыФормы);

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

Расширение конфигурации

Править типовой отчёт напрямую не стоит: обновление затрёт изменения. В расширении заимствуйте отчёт и перехватите обработчик модуля объекта аннотацией &Перед. Внутри обработчика доступен тот же КомпоновщикНастроек, и параметр можно поставить вспомогательной процедурой из способа 3. Если в типовом отчёте ПриКомпоновкеРезультата выполняет компоновку сам, ставьте параметр именно «перед», иначе значение опоздает.

Почему параметр СКД не применяется: ошибки и отладка

Диагностика: выберите симптом

Как посмотреть, что реально ушло в запрос

Самый быстрый способ отладки — остановиться отладчиком после КомпоновщикМакета.Выполнить и открыть макет:

  • 🔍 МакетКомпоновки.НаборыДанных — у набора-запроса свойство Запрос содержит итоговый текст. Видно, остались ли условия в фигурных скобках и какие отборы компоновщик перенёс в запрос;
  • 🔍 МакетКомпоновки.ЗначенияПараметров — фактические значения всех параметров, включая вычисленные выражениями.

Если параметра нет в ЗначенияПараметров или значение не то, проблема в настройках, а не в запросе. Проверку имени удобно делать через НайтиЗначениеПараметра: при опечатке он вернёт Неопределено.

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

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

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