Как получить штрихкод по номенклатуре в 1С?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При разработке интеграций, настройке обменов данными, печати этикеток или формировании прайс-листов разработчики часто сталкиваются с необходимостью быстро получить штрихкод конкретной позиции номенклатуры. Нередко написанная функция возвращает пустое значение, даже если штрихкод заведен в системе. Рассмотрим причины возникновения этой проблемы, разберем типичные ошибки и составим надежные и производительные алгоритмы для получения штрихкодов в различных конфигурациях 1С.

Анализ проблемы: почему запрос к регистру сведений возвращает пустой результат

Разберем исходную ситуацию, когда запрос к регистру сведений не находит запись:

  1. Передача объекта вместо ссылки: Если в функцию передается объект (например, из формы редактирования или обработчика обмена) типа СправочникОбъект.Номенклатура, прямое сравнение в запросе РегШтрихкоды.Владелец = &Владелец вернет Ложь. Запрос в 1С ожидает параметр типа СправочникСсылка.
  2. Несохраненный элемент: Если номенклатура создана программно и еще не записана в базу данных, ее ссылка является пустой (СправочникСсылка.Номенклатура.ПустаяСсылка()), поэтому в регистре связанных записей существовать не может.
  3. Несовпадение типов в составном измерении: В ряде конфигураций измерение Владелец имеет составной тип данных (включая характеристики или единицы измерения). Если тип переданного значения не совпадает с типом сохраненного владельца, условие равенства не сработает.
  4. Ошибки обхода выборки: Если после выполнения метода Выполнить() не вызывается метод Выбрать() и Следующий(), функция завершится без возврата нужного значения.

Решение 1: Универсальная функция получения штрихкода по ссылке

Рассмотрим правильный вариант написания функции для классических конфигураций, где данные хранятся в регистре сведений Штрихкоды. Обязательно позаботимся о том, чтобы на вход всегда попадала ссылка, а функция возвращала гарантированно строку (даже если штрихкод не найден):


