Как настроить отбор по реквизиту, если ведущее поле имеет составной тип?

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

Рассмотрим распространенную задачу при разработке на управляемых формах 1С: в документе есть реквизит Клиент составного типа (например, справочники «Организации» и «Контрагенты») и реквизит Договор. У договоров есть реквизит ВладелецДоговора. Нам нужно отфильтровать список договоров при подборе так, чтобы отображались только договоры выбранного клиента.

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

Вариант 1: Программная установка связей параметров выбора

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

Для этого мы воспользуемся объектом платформы СвязьПараметраВыбора:


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

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

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

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

В этой процедуре мы можем проанализировать переданные параметры. Если передан клиент, мы программно формируем нужный список значений с учетом владельца, либо модифицируем структуру Параметры.Отбор, добавив туда нужного клиента, предварительно установив СтандартнаяОбработка = Ложь.

Вариант 3: Событие формы ОбработкаВыбора (защита от вставки из буфера)

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

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


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

Вариант 4: Проверка в модуле объекта с учетом обменов данными

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

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


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Пропускаем проверку при обмене данными
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    Если ЗначениеЗаполнено(Договор) И ЗначениеЗаполнено(Клиент) Тогда
        Если Договор.ВладелецДоговора <> Клиент Тогда
            Отказ = Истина;
            Сообщить("В документе указан договор, не принадлежащий выбранному клиенту.");
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

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

← На главную