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