Функция ПолучитьШтрихкодНоменклатуры(Знач НоменклатураСсылка) Экспорт
    
    // Проверяем, передан ли объект, и получаем ссылку
    Если Не ЗначениеЗаполнено(НоменклатураСсылка) Тогда
        Возврат "";
    КонецЕсли;
    
    СсылкаНаВладельца = ?(Справочники.Номенклатура.ПолучитьСсылку(НоменклатураСсылка.Ссылка) = НоменклатураСсылка, НоменклатураСсылка.Ссылка, НоменклатураСсылка);
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |	РегШтрихкоды.Штрихкод КАК Штрихкод
        |ИЗ
        |	РегистрСведений.Штрихкоды КАК РегШтрихкоды
        |ГДЕ
        |	РегШтрихкоды.Владелец = &Владелец
        |	И (НЕ РегШтрихкоды.Штрихкод ЕСТЬ NULL)
        |	И РегШтрихкоды.Штрихкод <> """"";
        
    Запрос.УстановитьПараметр("Владелец", СсылкаНаВладельца);
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Штрихкод = "";
    Если Выборка.Следующий() Тогда
        Штрихкод = СокрЛП(Выборка.Штрихкод);
    КонецЕсли;
    
    Возврат Штрихкод;
    
КонецФункции

Посмотрим на важные моменты этой реализации:

  1. Мы явно инициализируем переменную Штрихкод пустой строкой, что исключает возврат значения Неопределено при отсутствии записей.
  2. Мы проверяем входные данные на заполненность через ЗначениеЗаполнено().
  3. Конструкция ПЕРВЫЕ 1 ускоряет работу СУБД, прерывая поиск после первого найденного совпадения.

Почему поиск по «Владелец.Наименование» является ошибкой

Иногда разработчики пытаются обойти проблему передачи объекта поиском по строковому наименованию через разыменование поля: Штрихкоды.Владелец.Наименование = &Наименование. Проанализируем, почему такой подход крайне не рекомендуется:

  1. Падение производительности: Обращение через точку к реквизиту владельца в секции ГДЕ приводит к неявному левому соединению (LEFT JOIN) с таблицей справочника номенклатуры и полному сканированию таблицы (Table Scan). Индекс регистра по измерению Владелец при этом перестает использоваться.
  2. Дублирование названий: Наименование номенклатуры в 1С не является уникальным. Если в базе присутствуют товары с одинаковыми названиями, запрос вернет штрихкод первого попавшегося товара, что приведет к пересортице и ошибкам учета.
  3. Чувствительность к пробелам: Лишний пробел или спецсимвол в наименовании приведет к тому, что штрихкод найден не будет.

Решение 2: Получение штрихкода в современных конфигурациях (ERP, КА, УТ 11, Розница)

В современных конфигурациях на базе БСП структура хранения штрихкодов изменилась. Регистр называется ШтрихкодыНоменклатуры, а штрихкод привязывается не только к товару, но и к его характеристикам, упаковкам и сериям. Разберем, как получить штрихкод штучной номенклатуры без упаковок и с учетом характеристик:


Функция ПолучитьШтрихкодНоменклатурыСовременная(НоменклатураСсылка, ХарактеристикаСсылка = Неопределено) Экспорт
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |	Штрихкоды.Штрихкод КАК Штрихкод
        |ИЗ
        |	РегистрСведений.ШтрихкодыНоменклатуры КАК Штрихкоды
        |ГДЕ
        |	Штрихкоды.Номенклатура = &Номенклатура
        |	И (&ФильтрПоХарактеристике = ЛОЖЬ ИЛИ Штрихкоды.Характеристика = &Характеристика)
        |	И Штрихкоды.Упаковка = ЗНАЧЕНИЕ(Справочник.УпаковкиЕдиницыИзмерения.ПустаяСсылка)";
        
    Запрос.УстановитьПараметр("Номенклатура", НоменклатураСсылка);
    
    Если ЗначениеЗаполнено(ХарактеристикаСсылка) Тогда
        Запрос.УстановитьПараметр("ФильтрПоХарактеристике", Истина);
        Запрос.УстановитьПараметр("Характеристика", ХарактеристикаСсылка);
    Иначе
        Запрос.УстановитьПараметр("ФильтрПоХарактеристике", Ложь);
        Запрос.УстановитьПараметр("Характеристика", Справочники.ХарактеристикиНоменклатуры.ПустаяСсылка());
    КонецЕсли;
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    Если Выборка.Следующий() Тогда
        Возврат СокрЛП(Выборка.Штрихкод);
    КонецЕсли;
    
    Возврат "";
    
КонецФункции

Если в конфигурации подключена Библиотека Стандартных Подсистем (БСП), для работы со штрихкодами рекомендуется использовать штатные процедуры и функции общего модуля ШтрихкодированиеНоменклатурыКлиентСервер или ШтрихкодированиеСервер, не создавая прямых запросов к регистрам.

Решение 3: Пакетное получение штрихкодов для массивов номенклатуры

Если задача заключается в выгрузке штрихкодов для большого каталога товаров (например, при выгрузке на сайт или маркетплейс), вызов функции с отдельным запросом в цикле создаст огромную нагрузку на базу данных. Разберем правильный подход с получением данных одним пакетным запросом:


Функция ПолучитьТаблицуШтрихкодовПоМассиву(МассивНоменклатуры) Экспорт
    
    ТаблицаШтрихкодов = Новый Соответствие;
    
    Если МассивНоменклатуры.Количество() = 0 Тогда
        Возврат ТаблицаШтрихкодов;
    КонецЕсли;
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	РегШтрихкоды.Владелец КАК Номенклатура,
        |	МАКСИМУМ(РегШтрихкоды.Штрихкод) КАК Штрихкод
        |ИЗ
        |	РегистрСведений.Штрихкоды КАК РегШтрихкоды
        |ГДЕ
        |	РегШтрихкоды.Владелец В(&МассивНоменклатуры)
        |	И РегШтрихкоды.Штрихкод <> """"
        |СГРУППИРОВАТЬ ПО
        |	РегШтрихкоды.Владелец";
        
    Запрос.УстановитьПараметр("МассивНоменклатуры", МассивНоменклатуры);
    
    Выборка = Запрос.Выполнить().Выбрать();
    Пока Выборка.Следующий() Цикл
        ТаблицаШтрихкодов.Вставить(Выборка.Номенклатура, СокрЛП(Выборка.Штрихкод));
    КонецЦикла;
    
    Возврат ТаблицаШтрихкодов;
    
КонецФункции

Использование Соответствие позволяет мгновенно получать штрихкод товара по его ссылке в оперативной памяти без повторных обращений к СУБД.

← На главную