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