Как программно запретить выбор определенной номенклатуры в формах выбора 1С

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает бизнес-задача: ограничить список доступных для выбора товаров или услуг. Например, запретить выбирать архивную номенклатуру, позиции без цен или товары, заблокированные для продажи. При этом важно сделать это максимально эффективно, чтобы не перегружать систему и не вносить изменения в каждую форму каждого документа. Рассмотрим подробнее, как реализовать такой запрет, используя различные технические подходы.

Метод 1. Использование события ОбработкаПолученияФормы в модуле менеджера

Проанализируем наиболее изящный и централизованный способ. Вместо того чтобы прописывать логику в каждом документе, мы можем перехватить процесс открытия формы выбора непосредственно в модуле менеджера справочника Номенклатура. Это позволит нам наложить фильтры один раз для всей системы.

Разберем по шагам реализацию в модуле менеджера:


Процедура ОбработкаПолученияФормы(ВидФормы, Параметры, ВыбраннаяФорма, СтандартнаяОбработка)
    
    Если ВидФормы = "ФормаВыбора" ИЛИ ВидФормы = "ФормаСписка" Тогда
        
        // Если нам нужно исключить список номенклатуры, добавим отбор в параметры
        // Предположим, у нас есть массив или список запрещенных ссылок
        СписокЗапрета = ПолучитьСписокЗапрещеннойНоменклатуры(); 
        
        // Формируем структуру отбора, если она еще не создана
        Если Не Параметры.Свойство("Отбор") Тогда
            Параметры.Вставить("Отбор", Новый Структура);
        КонецЕсли;
        
        // Добавляем условие: ссылка НЕ В списке запрещенных
        // В управляемых формах для динамических списков это работает через фиксированные настройки
        Параметры.Отбор.Вставить("Ссылка", Новый ФиксированныйМассив(СписокЗапрета));
        // Важно: для инверсии (НЕ В) лучше использовать изменение текста запроса или динамический отбор
        
    КонецЕсли;
    
КонецПроцедуры

Стоит отметить, что прямая вставка в Параметры.Отбор работает только для простых равенств. Для условия "НЕ В" (не входит в список) нам потребуется более сложная манипуляция с динамическим списком внутри самой формы или использование параметров запроса.

Метод 2. Использование события ОбработкаПолученияДанныхВыбора

Выясним причину, по которой многие разработчики забывают про этот важный механизм. Пользователи часто выбирают номенклатуру не через форму выбора (кнопка с тремя точками), а просто набирая текст в поле ввода («ввод по строке»). Если мы ограничим только форму выбора, пользователь все равно сможет выбрать «запрещенку» быстрым вводом.

Для предотвращения этой ситуации в модуле менеджера справочника Номенклатура необходимо использовать следующий код:


Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Формируем собственный запрос для получения данных выбора
    ТекстЗапроса = 
    "ВЫБРАТЬ
    |    Номенклатура.Ссылка КАК Ссылка,
    |    Номенклатура.Наименование КАК Наименование
    |ИЗ
    |    Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |    Номенклатура.Наименование ПОДОБНО &ТекстПоиска
    |    И НЕ Номенклатура.Ссылка В (&СписокЗапрещенных)";
    
    Запрос = Новый Запрос(ТекстЗапроса);
    Запрос.УстановитьПараметр("ТекстПоиска", "%" + Параметры.СтрокаПоиска + "%");
    Запрос.УстановитьПараметр("СписокЗапрещенных", ПолучитьСписокЗапрещеннойНоменклатуры());
    
    ДанныеВыбора = Новый СписокЗначений;
    Выборка = Запрос.Выполнить().Выбрать();
    
    Пока Выборка.Следующий() Цикл
        ДанныеВыбора.Добавить(Выборка.Ссылка, Выборка.Наименование);
    КонецЦикла;
    
КонецПроцедуры

Этот метод гарантирует, что даже при вводе с клавиатуры запрещенные позиции просто не появятся в выпадающем списке.

Метод 3. Хранение списка исключений в Регистре сведений или Сегментах

