При разработке документов и справочников в среде управляемых форм 1С:Предприятие 8.3 часто требуется реализовать взаимосвязанный выбор расчетного счета организации и обслуживающего банка. Типичная структура реквизитов включает в себя организацию (ссылка на справочник организаций), банк (ссылка на классификатор банков) и банковский счет (ссылка на справочник банковских счетов).
Разработчики нередко пытаются настроить декларативные свойства поля ввода «Счет» через «Связи параметров выбора», указывая два условия: отбор владельца по организации и отбор банка по значению реквизита «Банк». Однако при таком подходе возникают две существенные проблемы:
Механизм «Связи параметров выбора» (Choice Parameter Links) в платформе 1С предназначен для жесткой декларативной привязки фильтрации одного поля к текущему значению другого поля на форме. При его использовании действуют строгие системные правила:
Неопределено или пустую ссылку), платформа формирует запрос к динамическому списку выбора с условием равенства пустой ссылке. Исключением является только отбор по владельцу в подчиненных справочниках, где пустое значение владельца блокирует выбор или вызывает предупреждение платформы, но для произвольных реквизитов отбор накладывается буквально.Прежде чем программно обходить ограничения платформы, важно проанализировать структуру данных типовых конфигураций (1С:Бухгалтерия, 1С:ERP, 1С:Управление торговлей):
Справочник «Банковские счета» подчинен справочнику «Организации» (или «Контрагенты»). Это означает, что у конкретной организации обычно заведено небольшое количество счетов (от одного до нескольких десятков). Внутри каждого элемента справочника «Банковские счета» уже есть обязательный реквизит «Банк» (или ссылка на классификатор БИК/банков).
В типовых конфигурациях цепочка выбора строится в обратную сторону: пользователь выбирает организацию, затем выбирает расчетный счет (отфильтрованный по владельцу-организации), а поле «Банк» на форме документа заполняется автоматически из выбранного счета либо вообще не хранится в документе как отдельный реквизит, а отображается через реквизит счета (путь к данным: Объект.БанковскийСчет.Банк).
Если специфика прикладной задачи все же требует наличия отдельного поля «Банк» и гибкого управления отборами, применяются альтернативные технические решения.
Если бизнес-логика допускает выбор счета без предварительного указания банка, наиболее эргономичным решением является снятие отбора по банку в связях параметров выбора и автоматическое заполнение банка в обработчике изменения счета.
В свойствах элемента формы «Счет» в конфигураторе оставляется только одна связь параметров выбора:
Отбор.Владелец(Объект.Организация)
В модуле формы реализуется клиент-серверный обработчик события «ПриИзменении»:
&НаКлиенте
Процедура СчетПриИзменении(Элемент)
Если ЗначениеЗаполнено(Объект.Счет) Тогда
Объект.Банк = ПолучитьБанкСчета(Объект.Счет);
Иначе
Объект.Банк = ПредопределенноеЗначение("Справочник.КлассификаторБанков.ПустаяСсылка");
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьБанкСчета(Знач СсылкаНаСчет)
Возврат СсылкаНаСчет.Банк;
КонецФункции
Преимущества: Минимальное количество кода, максимальное соответствие стандартам разработки 1С, корректно работает стандартный ввод по строке.
Ограничения: Не позволяет отфильтровать счета заранее, если у организации открыто множество счетов в одном и том же банке и пользователь хочет отсечь остальные счета выбором банка.
Если необходимо жестко обязать пользователя сначала указать банк, стандартное открытие формы выбора расчетного счета перехватывается в событии поля ввода.
В свойствах элемента «Счет» связь с банком также удаляется из декларативных настроек (остается только связь с организацией). В модуле управляемой формы настраивается обработчик события «НачалоВыбора»:
&НаКлиенте
Процедура СчетНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
Если Не ЗначениеЗаполнено(Объект.Организация) Тогда
СтандартнаяОбработка = Ложь;
ПоказатьПредупреждение(, НСтр("ru = 'Сначала укажите организацию!'"));
Возврат;
КонецЕсли;
Если Не ЗначениеЗаполнено(Объект.Банк) Тогда
СтандартнаяОбработка = Ложь;
Оповещение = Новый ОписаниеОповещения("ПослеВыбораБанка", ЭтотОбъект);
ПараметрыФормы = Новый Структура;
ПоказатьЗначение(Оповещение, Объект.Банк);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПослеВыбораБанка(РезультатВыбора, ДополнительныеПараметры) Экспорт
Если ЗначениеЗаполнено(РезультатВыбора) Тогда
Объект.Банк = РезультатВыбора;
// После заполнения банка программно открываем выбор счета
Элементы.Счет.Выбрать();
КонецЕсли;
КонецПроцедуры
Преимущества: Полный контроль над очередностью заполнения полей формы.
Ограничения: Перехват события НачалоВыбора срабатывает только при интерактивном нажатии на кнопку с троеточием или нажатии клавиши F4. Если у поля включен быстрый ввод по строке, пользователь сможет начать вводить номер счета с клавиатуры в обход проверки, если не отключить автоподбор дополнительно.
Для реализации второго вопроса (наложение фильтра по банку только тогда, когда он фактически заполнен) платформа предоставляет программное свойство элемента формы ПараметрыВыбора. В отличие от метаданных связей, это свойство можно перезаписывать во время работы формы.
Свойство принимает значение типа ФиксированныйМассив, элементами которого являются объекты типа ПараметрВыбора. Алгоритм настраивается в обработчиках изменения банка и при инициализации формы:
&НаСервере
Процедура ОбновитьПараметрыВыбораСчетаНаСервере()
МассивПараметров = Новый Массив;
// Владелец устанавливается всегда
Если ЗначениеЗаполнено(Объект.Организация) Тогда
МассивПараметров.Добавить(Новый ПараметрВыбора("Отбор.Владелец", Объект.Организация));
КонецЕсли;
// Отбор по банку добавляется только при наличии значения
Если ЗначениеЗаполнено(Объект.Банк) Тогда
МассивПараметров.Добавить(Новый ПараметрВыбора("Отбор.Банк", Объект.Банк));
КонецЕсли;
Элементы.Счет.ПараметрыВыбора = Новый ФиксированныйМассив(МассивПараметров);
КонецПроцедуры
&НаКлиенте
Процедура БанкПриИзменении(Элемент)
ОбновитьПараметрыВыбораСчетаНаСервере();
// При смене банка ранее выбранный счет может стать невалидным
Если ЗначениеЗаполнено(Объект.Счет) Тогда
ПроверитьСоответствиеСчетаБанку();
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ОбновитьПараметрыВыбораСчетаНаСервере();
КонецПроцедуры
При таком подходе из настроек элемента формы в конфигураторе полностью удаляется статическая связь Отбор.Банк(Объект.Банк). Если банк не заполнен, в параметрах выбора передается только владелец, и форма выбора отображает все счета организации. Как только пользователь выбирает банк, массив параметров обновляется, и последующий выбор счета ограничивается выбранным банком.
Преимущества: Корректно поддерживается и диалог выбора из списка, и ввод по строке (автоподбор). Не нарушается поведение стандартных элементов интерфейса.
Ограничения: Требуется аккуратно отслеживать очистку реквизита «Счет», если пользователь изменил банк на другой, в котором данный расчетный счет не открыт.
Если бизнес-логика отбора содержит сложные составные условия, которые не укладываются в массив ПараметрыВыбора, выбор расчетного счета полностью переопределяется через вызов метода ОткрытьФорму.
&НаКлиенте
Процедура СчетНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ПараметрыФормы = Новый Структура;
Отбор = Новый Структура;
Если ЗначениеЗаполнено(Объект.Организация) Тогда
Отбор.Вставить("Владелец", Объект.Организация);
КонецЕсли;
Если ЗначениеЗаполнено(Объект.Банк) Тогда
Отбор.Вставить("Банк", Объект.Банк);
КонецЕсли;
ПараметрыФормы.Вставить("Отбор", Отбор);
ПараметрыФормы.Вставить("ЗакрыватьПриВыборе", Истина);
ОткрытьФорму("Справочник.БанковскиеСчета.ФормаВыбора", ПараметрыФормы, Элемент);
КонецПроцедуры
При передаче третьего параметра Элемент платформа автоматически оповестит элемент формы о выбранном значении и вызовет его событие «ОбработкаВыбора», после чего сработает стандартное событие «ПриИзменении».
ПараметрыВыбора. Он сохраняет встроенные механизмы полнотекстового поиска и автоподбора платформы 1С:Предприятие 8.3.НачалоВыбора и обязательным контролем очистки зависимых реквизитов при смене вышестоящих значений.