Как настроить отбор в форме выбора документа на основе табличной части другого документа

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

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача реализации сложной логики подбора элементов. Типичный сценарий: в форме обработки или документа при выборе значения в одном поле (например, Документ2) необходимо учитывать данные, уже введенные в другом поле (например, Документ1). Если Документ2 должен присутствовать в табличной части Документа1, стандартных механизмов «Связи параметров выбора» в свойствах реквизита может быть недостаточно, особенно если между объектами нет прямой ссылки в метаданных.

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

Шаг 1. Программный вызов формы выбора с передачей параметров

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

Рассмотрим пример кода в модуле формы обработки. Допустим, у нас есть реквизит ОбъектДляФильтрации (тот самый Документ1), и нам нужно открыть форму выбора для реквизита ВыбираемыйДокумент (Документ2):


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

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

Шаг 2. Настройка динамического списка в форме выбора

Теперь перейдем к работе с формой выбора Документа2. Чтобы отбор сработал, нам нужно модифицировать текст запроса динамического списка (основного реквизита Список) и установить значение параметра, переданного из первой формы.

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

Правильный текст запроса в схеме динамического списка должен выглядеть примерно так:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Документ2.Ссылка КАК Ссылка,
    Документ2.Номер КАК Номер,
    Документ2.Дата КАК Дата
ИЗ
    Документ.Документ2 КАК Документ2
ГДЕ
    Документ2.Ссылка В (
        ВЫБРАТЬ
            ТЧ.Документ2
        ИЗ
            Документ.Документ1.ТабличнаяЧасть1 КАК ТЧ
        ГДЕ
            ТЧ.Ссылка = &ПараметрДокумент1
    )
    ИЛИ &ПараметрДокумент1 = ЗНАЧЕНИЕ(Документ.Документ1.ПустаяСсылка)

Важные моменты:

  1. Ключевое слово РАЗЛИЧНЫЕ гарантирует отсутствие дублей в списке выбора.
  2. Использование подзапроса в условии ГДЕ ... В (...) позволяет платформе оптимизировать выполнение на уровне SQL.
  3. Добавление условия ИЛИ &ПараметрДокумент1 = ЗНАЧЕНИЕ(...) позволяет видеть весь список, если фильтр не задан.

Шаг 3. Установка параметров при создании формы

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


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверяем, передан ли наш параметр в структуре "Параметры"
    Если Параметры.Свойство("ДокументФильтр") И ЗначениеЗаполнено(Параметры.ДокументФильтр) Тогда
        
        // Устанавливаем значение параметра в динамический список
        Список.Параметры.УстановитьЗначениеПараметра("ПараметрДокумент1", Параметры.ДокументФильтр);
        
    Иначе
        
        // Если параметр не передан, устанавливаем пустую ссылку, чтобы условие "ИЛИ" в запросе сработало
        Список.Параметры.УстановитьЗначениеПараметра("ПараметрДокумент1", Документы.Документ1.ПустаяСсылка());
        
    КонецЕсли;
    
КонецПроцедуры

Шаг 4. Использование фиксированных настроек компоновки

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

Рассмотрим, как это реализовать программно:


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

Этот метод считается более надежным для жестких бизнес-ограничений, так как он полностью скрывает механику отбора от конечного пользователя.

Шаг 5. Обработка быстрого ввода (поиск по строке)

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

Для решения этой проблемы необходимо задействовать обработчик ОбработкаПолученияДанныхВыбора в модуле менеджера Документа2. В этот обработчик также можно передать параметры через свойство элемента формы ПараметрыВыбора. На форме обработки, где выбирается Документ2, в событии ПриИзменении для Документа1 следует динамически обновлять свойство ПараметрыВыбора:


&НаКлиенте
Процедура ОбъектДляФильтрацииПриИзменении(Элемент)
    
    // Обновляем параметры выбора для поля Документ2, чтобы работал быстрый поиск
    НовыйПараметр = Новый ПараметрВыбора("Отбор.ДокументФильтр", Объект.ОбъектДляФильтрации);
    МассивПараметров = Новый Массив;
    МассивПараметров.Добавить(НовыйПараметр);
    
    Элементы.ВыбираемыйДокумент.ПараметрыВыбора = Новый ФиксированныйМассив(МассивПараметров);
    
КонецПроцедуры

Резюме и рекомендации

Подведем итог. Для качественной реализации фильтрации в форме выбора необходимо:

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

← На главную