Как справедливо заметили участники обсуждения, если список запрещенной номенклатуры постоянно растет, хранение его «в коде» или в массивах неэффективно. Проанализируем вариант с использованием Регистров сведений или Сегментов номенклатуры.

Преимущества использования Регистра сведений:

  1. Производительность: Поиск по индексированным полям регистра в SQL-запросе выполняется мгновенно.
  2. Гибкость: В регистре можно указать дополнительные измерения: «Организация», «Склад» или «Пользователь», для которых действует запрет.
  3. Удобство: Пользователи могут сами наполнять этот регистр через простой интерфейс без участия программиста.

Для интеграции этого решения в динамический список формы выбора, рассмотрим пример модификации запроса:


// В обработчике ПриСозданииНаСервере формы выбора
ТекстЗапроса = Список.ТекстЗапроса;
ТекстЗапроса = ТекстЗапроса + "
| ГДЕ Ссылка НЕ В (ВЫБРАТЬ Номенклатура ИЗ РегистрСведений.ЗапрещеннаяКВыборуНоменклатура) ";
Список.ТекстЗапроса = ТекстЗапроса;

Использование сегментов номенклатуры (если конфигурация типовая, например, УТ 11 или ERP) также является отличным вариантом, так как механизм сегментации уже оптимизирован платформой для работы с большими объемами данных.

Метод 4. Запрет через расширение конфигурации

Рассмотрим ситуацию, когда конфигурация находится на поддержке. Чтобы не снимать её с поддержки, мы будем использовать Расширения. Мы можем создать расширение и добавить в него модуль менеджера справочника Номенклатура.

Используем аннотацию &Вместо или &После для перехвата событий. Это позволит нам внедрить логику отбора, сохранив возможность легкого обновления основной конфигурации. Например:


&НаСервере
&Вместо("ПриСозданииНаСервере")
Процедура Расш_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Вызываем оригинальный обработчик
    ПродолжитьВызов(Отказ, СтандартнаяОбработка);
    
    // Добавляем наш фильтр в динамический список
    ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ссылка");
    ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.НеВСписке;
    ЭлементОтбора.ПравоеЗначение = ПолучитьМассивИсключений();
    ЭлементОтбора.Использование = Истина;
КонецПроцедуры

Метод 5. Использование события ОбработкаВыбораЗначения

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


&НаКлиенте
Процедура СписокОбработкаВыбораЗначения(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
    
    Если ЭтоЗапрещенныйТовар(ВыбранноеЗначение) Тогда
        СтандартнаяОбработка = Ложь; // Отменяем стандартный выбор
        ПоказатьПредупреждение(, "Выбор данной номенклатуры запрещен согласно внутренним правилам компании!");
    КонецЕсли;
    
КонецПроцедуры

Сравнительный анализ подходов

Выясним, какой метод лучше выбрать в зависимости от условий:

  1. Отбор в Динамическом списке: Лучший вариант для удобства пользователя. Пользователь просто не видит того, что нельзя выбирать. Это исключает лишние вопросы.
  2. ОбработкаПолученияДанныхВыбора: Обязателен к реализации вместе с первым методом, чтобы закрыть возможность выбора через ввод текста.
  3. Параметры выбора в метаданных: Подходит, если запрет статичен (например, «не выбирать услуги в документ поступления товаров»). Настраивается без кода в свойствах реквизита.
  4. RLS (Row Level Security): Самый мощный метод. Если настроить ограничение прав на уровне записей, номенклатура исчезнет не только из выбора, но и из всех отчетов. Однако помните, что RLS может существенно замедлить работу системы при некорректной настройке запросов.

Подведем итог: для реализации качественного запрета выбора рекомендуется комбинировать программную установку отбора в форме выбора (через ОбработкаПолученияФормы) и фильтрацию при вводе текста (через ОбработкаПолученияДанныхВыбора). В качестве хранилища списка запрещенных позиций лучше всего использовать индексированный Регистр сведений, что обеспечит высокую скорость работы даже при десятках тысяч позиций номенклатуры.

← На главную