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