При работе с управляемыми формами в конфигурациях на платформе 1С:Предприятие 8.3, особенно при использовании Библиотеки стандартных подсистем (БСП), разработчики часто сталкиваются с необходимостью программно устанавливать отборы в формах списков документов. Это может быть вызвано требованиями бизнеса, например, для автоматического фильтрации данных по организации, текущему пользователю или другим условиям. Однако при попытке установить такой отбор, особенно если он касается уже предопределенных или "фиксированных" настроек, может возникнуть ошибка: "Невозможно применить фиксированные настройки. Пересекаются элементы отбора."
Эта проблема возникает, когда система пытается применить несколько отборов по одному и тому же полю (например, по полю "Организация"), и один из этих отборов является "фиксированным" (предопределенным системой или конфигурацией), а другой – пользовательским или программно установленным. Платформа 1С не позволяет объединять такие пересекающиеся отборы по принципу "И" для одного поля, что приводит к ошибке и отображению пустого списка. В данной статье мы подробно разберем, почему возникает эта ошибка и какие существуют эффективные способы борьбы с ней.
Прежде чем перейти к решениям, давайте разберемся, что такое "фиксированные настройки" и откуда берется отбор, вызывающий конфликт. Фиксированные настройки в 1С:Предприятии — это предопределенные настройки, которые имеют приоритет над другими, включая пользовательские. Они используются как в отчетах, так и в формах списков и выбора для того, чтобы ограничить изменения, вносимые пользователем или программой.
Причина ошибки "Невозможно применить фиксированные настройки. Пересекаются элементы отбора." заключается в следующем:
Форма.Параметры.Отбор. Система рассматривает такие отборы как своего рода "фиксированные" для данного сеанса открытия формы.Важно отметить, что конфликт происходит только если отборы касаются одного и того же поля. Если фиксированный отбор установлен по "Организации", а пользовательский по "Дате", конфликта не будет, и они успешно объединятся.
Мы рассмотрим несколько эффективных подходов для решения проблемы конфликта отборов, начиная с конкретного решения, найденного автором вопроса, и заканчивая общими рекомендациями.
Одним из наиболее эффективных способов борьбы с этой проблемой, особенно когда фиксированный отбор приходит через параметры формы, является перехват момента создания формы на сервере и программное изменение её параметров.
Суть подхода: При открытии формы, если мы видим, что в Форма.Параметры.Отбор уже присутствует фиксированный отбор по полю "Организация" (или любому другому, с которым возникает конфликт), мы можем:
Форма.Параметры.Отбор, чтобы он больше не считался фиксированным.Рассмотрим по шагам, как это можно реализовать в расширении:
Шаг 1: Перехват события ПриСозданииНаСервере
В расширении мы переопределяем процедуру ПриСозданииНаСервере для нужной формы списка. Если форма является стандартной формой списка документов в БСП, то часто для подобных задач используется процедура ПодключаемыеКоманды.ПриСозданииНаСервере, которую можно переопределить.
Например, в модуле формы документа, к которой привязан список выбора, или в модуле расширения для этой формы:
// В расширении, в модуле формы, для которой нужен обход
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Выполняем действия типовой конфигурации, если это переопределенная процедура
// или вызываем процедуру из основной конфигурации
// ВызовПроцедурыИсходнойКонфигурации(ЭтотОбъект, "ПриСозданииНаСервере", Отказ, СтандартнаяОбработка);
// Анализируем параметры формы
АнализироватьПараметрыОтбораОрганизации(ЭтотОбъект);
// ... дальнейший код, если есть ...
КонецПроцедуры
&НаСервере
Процедура АнализироватьПараметрыОтбораОрганизации(Форма)
// Проверяем наличие отбора по "Организации" в параметрах формы
ЗначениеОтбораПоОрганизации = Неопределено;
Если Форма.Параметры.Отбор.Свойство("Организация", ЗначениеОтбораПоОрганизации) Тогда
// Отбор по Организации найден в фиксированных настройках формы.
// Удаляем его из фиксированных параметров, чтобы избежать конфликта.
Форма.Параметры.Отбор.Удалить("Организация");
// Теперь нам нужно применить этот отбор как пользовательский.
// Для этого мы можем использовать функцию БСП
// ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка
// или напрямую добавить в пользовательские настройки динамического списка формы.
// Предположим, что динамический список на форме называется "Список"
// Если это форма выбора, то часто это свойство Формы.ДинамическийСписок
ДинамическийСписок = Форма.Список;
Если ДинамическийСписок <> Неопределено Тогда
// Создаем новый элемент отбора для пользовательских настроек
НовыйЭлементОтбора = ДинамическийСписок.Настройки.ПользовательскиеНастройки.Элементы.Добавить(Тип("ЭлементОтбораКомпоновщикаНастроек"));
НовыйЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновщикаНастроек("Организация");
НовыйЭлементОтбора.ВидСравнения = ВидСравненияКомпоновщикаНастроек.Равно;
НовыйЭлементОтбора.ПравоеЗначение = ЗначениеОтбораПоОрганизации;
НовыйЭлементОтбора.Использование = Истина;
НовыйЭлементОтбора.РежимОтображения = РежимОтображенияЭлементаНастройки.Всегда; // или РежимОтображенияЭлементаНастройки.Недоступен
НовыйЭлементОтбора.ИдентификаторПользовательскойНастройки = "ОтборПоОрганизацииИзПараметров"; // Уникальный идентификатор
// Важно! Для применения изменений нужно обновить динамический список
// В зависимости от конфигурации и версии БСП, это может произойти автоматически
// или потребуется вызов Форма.Список.Обновить() / Форма.Список.ЗагрузитьНастройкиКомпоновкиДанных()
// или ОбщегоНазначенияКлиентСервер.НастроитьДинамическийСписок(ДинамическийСписок, ...);
// Также, можно использовать специальную функцию БСП, как предложено в сообщении 8
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
ДинамическийСписок,
"Организация",
ЗначениеОтбораПоОрганизации,
ВидСравнения.Равно,
НСтр("ru = 'Организация'"), // Представление отбора для пользователя
Истина,
РежимОтображенияЭлементаНастройки.Всегда,
"ОтборПоОрганизацииИзПараметров"
);
// Если вы использовали ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка,
// прямое добавление в Настройки.ПользовательскиеНастройки.Элементы может быть излишним,
// так как функция БСП делает это сама.
// Но важно понять, что именно делает эта функция и как она взаимодействует с общими настройками.
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важные моменты:
Форма.Список или Элементы.Список).ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка (сообщение 8) является предпочтительным, так как это стандартный и поддерживаемый БСП метод работы с отборами динамических списков. Он заботится о корректном формировании элемента отбора и его применении.СписокПередЗагрузкойПользовательскихНастроекНаСервереНачиная с версии платформы 8.3.3.721, для динамического списка управляемой формы были добавлены новые события, позволяющие обойти ошибку программно. Рекомендуется использовать обработчик события СписокПередЗагрузкойПользовательскихНастроекНаСервере.
Суть подхода: В этом обработчике мы можем проанализировать, какие пользовательские настройки собирается загрузить платформа, и если среди них есть отбор по тому же полю, что и фиксированный отбор (пришедший из параметров формы), то удалить конфликтный пользовательский отбор из загружаемых настроек. Это позволит платформе успешно применить фиксированный отбор, не встречая конфликтующего пользовательского.
Рассмотрим пример кода для данного обработчика:
&НаСервере
Процедура СписокПередЗагрузкойПользовательскихНастроекНаСервере(Настройки)
// Настройки - это объект типа КомпоновщикНастроекКомпоновкиДанных,
// содержащий загружаемые пользовательские настройки.
// 1. Проверяем, есть ли фиксированный отбор по Организации в параметрах формы.
// Это означает, что форма открыта с предопределенным отбором.
ФиксированныйОтборОрганизация = Неопределено;
Если ЭтаФорма.Параметры.Отбор.Свойство("Организация", ФиксированныйОтборОрганизация) Тогда
// 2. Если фиксированный отбор по Организации существует,
// ищем пользовательский отбор по тому же полю среди загружаемых настроек.
// Нам нужно пройти по всем элементам отбора в Настройки.Элементы
// и найти тот, который относится к "Организации".
ИндексУдаления = -1;
Для Индекс = 0 По Настройки.Элементы.Количество() - 1 Цикл
ЭлементНастройки = Настройки.Элементы[Индекс];
// Проверяем, является ли текущий элемент отбором
Если ТипЗнч(ЭлементНастройки) = Тип("ЭлементОтбораКомпоновщикаНастроек") Тогда
// Проверяем, относится ли отбор к полю "Организация"
Если ЭлементНастройки.ЛевоеЗначение.Представление = "Организация" ИЛИ
(ЭлементНастройки.ЛевоеЗначение.Поле <> Неопределено И ЭлементНастройки.ЛевоеЗначение.Поле.Имя = "Организация") Тогда
// Нашли пользовательский отбор по Организации, который будет конфликтовать.
// Отключаем его использование или удаляем.
ЭлементНастройки.Использование = Ложь; // Предпочтительнее отключить, чем удалять, чтобы не терять настройку
// Или можно полностью удалить:
// ИндексУдаления = Индекс;
// Прервать;
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Если решили удалять элемент, то удаляем его после завершения цикла
// (чтобы избежать проблем с изменением коллекции в цикле)
// Если ИндексУдаления <> -1 Тогда
// Настройки.Элементы.Удалить(Настройки.Элементы[ИндексУдаления]);
// КонецЕсли;
// Важно: если мы просто отключили Использование = Ложь,
// то платформа применит фиксированный отбор.
// Если же нам нужно, чтобы этот отбор все равно был активен,
// но как пользовательский, а не фиксированный, то этот подход
// придется комбинировать с предыдущим (извлечением из параметров формы).
// В этом сценарии (ПередЗагрузкойПользовательскихНастроек),
// цель - устранить конфликт, а не переопределить логику.
// Поэтому достаточно просто отключить пользовательский отбор.
КонецЕсли;
КонецПроцедуры
Преимущества этого метода: он позволяет сохранить пользовательские настройки, просто временно отключая их использование, когда присутствует фиксированный отбор.
Для более удобного и стандартного управления отборами динамических списков в БСП предусмотрены специальные функции. Одна из них – ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка (как упомянуто в сообщении 8).
Применение: Эта функция позволяет программно добавить или изменить элемент отбора для динамического списка, при этом корректно работая с его настройками. Её удобно использовать после того, как вы удалили конфликтный отбор из Форма.Параметры.Отбор (как в первом способе), чтобы затем применить его как обычный пользовательский отбор.
// Пример использования ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка
// (предполагаем, что ЗначениеОтбораПоОрганизации было извлечено из Форма.Параметры.Отбор
// и удалено оттуда)
// ДинамическийСписок - это ссылка на элемент формы типа ДинамическийСписок
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
ДинамическийСписок, // Ссылка на динамический список формы
"Организация", // Имя поля, по которому устанавливается отбор
ЗначениеОтбораПоОрганизации, // Правое значение отбора (ранее извлеченное)
ВидСравнения.Равно, // Вид сравнения
НСтр("ru = 'Организация'"), // Представление отбора для пользователя
Истина, // Использование (включен/выключен)
РежимОтображенияЭлементаНастройки.Всегда, // Режим отображения (например, всегда виден)
"ОтборПоОрганизацииВРасширении" // Уникальный идентификатор пользовательской настройки
);
Эта функция позволяет более гибко управлять программными отборами, интегрируя их в стандартный механизм настроек динамического списка БСП.
Если требуется очень глубокая кастомизация или если предыдущие методы не подходят, можно рассмотреть вариант с изменением текста запроса динамического списка. Этот метод требует глубокого понимания построения запросов и может быть более трудоемким.
Суть подхода: Вместо того чтобы полагаться на механизм отборов компоновщика настроек, вы можете встроить условие отбора непосредственно в текст запроса, который выбирает данные для динамического списка. Отбор при этом может быть параметризован, а значения параметров устанавливаются программно.
// Пример модификации запроса динамического списка
// Этот код обычно размещается в обработчике ПриСозданииНаСервере или ПриОткрытии
&НаСервере
Процедура УстановитьОтборВЗапросе(Форма)
Если Форма.Список.ОсновнаяТаблицаЗапроса = "Документ.ПлатежноеПоручение" Тогда
// Пример получения значения отбора
ЗначениеОтбораПоОрганизации = Константы.ОсновнаяОрганизация.Получить(); // Или из параметров формы
// Добавляем условие в запрос
Если Не Форма.Список.ПроизвольныйЗапрос Тогда
Форма.Список.ПроизвольныйЗапрос = Истина;
Форма.Список.ТекстЗапроса = "ВЫБРАТЬ
| ПлатежноеПоручение.Ссылка,
| ...
|ИЗ
| Документ.ПлатежноеПоручение КАК ПлатежноеПоручение
|ГДЕ
| ПлатежноеПоручение.Организация = &ПараметрОрганизация";
КонецЕсли;
Форма.Список.Параметры.УстановитьЗначениеПараметра("ПараметрОрганизация", ЗначениеОтбораПоОрганизации);
Форма.Список.Обновить();
КонецЕсли;
КонецПроцедуры
Недостатки: Этот метод более инвазивен, сложнее в поддержке и может конфликтовать с другими механизмами БСП, работающими с динамическим списком. Также он может быть сброшен при обновлении конфигурации, если вы не используете расширения для изменения запроса.
Поскольку "Связи параметров выбора" часто являются источником фиксированных отборов, полезно проанализировать их настройку.
ПриИзменении для поля-источника связи.Этот подход может быть полезен, если вы имеете полный контроль над конфигурацией и можете изменить источник фиксированного отбора, а не только обходить его последствия.
При работе с конфликтами отборов в 1С:Предприятии всегда учитывайте следующие моменты:
В целом, проблема конфликта фиксированных и пользовательских отборов является известной особенностью платформы 1С. Хотя платформа не предусматривает прямого объединения отборов по "И" для одного и того же поля, существуют эффективные программные методы обхода. Мы рассмотрели несколько таких подходов, включая перехват параметров формы, использование событий динамического списка и функций БСП. Выбор конкретного метода зависит от специфики вашей задачи, версии платформы и конфигурации.