Как задать отбор отчёта 1С из кода: Отбор, параметры и пользовательские настройки
Содержание
Программно установить отбор в отчёте 1С на системе компоновки данных (СКД) можно тремя способами: добавить элемент в КомпоновщикНастроек.Настройки.Отбор в модуле отчёта, передать структуру Отбор в параметры формы при открытии отчёта или изменить значение быстрого отбора в ПользовательскиеНастройки. Ключевой объект во всех случаях один — ЭлементОтбораКомпоновкиДанных с полями ЛевоеЗначение, ВидСравнения, ПравоеЗначение и Использование.
Типичная ситуация: бухгалтер просит кнопку «Продажи по этому контрагенту» прямо в карточке, а руководитель — чтобы менеджер видел в отчёте только свои сделки и не мог снять отбор. Обе задачи решаются кодом, но в разных местах. Всё ниже относится к платформе 8.3 и управляемым формам и не зависит от конфигурации.
Как устроен отбор в настройках компоновки
Отбор живёт внутри настроек компоновки. У отчёта есть КомпоновщикНастроек, а у него три слоя:
- 📐
Настройки— вариант отчёта, который задал разработчик; - 👤
ПользовательскиеНастройки— то, что пользователь поменял в форме (быстрые отборы, период); - 🔒
ФиксированныеНастройки— то, что пользователь изменить не может.
Итоговые настройки компоновщик собирает методом ПолучитьНастройки(). Если пользователь заполнил быстрый отбор, его значение перекроет то, что вы поставили в Настройки.Отбор для того же элемента.
Коллекция Отбор.Элементы хранит элементы двух типов:
| Тип | Что это | Ключевые свойства |
|---|---|---|
ЭлементОтбораКомпоновкиДанных | Одно условие | ЛевоеЗначение, ВидСравнения, ПравоеЗначение, Использование |
ГруппаЭлементовОтбораКомпоновкиДанных | Группа условий | ТипГруппы (И / ИЛИ / НЕ), Элементы |
Есть ещё отборы внутри группировок: у каждой группировки структуры отчёта своя коллекция Отбор. Она фильтрует только эту группировку, а не весь отчёт. Если условие нужно для всего отчёта, работайте с Настройки.Отбор.
Поле в ЛевоеЗначение — это не строка, а Новый ПолеКомпоновкиДанных("Контрагент"). Через точку можно обращаться к реквизитам: "Контрагент.ИНН", "Номенклатура.Родитель".
Добавление условия в отбор отчёта: пошаговый код
Самый надёжный вариант — модуль объекта отчёта и обработчик ПриКомпоновкеРезультата. Он выполняется на сервере при каждом нажатии «Сформировать».
Шаг 1. Простой элемент отбора
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
ЭлементОтбора = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Организация");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = Справочники.Организации.НайтиПоНаименованию("Ромашка");
ЭлементОтбора.Использование = Истина;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
Макет = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
Процессор = Новый ПроцессорКомпоновкиДанных;
Процессор.Инициализировать(Макет, , ДанныеРасшифровки, Истина);
ДокументРезультат.Очистить();
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(Процессор);
КонецПроцедуры
Мы работаем с копией настроек из ПолучитьНастройки(). Поэтому отбор не накапливается при повторных нажатиях и не сохраняется в вариант отчёта.
Использование = Истина обязательно. Новый элемент создаётся выключенным, и без этой строки отбор молча не сработает.
Шаг 2. Не плодить дубли
Если вы меняете не копию, а КомпоновщикНастроек.Настройки (например, из формы), сначала ищите существующий элемент по полю:
Функция ЭлементОтбораПоПолю(Отбор, ИмяПоля) Экспорт
Для Каждого Элемент Из Отбор.Элементы Цикл
Если ТипЗнч(Элемент) = Тип("ЭлементОтбораКомпоновкиДанных")
И Строка(Элемент.ЛевоеЗначение) = ИмяПоля Тогда
Возврат Элемент;
КонецЕсли;
КонецЦикла;
Элемент = Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Элемент.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяПоля);
Возврат Элемент;
КонецФункции
В типовых конфигурациях на БСП это уже сделано за вас: ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбора(Настройки.Отбор, "Организация", Организация) найдёт элемент или создаст новый и включит его.
Иногда нужно обратное: снять все отборы варианта и поставить свои. Удаляйте элементы обратным циклом, чтобы индексы не съезжали:
Количество = Настройки.Отбор.Элементы.Количество();
Для Сч = 1 По Количество Цикл
Настройки.Отбор.Элементы.Удалить(Настройки.Отбор.Элементы[Количество - Сч]);
КонецЦикла;
Для копии из ПолучитьНастройки() это безопасно: вариант отчёта и сохранённые настройки пользователя не пострадают. В КомпоновщикНастроек.Настройки так делать не стоит — пропадут быстрые отборы, которые пользователь видит в шапке формы.
Шаг 3. Список значений и группа «ИЛИ»
Отбор по нескольким складам — вид сравнения ВСписке, правое значение — СписокЗначений:
Склады = Новый СписокЗначений;
Склады.Добавить(СкладОсновной);
Склады.Добавить(СкладРозница);
Элемент = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Элемент.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Склад");
Элемент.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
Элемент.ПравоеЗначение = Склады;
Элемент.Использование = Истина;
Условие «покупатель из Москвы ИЛИ сумма больше 100 000» собирают через группу:
Группа = Настройки.Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
Группа.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИли;
Группа.Использование = Истина;
Условие1 = Группа.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Условие1.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Контрагент.Город");
Условие1.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
Условие1.ПравоеЗначение = "Москва";
Условие1.Использование = Истина;
Условие2 = Группа.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Условие2.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Сумма");
Условие2.ВидСравнения = ВидСравненияКомпоновкиДанных.Больше;
Условие2.ПравоеЗначение = 100000;
Условие2.Использование = Истина;
Для иерархических справочников есть ВИерархии и ВСпискеПоИерархии: отбор по группе номенклатуры захватит все вложенные позиции. Для пустых значений — Заполнено и НеЗаполнено, правое значение не нужно.
| Вид сравнения | Когда применять | Правое значение |
|---|---|---|
Равно, НеРавно | Одно конкретное значение | Ссылка, число, строка |
ВСписке, НеВСписке | Несколько значений | СписокЗначений |
ВИерархии | Группа справочника с подчинёнными | Ссылка на группу |
Содержит, Подобно | Поиск по части строки | Строка |
Больше, МеньшеИлиРавно и т. п. | Числа и даты | Число или дата |
Заполнено, НеЗаполнено | Проверка на пустоту | Не задаётся |
Период и даты: параметр или отбор
С датами частая ошибка — ставить отбор по полю Период вместо параметров. Отбор по дате работает, но для регистров с виртуальными таблицами это медленно и иногда неверно: остатки на дату через отбор не получить.
Правильно — параметры данных:
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("НачалоПериода", НачалоМесяца(ТекущаяДатаСеанса()));
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("КонецПериода", КонецМесяца(ТекущаяДатаСеанса()));
Метод УстановитьЗначениеПараметра сам включает использование параметра. Если параметра с таким именем в схеме нет, ничего не произойдёт и ошибки не будет. Проверить можно так:
Параметр = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("НачалоПериода"));
Если Параметр = Неопределено Тогда
ВызватьИсключение "В схеме нет параметра НачалоПериода";
КонецЕсли;
Три приёма, которые экономят время:
- 📅 Один параметр-период. Заведите в схеме параметр
ПериодтипаСтандартныйПериод, а уНачалоПериодаиКонецПериодаукажите выражения&Период.ДатаНачалаи&Период.ДатаОкончания. Пользователь выбирает период одним полем, а из кода вы передаётеНовый СтандартныйПериод(ВариантСтандартногоПериода.ПрошлыйМесяц). - 🕛 Конец дня. Дата без времени означает 00:00:00. Передавайте
КонецДня(Дата), иначе документы последнего дня выпадут. - 📌 Остатки «включая» момент. Для параметра виртуальной таблицы остатков используйте
Новый Граница(КонецДня(Дата), ВидГраницы.Включая).
Отбор по дате уместен, когда фильтруете поле документа, а не регистра: например, «договоры с датой окончания до 31.12».
Отбор из формы и при открытии отчёта
Открыть отчёт с готовым отбором
Для кнопки «Продажи по контрагенту» в карточке модуль отчёта не нужен. У формы отчёта есть стандартные параметры Отбор и СформироватьПриОткрытии:
&НаКлиенте
Процедура ПродажиПоКонтрагенту(Команда)
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Отбор", Новый Структура("Контрагент", Объект.Ссылка));
ПараметрыФормы.Вставить("СформироватьПриОткрытии", Истина);
ОткрытьФорму("Отчет.ПродажиПоКонтрагентам.Форма", ПараметрыФормы);
КонецПроцедуры
Ключи структуры Отбор — имена полей схемы. Платформа сама создаст элементы отбора с видом сравнения «Равно». Если значение — СписокЗначений, получится «В списке».
Поменять отбор в открытой форме
В модуле формы отчёта настройки доступны через реквизит Отчет:
&НаСервере
Процедура УстановитьОтборПоМенеджеру()
Элемент = Отчет.КомпоновщикНастроек.Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
Элемент.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Менеджер");
Элемент.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
Элемент.ПравоеЗначение = Пользователи.ТекущийПользователь();
Элемент.Использование = Истина;
Элемент.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
КонецПроцедуры
РежимОтображения = Недоступный прячет элемент от пользователя. Строка Пользователи.ТекущийПользователь() — функция БСП; в самописной конфигурации подставьте свой способ получить пользователя.
Быстрые отборы: пользовательские настройки
Если элемент отбора вынесен в шапку формы, у него есть ИдентификаторПользовательскойНастройки. Значение, которое видит пользователь, лежит не в Настройки.Отбор, а в ПользовательскиеНастройки. Менять нужно там:
&НаСервере
Процедура УстановитьБыстрыйОтбор(ИмяПоля, Значение)
Компоновщик = Отчет.КомпоновщикНастроек;
Для Каждого ЭлементНастроек Из Компоновщик.Настройки.Отбор.Элементы Цикл
Если ТипЗнч(ЭлементНастроек) <> Тип("ЭлементОтбораКомпоновкиДанных")
Или Строка(ЭлементНастроек.ЛевоеЗначение) <> ИмяПоля Тогда
Продолжить;
КонецЕсли;
Для Каждого ЭлементПН Из Компоновщик.ПользовательскиеНастройки.Элементы Цикл
Если ЭлементПН.ИдентификаторПользовательскойНастройки
= ЭлементНастроек.ИдентификаторПользовательскойНастройки Тогда
ЭлементПН.ПравоеЗначение = Значение;
ЭлементПН.Использование = Истина;
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Отбор, который нельзя снять
Для ограничения «менеджер видит только своё» добавляйте элемент в ФиксированныеНастройки.Отбор. Пользователь не сможет его изменить ни через форму, ни через настройки варианта.
Фиксированный отбор — это удобство интерфейса, а не защита данных. Пользователь с правом на конфигуратор или на свой отчёт обойдёт его. Настоящее ограничение доступа делают через RLS в ролях.
Почему программный отбор не срабатывает
Отбор добавлен, а отчёт показывает всё. Проверяйте по порядку.
Использование = Истина, либо отбор добавлен в КомпоновщикНастроек.Настройки уже после того, как стандартная обработка взяла настройки. Ставьте отбор в копию из ПолучитьНастройки() и выводите результат сами.ПользовательскиеНастройки перекрывает элемент варианта с тем же идентификатором. Меняйте значение в пользовательских настройках или ставьте элемент в фиксированные.КонецДня. Проверьте значение в отладчике.Настройки.Отбор.ДоступныеПоляОтбора.НайтиПоле(Новый ПолеКомпоновкиДанных("Склад")) — если вернулось Неопределено, поле недоступно.КомпоновщикНастроек.Настройки без поиска существующего. Используйте поиск по полю или работайте с копией настроек.Удобный приём отладки — посмотреть, какой запрос ушёл в базу. Поставьте точку останова после КомпоновщикМакета.Выполнить, раскройте в отладчике Макет → НаборыДанных → <набор> → Запрос. Если ваше условие появилось в тексте запроса, отбор дошёл до СУБД. Если нет — СКД фильтрует уже готовые строки.
Ещё один способ — сохранить итоговые настройки в XML и сравнить с ожидаемыми:
Запись = Новый ЗаписьXML;
Запись.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(Запись, Настройки);
ТекстНастроек = Запись.Закрыть();
Отбор и скорость отчёта
СКД старается переносить отбор в запрос. Получается это не всегда, и разница в скорости бывает в десятки раз на больших регистрах.
- ✅ Поле из запроса набора — условие встаёт в
ГДЕзапроса, фильтрует СУБД. - ✅ Поле виртуальной таблицы при автозаполнении — СКД передаёт условие в параметры виртуальной таблицы, если поле есть среди её измерений.
- ⚠️ Вычисляемое поле и поле из набора-объекта — фильтрация после получения всех данных.
- ⚠️ Ресурс (
Сумма,Количество) — условие применяется к итогам, какИМЕЮЩИЕ: сначала считаются все суммы. - ⚠️ Реквизит через точку (
Контрагент.Город) — в запросе появится соединение с таблицей справочника.
Если вы пишете запрос набора вручную и отключили автозаполнение, СКД переносит в запрос только те условия, для которых вы явно разрешили это место. Откройте конструктор запроса набора, перейдите на вкладку «Компоновка данных» и отметьте поля, по которым допустим отбор, для каждой таблицы. Конструктор сам допишет в текст запроса фрагменты в фигурных скобках: в параметрах виртуальной таблицы и в блоке условий.
Фигурные скобки в запросе СКД означают «сюда можно подставить отбор пользователя». Для виртуальной таблицы это особенно важно: если отбор по измерению не попал в её параметры, обороты сначала рассчитаются по всей базе и лишь потом будут отфильтрованы.
Отбор по Номенклатура из отчёта на виртуальной таблице без фигурных скобок — классическая причина, почему отчёт за месяц строится минуту, а не секунду.
Правило для больших отчётов простое: фильтр по измерениям регистра — в параметры виртуальной таблицы, фильтр по документам — в ГДЕ запроса, отбор по ресурсам и вычисляемым полям — только когда без него никак.
Частые вопросы
Можно ли установить отбор в отчёте без модуля объекта?
Отбор в параметрах формы при ОткрытьФорму или измените Отчет.КомпоновщикНастроек в модуле формы. Модуль объекта нужен, когда отбор должен применяться при каждом формировании.Как убрать отбор, который поставил код?
Отбор.Элементы.Удалить(Элемент) или выключите его: Элемент.Использование = Ложь. Второй вариант удобнее, если элемент вынесен в быстрые настройки.Как отобрать записи с пустым значением поля?
НеЗаполнено, правое значение не задаётся. Он ловит и пустую ссылку, и NULL из левого соединения.Работает ли программный отбор во внешнем отчёте?
ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных") или реквизит СхемаКомпоновкиДанных модуля объекта.Отличается ли отбор в отчёте от отбора динамического списка?
КомпоновщикНастроек и коллекция Отбор с элементами ЭлементОтбораКомпоновкиДанных. Код добавления условия переносится почти без изменений.