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