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