Как на форме 1С отфильтровать справочник по другому реквизиту (выбор договора по контрагенту)

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

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

Давайте подробно разберем, какими способами можно решить эту задачу в современных управляемых формах 1С (платформа 8.3), а также затронем особенности реализации для старых обычных форм (платформа 8.2 и ниже). Мы изучим как быстрый декларативный метод настройки в конфигураторе, не требующий написания ни одной строчки кода, так и гибкие программные варианты решения.

Важное условие: Иерархия и подчинение справочников

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

Давайте проверим это в конфигураторе:

  1. Найдем в дереве метаданных справочник, в котором хранятся договоры (например, ДоговорыКонтрагентов), и откроем его свойства.
  2. Перейдем на вкладку Владельцы.
  3. В списке «Владельцы справочника» должен быть обязательно указан (отмечен галочкой) справочник Контрагенты.

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

Теперь рассмотрим основные способы настройки отбора.

Способ 1. Декларативная настройка через «Связи параметров выбора»

Это самый простой, быстрый и рекомендуемый способ. Платформа «1С:Предприятие 8» предоставляет встроенный декларативный механизм связи реквизитов, который работает полностью на уровне настроек конфигурации без программирования.

Настроить это свойство можно в двух местах в зависимости от вашей задачи:

  1. В свойствах реквизита объекта (документа/справочника): Если вы хотите, чтобы фильтр по контрагенту работал во всех формах, где будет размещен реквизит Договор, настраивайте связь прямо в дереве метаданных. Откройте свойства реквизита Договор в вашем документе, найдите свойство Связи параметров выбора и нажмите кнопку с троеточием.
  2. В свойствах элемента формы: Если ограничение выбора требуется применить только на одной конкретной форме, откройте эту форму в конфигураторе. Выделите элемент формы (поле ввода) Договор, откройте его палитру свойств, найдите строку Связи параметров выбора и нажмите кнопку выбора.

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

  1. В появившейся таблице нажмите кнопку Добавить.
  2. В колонке Имя параметра нам нужно указать путь для фильтрации. Поскольку наш справочник договоров подчинен контрагентам, выберите из списка или введите вручную предопределенный параметр: Отбор.Владелец. Это указывает системе, что список договоров нужно отфильтровать по владельцу.
  3. В колонке Реквизит выберите поле формы, значение которого будет выступать в качестве фильтра. В нашем случае это реквизит Контрагент (или Объект.Контрагент, если мы работаем в контексте объекта формы).
  4. В колонке Режим изменения крайне рекомендуется выбрать значение Очищать. Разберем подробнее, зачем это нужно: если пользователь сначала заполнит контрагента «Альфа» и выберет его договор, а затем решит изменить контрагента на «Бета», поле договора автоматически очистится. Это защитит базу данных от некорректных и несогласованных данных (ситуации, когда в документе указан контрагент «Бета», а договор остался от контрагента «Альфа»).

После этой простой настройки запустите сеанс в режиме «1С:Предприятие» и проверьте результат. Теперь при открытии списка выбора или формы выбора договора система будет автоматически показывать только договоры выбранного контрагента.

Способ 2. Программный отбор в управляемых формах через событие «НачалоВыбора»

Декларативный метод прекрасен, но что делать, если логика вашей задачи выходит за рамки простого подчинения? Например, вам нужно сделать так, чтобы при пустом контрагенте пользователь мог выбирать любые договоры, или отбор должен накладываться по сложному условию (например, по типу договора, его статусу или периоду действия), зависящему от других реквизитов формы.

В таких сценариях мы используем программное управление процессом выбора. Для этого нам понадобится обработчик события НачалоВыбора для элемента формы Договор.

Давайте разберем по шагам, как это реализовать:

  1. Откройте форму документа в конфигураторе.
  2. Выберите элемент формы Договор и в палитре свойств в самом низу найдите событие НачалоВыбора. Нажмите на кнопку создания процедуры (с лупой).
  3. Система создаст шаблон клиентской процедуры в модуле формы.

Запишем в созданный обработчик следующий код:


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

Используя этот подход, мы полностью контролируем поведение формы выбора и можем накладывать абсолютно любые динамические фильтры в зависимости от ситуации в документе.

Способ 3. Динамическая установка параметров выбора на сервере

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

Для этого используется свойство элемента формы ПараметрыВыбора. Давайте проанализируем, как программно ограничить выбор договоров, например, при открытии формы или при изменении контрагента:


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

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

Обеспечение целостности данных при изменении контрагента

Когда мы связываем два поля отбором, очень важно обрабатывать сценарий изменения родительского реквизита. Если пользователь сначала выбрал контрагента «А» и договор «Договор А», а затем изменил контрагента на «Б», то старый договор останется заполненным в поле ввода, хотя он больше не подходит под условия отбора.

Чтобы избежать этой критической ошибки ведения учета, мы должны обязательно очищать или пересчитывать поле Договор при изменении поля Контрагент. Разберем, как написать обработчик события ПриИзменении для поля контрагента:


&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
    
    // При изменении контрагента мы обязаны очистить договор,
    // чтобы предотвратить запись несогласованных данных в базу
    Объект.Договор = ПредопределенноеЗначение("Справочник.ДоговорыКонтрагентов.ПустаяСсылка");
    
    // Если используется Способ 3 с установкой параметров на сервере,
    // то здесь же вызываем обновление параметров выбора:
    // УстановитьОтборДоговоровНаСервере();
    
КонецПроцедуры

Способ 4. Реализация в обычных (неуправляемых) формах (1С 8.1 / 8.2)

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

Интерактивная настройка в свойствах поля:

  1. Откройте обычную форму документа в конфигураторе.
  2. Выделите поле ввода Договор и откройте его свойства.
  3. Найдите свойство Связь по владельцу.
  4. Нажмите кнопку выбора и укажите элемент формы, который отображает контрагента (обычно это поле Контрагент).

После этого платформа автоматически свяжет эти два поля на форме.

Программный метод в обычных формах:

Если требуется управлять отбором программно в неуправляемом интерфейсе, мы используем событие поля ввода ПриНачалеВыбора:


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

Мы детально изучили все возможные варианты фильтрации связанных реквизитов. Используйте декларативный способ настройки через свойства связи параметров выбора для стандартных ситуаций подчинения справочников — это сэкономит ваше время и сохранит производительность системы. В сложных случаях, требующих гибких условий и дополнительных проверок, смело переходите к программной обработке событий начала выбора на клиенте или динамической установке параметров на сервере.

← На главную