В практике разработки на платформе 1С часто возникает задача: ограничить пользователю список доступных элементов справочника (например, организаций или складов) таким образом, чтобы он видел только разрешенные ему позиции. При этом использование стандартного механизма RLS (Record Level Security) может быть нежелательным из-за падения производительности или сложности настройки. Однако простое ограничение формы выбора не спасает, если пользователь начинает вводить название объекта прямо в поле ввода документа (ввод по строке). Разберем, как решить эту задачу универсально для всей системы.
Для управляемых форм (платформа 8.2 и 8.3) существует элегантное решение на уровне метаданных. Мы воспользуемся обработчиком ОбработкаПолученияДанныхВыбора, который располагается в модуле менеджера соответствующего справочника. Этот метод вызывается платформой каждый раз, когда система пытается подобрать данные: при вводе по строке, при нажатии кнопки выбора или при автоподборе.
Рассмотрим пример кода, который нужно разместить в модуле менеджера справочника (например, Организации):
Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)
// Если мы хотим полностью переопределить логику поиска, отключаем стандартную обработку
СтандартнаяОбработка = Ложь;
// Создаем список значений, который будет предложен пользователю
ДанныеВыбора = Новый СписокЗначений;
// Формируем запрос с учетом прав текущего пользователя
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Организации.Ссылка КАК Ссылка,
| Организации.Наименование КАК Наименование
|ИЗ
| Справочник.Организации КАК Организации
|ГДЕ
| Организации.Наименование ПОДОБНО &СтрокаПоиска
| И Организации.Ссылка В (&ДоступныеОрганизации)";
// Параметры.СтрокаПоиска содержит то, что пользователь ввел в поле
Запрос.УстановитьПараметр("СтрокаПоиска", "%" + Параметры.СтрокаПоиска + "%");
// Здесь должна быть ваша функция, определяющая массив доступных ссылок
ДоступныеСсылки = ПолучитьДоступныеОрганизацииДляТекущегоПользователя();
Запрос.УстановитьПараметр("ДоступныеОрганизации", ДоступныеСсылки);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
ДанныеВыбора.Добавить(Выборка.Ссылка, Выборка.Наименование);
КонецЦикла;
КонецПроцедуры
Важный нюанс: В параметре Параметры также передается структура Отбор. Если в поле ввода на форме установлены дополнительные связи параметров выбора (например, отбор по владельцу), их нужно учитывать в запросе, чтобы не нарушить логику работы конкретных форм.
Иногда программисты сталкиваются с тем, что в обычных полях ввода код работает, а в отчетах на базе СКД или в динамических списках пользователь все равно видит лишние данные. Проанализируем основные причины этой ситуации:
ОбработкаПолученияДанныхВыбора. Чтобы этого избежать, в свойствах поля ввода на критически важных формах можно установить свойство ИсторияВыбораПриВводе в значение Не использовать.Быстрый выбор, система может пытаться подгрузить весь список сразу, что иногда обходит стандартные механизмы автоподбора. Проверьте это свойство в палитре свойств справочника.Механизм ОбработкаПолученияДанныхВыбора появился в управляемом приложении. Если ваша конфигурация использует обычные формы, нам придется действовать иначе. В обычном приложении для каждого конкретного поля ввода на форме необходимо использовать событие АвтоПодбор.
Разберем пример реализации для обычной формы:
Процедура ОрганизацияАвтоПодбор(Элемент, Текст, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Ссылка ИЗ Справочник.Организации ГДЕ Наименование ПОДОБНО &Текст";
Запрос.УстановитьПараметр("Текст", Текст + "%");
// Здесь добавляем фильтр по доступным организациям
// ...
Список = Новый СписокЗначений;
Список.ЗагрузитьЗначения(Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"));
ДанныеВыбора = Список;
КонецПроцедуры
Однако, как справедливо заметил автор вопроса, прописывать это в каждой форме трудозатратно. В таком случае рекомендуется использовать подписки на события.
Если нам нужно гарантировать, что пользователь не просто "не увидел" лишнее, но и физически не смог сохранить документ с недопустимым значением, мы можем использовать общую подписку на событие. Это "последний рубеж" обороны, который сработает даже если ввод по строке каким-то образом обошел фильтры.
Создадим общую подписку на событие ПередЗаписью для всех документов, где используется справочник Организации. Проанализируем пример кода:
Процедура ПроверитьДоступностьОрганизацийПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
#Если Клиент Тогда
Если Отказ Или РежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения Тогда
Возврат;
КонецЕсли;
ТипОрганизации = Тип("СправочникСсылка.Организации");
// Перебираем все реквизиты объекта через метаданные
Для Каждого Реквизит Из Источник.Метаданные().Реквизиты Цикл
// Проверяем, совпадает ли тип реквизита с искомым справочником
Если Реквизит.Тип.СодержитТип(ТипОрганизации) Тогда
ЗначениеРеквизита = Источник[Реквизит.Имя];
Если ЗначениеЗаполнено(ЗначениеРеквизита) Тогда
// Вызываем проверку прав доступа к этой конкретной ссылке
Если Не ОрганизацияРазрешенаДляПользователя(ЗначениеРеквизита) Тогда
Сообщить("У вас нет прав на использование организации: " + ЗначениеРеквизита);
Отказ = Истина;
Прервать;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
#КонецЕсли
КонецПроцедуры
Обратите внимание: Использование диалоговых окон (например, ВвестиЗначение или Вопрос) внутри подписок на события крайне не рекомендуется, так как запись может происходить на сервере или в фоновом задании, где интерактивные действия невозможны. Проверка должна возвращать Отказ = Истина и выводить сообщение об ошибке.
Еще один способ ограничить ввод по строке во всех формах — использование свойства Параметры выбора непосредственно в свойствах реквизита в дереве метаданных. Если ваше условие достаточно простое (например, Отбор.ПометкаУдаления(Ложь) или Отбор.Статус(Энум.Статусы.Активен)), вы можете задать этот отбор прямо в конфигураторе. Платформа будет автоматически применять этот фильтр ко всем полям ввода, спискам и даже настройкам отборов в отчетах. Для гибкой настройки ограничений видимости данных подойдёт инструмент для установки отборов в отчетах и списках СКД.
Подводя итог, можно сказать, что наиболее надежным и современным методом для 1С 8.3 является сочетание ОбработкаПолученияДанныхВыбора в модуле менеджера (для удобства пользователя) и подписки на событие ПередЗаписью (для жесткого контроля данных).