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

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

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

Если мы заглянем в структуру метаданных большинства типовых конфигураций прошлых поколений, то увидим, что регистр сведений ШтрихкодыНоменклатуры является непериодическим. Это означает, что записи в нем не привязаны ко времени. База данных хранит их как неупорядоченный набор, и просто так «спросить» у СУБД, какая запись была внесена последней, стандартным запросом невозможно. Выясним, какие существуют пути решения этой задачи на платформе 1С:Предприятие 8, начиная от штатных возможностей современных систем и заканчивая грамотной доработкой архитектуры.

Решение 1: Использование штатного механизма «Штрихкод для отчетов» (для современных конфигураций)

Если вы работаете в современных конфигурациях на управляемых формах (например, 1С:Управление нашей фирмой 3.0, 1С:Розница 3.0, 1С:Управление торговлей 11.5, 1С:Комплексная автоматизация 2.5 или 1С:ERP), то разработчики фирмы 1С уже добавили изящный обходной путь для этой проблемы.

Проанализируем этот механизм. В карточке номенклатуры на вкладке со штрихкодами присутствует признак (флаг) «Использовать для отчетов и печатных форм». При добавлении нового штрихкода вручную или через пакетную обработку загрузки система автоматически устанавливает этот флаг для самой свежей записи, снимая его с предыдущих. В структуре регистра сведений за это отвечает реквизит с типом Булево (например, ИспользоватьДляОтчетов).

В этом случае задача в запросе решается максимально просто и быстро с помощью левого соединения:


ВЫБРАТЬ
    Номенклатура.Ссылка КАК Товар,
    Штрихкоды.Штрихкод КАК ПоследнийШтрихкод
ИЗ
    Справочник.Номенклатура КАК Номенклатура
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ШтрихкодыНоменклатуры КАК Штрихкоды
        ПО Номенклатура.Ссылка = Штрихкоды.Номенклатура
        И Штрихкоды.ИспользоватьДляОтчетов = ИСТИНА

Этот способ является наиболее приоритетным, так как он не требует изменения структуры конфигурации и работает на штатных индексах СУБД.

Решение 2: Метод агрегатных функций (для внутренних штрихкодов)

Рассмотрим ситуацию, когда штрихкоды генерируются непосредственно внутри вашей базы 1С (это касается штучных или весовых кодов, обычно начинающихся на «20...» или «29...»). Внутренние штрихкоды стандарта EAN-13 присваиваются системой строго последовательно, по возрастанию их числового значения.

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


ВЫБРАТЬ
    Штрихкоды.Номенклатура КАК Номенклатура,
    МАКСИМУМ(Штрихкоды.Штрихкод) КАК ПоследнийШтрихкод
ИЗ
    РегистрСведений.ШтрихкодыНоменклатуры КАК Штрихкоды
ГДЕ
    Штрихкоды.Штрихкод ПОДОБНО "20%" // Ограничиваем выборку только внутренними кодами
СГРУППИРОВАТЬ ПО
    Штрихкоды.Номенклатура

Важное ограничение метода: данный способ абсолютно неприменим, если вы сканируете внешние штрихкоды производителей. У разных производителей структура кодов никак не связана с хронологией их заведения в вашу базу, и штрихкод, начинающийся на «40...», заведенный сегодня, будет меньше штрихкода на «46...», который был заведен три года назад.

Решение 3: Анализ торговых документов (Разбор мифа)

Иногда на форумах предлагают «оригинальное» решение: брать последний штрихкод из недавно проведенных документов поступления товаров, реализаций или документов установки цен. Давайте разберем по шагам, почему этот подход технически неверен и опасен для производительности системы:

  1. Отсутствие данных в СУБД. В 99% типовых конфигураций 1С при сканировании штрихкода в документе (например, в «Реализации товаров и услуг») происходит лишь поиск сопоставленной номенклатуры и характеристики. В саму табличную часть документа записывается ссылка на номенклатуру, а не строковое значение штрихкода. Штрихкод выступает лишь инструментом поиска в интерфейсе и физически в таблицах документов не хранится.
  2. Огромная нагрузка на сервер. Даже если в вашей конфигурации штрихкод записывается в табличную часть (например, при партионном учете или в специализированных отраслевых решениях), запрос к миллионам строк документов для динамического вычисления «последнего документа по дате» ради получения штрихкода положит производительность любого отчета.

Решение 4: Восстановление хронологии через Журнал регистрации

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

Журнал регистрации фиксирует все транзакции создания и изменения записей в базе данных с точностью до секунды. Мы можем программно прочитать эти события. Рассмотрим пример кода:


Отбор = Новый Структура;
Отбор.Вставить("Событие", "_$Data$_.New"); // Фильтр на создание новых записей
Отбор.Вставить("Метаданные", Метаданные.РегистрыСведений.ШтрихкодыНоменклатуры);

ТаблицаСобытий = Новый ТаблицаЗначений;
ВыгрузитьЖурналРегистрации(ТаблицаСобытий, Отбор, "Дата, Данные, ПредставлениеДанных");

// Полученную таблицу значений далее можно связать с номенклатурой по GUID данных

Почему это нельзя использовать в отчетах? Метод чтения журнала регистрации крайне ресурсоемок. Он выполняется во внешних файлах на диске, не кэшируется СУБД и не может быть интегрирован внутрь обычного запроса схемы компоновки данных (СКД).

Решение 5: Правильная доработка регистра сведений (Создание поля даты)

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

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

Вместо этого мы добавим в регистр сведений ШтрихкодыНоменклатуры обычный реквизит ДатаСоздания с типом Дата (состав даты: Дата и время).

Разберем по шагам, как автоматизировать заполнение этого поля:

  1. Откройте конфигуратор и найдите регистр сведений ШтрихкодыНоменклатуры.
  2. В ветке «Реквизиты» добавьте новое поле ДатаСоздания (тип: Дата).
  3. Перейдите в модуль набора записей регистра и добавьте обработчик события ПередЗаписью, чтобы дата фиксировалась автоматически при создании записи:

Процедура ПередЗаписью(Отказ, Замещение)
    Для Каждого Запись Из ЭтотОбъект Цикл
        Если НЕ ЗначениеЗаполнено(Запись.ДатаСоздания) Тогда
            Запись.ДатаСоздания = ТекущаяДатаСеанса();
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

После сохранения изменений у всех новых штрихкодов будет автоматически фиксироваться точное время их создания. Для старых записей можно написать простую обработку, которая заполнит это поле датой по умолчанию.

Теперь задача получения последней записи легко и красиво решается в любом отчете СКД с помощью классического среза последних через вложенный запрос:


ВЫБРАТЬ
    МаксимальныеДаты.Номенклатура КАК Номенклатура,
    Штрихкоды.Штрихкод КАК ПоследнийШтрихкод
ИЗ
    (ВЫБРАТЬ
        ШтрихкодыМакс.Номенклатура КАК Номенклатура,
        МАКСИМУМ(ШтрихкодыМакс.ДатаСоздания) КАК МаксДата
    ИЗ
        РегистрСведений.ШтрихкодыНоменклатуры КАК ШтрихкодыМакс
    СГРУППИРОВАТЬ ПО
        ШтрихкодыМакс.Номенклатура) КАК МаксимальныеДаты
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ШтрихкодыНоменклатуры КАК Штрихкоды
        ПО МаксимальныеДаты.Номенклатура = Штрихкоды.Номенклатура
        И МаксимальныеДаты.МаксДата = Штрихкоды.ДатаСоздания

Используя этот подход, вы получите абсолютно точные данные в отчетах без малейшей потери производительности системы.

← На главную