Кое-что простое о сложных штрих-кодах

На просторах и-нета часто встречаю публикации, в которых авторы с энтузиазмом рассказывают о том, как в штрих-код внести информацию о нескольких сущностях: например, как сделать, чтобы при сканировании одного штрих-кода на ярлыке товара, 1С определяла что это за товар, его качество и приходную накладную по которой этот товар поступил. Увы, но делается это «в лоб». Я предлагаю более разумный способ. Он очевиден — так что не претендую на лавры первооткрывателя.

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

  • Товар ("Кровать "Антара"")
  • Качество товара ("Брак, некомплект производителя")
  • Приходная накладная ("РЛ-000824 от 12.09.2024")

Как правило, предлагается такой путь: для каждой сущности задаем кодировку: для полей "товар" и "качество" — это будет код 1С, для "Приходной накладной" — номер:

  • Товар ("Кровать "Антара"") — "0000345"
  • Качество товара ("Брак, некомплект производителя") — "005"
  • Приходная накладная ("РЛ-000824 от 12.09.2024") — "РЛ-000824"

Теперь собираем штрих-код: "0000345_005_РЛ-000824" кодируем его в code128 и все готово — при сканировании 1С должна распарсить полученную строку и извлечь из нее все требуемые данные. Все очень просто и очень НЕПРАВИЛЬНО. Вот причины:

  1. Если кто-то изменит кодировку элементов справочников 1С, то штрих-кода в лучшем случае не будут читаться вовсе, а в худшем — будет определяться неверный объект базы 1С
  2. Что делать, если каждый год нумерация документов начинается с "0000001"? Тогда номера накладной недостаточно — надо указывать еще одно поле — период данной накладной. Но даже это не спасет в случае, если накладную сделают 29.12.2024, распечатают штрих-кода, а потом перенесут накладную в 2024 год
  3. Что делать, если в штрих-код надо вставить 8 разных сущностей (реальный пример из моей практики СЭД)? Длины даже code128 будет недостаточно. Можно, конечно, использовать QR-код, но это означает, что надо покупать более дорогое оборудование (принтера и сканеры) 
  4. code128 намного больше, чем EAN13 — нужна этикетка большого размера, что увеличивает вероятность ее повреждения при хранении и транспортировке товара.
  5. Что делать, если в штрих-код надо вставить не объект из базы 1С, а строку, например адрес получателя посылки без КЛАДРа, например в Великобритании: "Salisbury, Castlt st, 18, mr. Skripal"? Но при этом очень хочется, чтобы Британская разведка MI6 при сканировании этого кода в блокнот или ворлд не получила этот адрес в таком открытом виде.

Вот правильное решение:

1. Создаем справочник "УниверсальныеШтрихкода" (почему именно справочник, а не регистр сведений — это тема отдельной статьи):

Здесь "Парам1", "Парам2",…"Парам9" — это то, что "зашито" в наш штрих-код. Тип этих полей — составной, т.е. там и "Строка" и "Число" и "Булево" и "Дата" и "СсылкаНаПроизвольныйСправочник" и "СсылкаНапроизвольныйДокумент" и "СсылкаНаПеречисление" и все-все-все, что можно отметить галками в свойствах поля.

"Тип" — это строка, по которой 1С будет понимать, какие сущности находятся в параметрах. Например, если Тип = "Товар", то в "Параметре1" содержится ссылка на справочник "Номенклатура", а в "Параметре2" — ссылка на справочник "Качество", а в "Параметре3" — ссылка на документ "ПоступлениеТоваровУслуг". В тестовой конфигурации, приаттаченной к этой статье, "Тип" = "ОС", а это означает, что в "Параметре1" находится ссылка на справочник "ОсновныеСредства", а в "Параметре2" — ссылка на справочник "ИнвентарныеНомера" (одному моему заказчику понадобилась система учета основных средств без сквозной нумерации инвентарных номеров. Пример: на предприятии есть 30 одинаковых ОС "Шкаф электрический 2eu45" и надо, что бы их нумерация была от "000001" до "000030". И так по всем однотипным ОС) 

"Представление" — строковое описание данного штрих-кода. Я обычно вывожу его под самим штрих-кодом, для нашего примера это может быть: "Кровать "Антара", брак н/п, РЛ-000824". Это поле ни на что не влияет. Нужно для сотрудников, которые по данному описанию могут быстро ориентироваться в товарах.

"Код" нашего справочника — это Число длиной 13, т.е. это и есть наш штрих-код в кодировке EAN13. При создании элементов справочника надо позаботиться о том, чтобы он заполнялся корректно.

Для этого в модуле формы этого справочника определим процедуру: 

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

    ТекКод = Число(МаксКод) + 1;
    
    ТекКод
= СокрЛП(ТекКод);
    ТекКод = СтрЗаменить(ТекКод," ","");    

    КодСтр = "" + ТекКод + ШтрихКода.КонтрольныйСимволEAN(ТекКод,13);
        
    Код
= КодСтр;    

КонецПроцедуры
Эта процедура обеспечит корректную генерацию штрих-кодов в формате EAN13 начиная с номера "5000000000012"

А теперь, собственно, функция, которая генерирует (или находит существующую) запись для набора данных "товар" — "качество" — "прих.накл.":

&НаСервере                                     
Функция ПолучитьУнШК_Товар(Товар,Качество,ПрихНакл) Экспорт
    
    Тип = "Товар";
    
    Запрос = Новый Запрос;
    Запрос.Текст
        "ВЫБРАТЬ
        |    УниверсальныйШтрихКод.Ссылка,
        |    УниверсальныйШтрихКод.Код
        |ИЗ
        |    Справочник.УниверсальныйШтрихКод КАК УниверсальныйШтрихКод
        |ГДЕ
        |    УниверсальныйШтрихКод.Тип = &Тип
        |    И УниверсальныйШтрихКод.Парам1 = &Парам1
        |    И УниверсальныйШтрихКод.Парам2 = &Парам2
        |    И УниверсальныйШтрихКод.Парам3 = &Парам3";
    
    Запрос.УстановитьПараметр("Парам1", Товар);
    Запрос.УстановитьПараметр("Парам2", Качество);
    Запрос.УстановитьПараметр("Парам3", ПрихНакл);

    Запрос.УстановитьПараметр("Тип", Тип);
    
    РезультатЗапроса
= Запрос.Выполнить();
    
    ВыборкаДетальныеЗаписи
= РезультатЗапроса.Выбрать();
    
    
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        ТекКод = ВыборкаДетальныеЗаписи.Код;
        ТекКод = СтрЗаменить(ТекКод," ","");
        Возврат ТекКод;
    КонецЦикла;        
    
    Спр
= Справочники.УниверсальныйШтрихКод.СоздатьЭлемент();
    Спр.Тип = Тип;
    Спр.Парам1 = Товар;
    Спр.Парам2 = Качество;
    Спр.Парам3 = ПрихНакл;
    Спр.Представление = СокрЛП(Товар.Наименование) + ", " + СокрЛП(Качество.Кратко) + ", " + ПрихНакл.Номер;
    Спр.Записать();
    
    ТекКод
= СтрЗаменить(Спр.Код," ","");

    Возврат ТекКод;

КонецФункции
 

Эта функция находится в общем модуле и мы вызываем ее тогда, когда надо получить штрих-код (пока не картинку, а числовое представление) для требуемого набора данных.

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

Печать штрих-кода — здесь все стандартно, но в конфигурации к данной статье есть и этот блок.

Теперь что надо делать при сканировании штрих-кода. Здесь все еще проще:

После сканирования вызываем серверную процедуру, которая разбирает, что "скрывается" под данным штрих-кодом:

СпрУнШК = Справочники.УниверсальныйШтрихКод.НайтиПоКоду(ШК);
    Если СпрУнШК <> Справочники.УниверсальныйШтрихКод.ПустаяСсылка() Тогда
        Если СокрЛП(СпрУнШК.Тип) = "Товар" Тогда
            Товар = СпрУнШК.Парам1;
            Качество = СпрУнШК.Парам2;
            ПрихНакл = СпрУнШК.Парам3;
        КонецЕсли;
    КонецЕсли;

 

В конце статьи приведу реальные примеры из практики, где использовал данный подход:

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

  • "Товар" — Справочник.Номенклатура
  • "Размер" — Справочник.Размеры
  • "Часть" — Число(2,0). Если товар состоит из нескольких частей (юбка+майка+пиджак) 
  • "ЗаказНаПроизводство" — Документ.ЗаказНаПроизводство
  • "ПорядковыйНомерВЗаказе" — Число(3,0)

Этот уникальный штрих-код создается на старте, распечатывается на бирке, вшивается в готовое изделие и сканируется на всех этапах производства и продажи. В результате можно восстановить полную историю изделия — кто и когда шил, куда отправили, когда вернулось, с каким браком и т.д.

Металлобаза. Для крупноформатных линейных товаров (балка, швеллер, уголок больших размеров) при порезке для каждой "нитки" остатка создаем уникальный штрих-код с такой информацией:

  • "ID" — Строка(30) уникальный ИД для данной "нитки"
  • "Товар" — Справочник.Номенклатура
  • "ТекущийЛинейныйРазмер" — Число(10,3) — длина "нитки"
  • "ДокументФормирования" — Документы: ПриходнаяНакладная, Производство, Оприходование

Это позволяет видеть остатки товаров нестандартной длины, ограничивать их "безконтрольное размножение" (например, для товара "Балка 45 ст3" устанавливается ограничение: на складе не более двух "ниток" с размером < 3м и не более трех "ниток" с размером от 3м до 6м. При формировании менеджером заказа, 1С контролирует остаток всех обрезков на складе, которые будут после порезки, и если в результате данной операции ограничения будут нарушены, то менеджер не сможет оформить такой заказ). А когда менеджеру надо продать товар нестандартной длины, то он указывает складу какой именно экземпляр ему нужен.

СЭД: для печатной формы документа формируем штрих-код для шапки документа, где указано:

  • "Документ" — ссылка на произвольный документ 1С
  • "ВерсияДокумента" — Строка(100) — связь с системой версионирования для понимания того, что именно было в документе, когда пользователь нажал кнопку "печать" или "отправить на e-mail"
  • "ЭтапСогласованияНаМоментПечати" — Справочник.ЭтапыСогласований
  • "ИмяПечатнойФормы" — Строка(20)
  • "НомерСтраницы" — Число(5,0) — для многостраничных документов получаем уникальный штрих-код на каждую страницу
  • "Пользователь" — Справочник.Сотрудники — пользователь, который нажал кнопку "печать" или "отправить e-mail"
  • "ДатаВремяПечати" — ДатаВремя
  • "ПорядковыйНомерВПакете" — Число(3,0) — если был запущен механизм групповой печати/рассылки

"Партизанская" торговля. По выставкам ездят автобусы с товаром и что-то там продают. Для каждого выездного магазинчика свои цены и валюты, которые зависят еще и от того, куда он в данный момент поехал (UAH, RUB, BYN, MDL, EUR). Короче, с ценообразованием все очень сложно. По факту магазинчик распродает почти все, что взял с собой с центрального склада, а то, что привозит назад проходит предпродажную подготовку (чистку/упаковку) и заново перестикеровывается. Вставляем цены и валюту в штрих-код на ярлыке товара. Да, да, да… я знаю, что это "апокрифичекое" решение, апологеты "1С-совместимо" предадут меня анафеме, а "свидетели УТП" проклянут меня и мой род до 7 колена, после смерти я буду гореть в 1С-аду, но я сознательно принимаю это, т.к. считаю, что нет "правильных" и "неправильных" решений, а есть те, что "подходят" для данного бизнеса и "не подходят". Итак штрих-код для этого бизнеса содержит такие данные:

  • "Товар" — Справочник.Номенклатура
  • "Размер" — Справочник.Размеры
  • "ЦенаРозница" — Число (10,2)
  • "ЦенаОпт" — Число (10,2)
  • "ЦенаРаспродажа" — Число (10,2)
  • "Валюта" — Справочник.Валюты

Заодно вместе со штрих-кодом печатаем на ярлыке красиво цены "розница" и "опт" в валюте той страны, куда едет наш "партизан".

"Кондитерское производство" — специфика бизнеса в том, что товар скоропортящийся (срок реализации до 3дней), его производят только под заказ клиента. В штрих-код для каждого торта вносим такую информацию:

  • "Товар" — Справочник.Номенклатура
  • "Клиент" — Справочник.Контрагенты
  • "ДатаЗаказа" — ДатаВремя
  • "ДатаПроизводстваПлан" — ДатаВремя
  • "ДатаОтгрузкиПлан" — ДатаВремя

"Бакалея" — у такой группы товаров как "Твердые сыры" есть одна особенность — каждая "голова" сыра имеет свой уникальный вес. При оптовой торговле никто не продает 30кг сыра — продают 1,2,3 и т.д. "головы". Если менеджер принял заказ от клиента на 30кг сыра, то по факту клиенту может уехать 2 головы с весом 17.560кг и 16.380кг. Для этого вида товаров штрих-код ярлыка для каждой "головы" содержит информацию:

  • "Товар" — Справочник.Номенклатура
  • "Партия" — Документ.ПриходнаяНакладная
  • "ГраничнаяДатаРеализации" — Дата (это поле не дублирует партию, т.к. в одной прих. накл. один и тот же товар может быть с разными сроками годности)
  • "Вес" — Число(10,3) 

Бюро ритуальных услуг. Э-э-э… пожалуй про штрих-кода для этого бизнеса пока рассказывать не буду. 

15 Comments

  1. drmaxart

    То есть суть в том, что мы не зашиваем информацию о самих объектах в ШК, а храним соответствие ШК набору значений. Недостаток только в том, что использовать информацию из данного ШК можно только в той же ИБ

    Reply
  2. torch

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

    Reply
  3. SerVer1C

    … ворлд … — вы, наверное, имели ввиду ХЭЛЛОУ ВОРЛД ?

    Reply
  4. kembrik

    Прошу прощения, если это не велосипед, то близко. Как и использование префикса 50 для «Своих» кодов. Согласен, Code128 имеет недостатки, но есть же шикарные gs1 databar expanded с зоопарком вариантов, где все ваши новодельные сущности типа Парам1 и далее по списку превращаются в элегантные (01)04605025000880(3103)000830(17)161223 (с большим запасом по чтению в случае повреждения)

    Идентификаторов применения (числа в скобках) вагон, как типовых так и «своих собственных»

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

    Внешняя компонента по ссылке https://infostart.ru/public/824109/ — вполне рабочая

    Reply
  5. 🅵🅾️🆇

    Эм, решение, какбэ, самое очевидное.

    Только вместо справочника, вероятно, стоит использовать регистр сведений и возможно план видов характеристик, чтоб совсем уж универсальная штука получилась.

    Тк вам по уникальному значению (которое надо соблюдать уникальным) надо искать некие ресурсы.

    Алсо, вам никто не запрещает совмещать и делать понятный штрихкод, например: РЛ-000824

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

    Reply
  6. torch

    to (5). Решение самое очевидное — это именно то, что сказано в анонсе. В первых версиях использовал регистр сведений, но позже перешел именно на справочник — в самых экзотических случаях нужна была табличная часть для данного элемента, а в сложных системах надо было открывать этот инструмент «администраторам» системы для ручного внесения изменений в элементы. Из этого сразу же последовала необходимость контроля и логирования «кто и чего и когда напедалил». Так что с течением времени от регистра сведений перешел к справочнику.

    Reply
  7. 🅵🅾️🆇

    (6) Ну так все тоже самое вы можете делать и с регистром сведений.

    + его удобные плюшки, да еще и работает быстрее.

    Касательно справочника: это ни что иное как расширение класса регистра сведений, с добавленными ненужными переменными «код» и «наименование».

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

    Человек точно также может открывать и вносить изменения в регистр сведений, причем вполне можно ограничиться одним формошлепством с 0 кода.

    Справочники, всеже, для другого нужны.

    Reply
  8. Ziggurat

    Делал так еще в 7.7, очевидное решение. В чём инновационность?

    Reply
  9. drmaxart

    (7)Ну вот табличную часть действительно в РС не зашьешь, делать только отдельный типа подчиненный по каким-то ключам другой РС, играющий роль ТЧ, но смысл

    Reply
  10. drmaxart

    (8)Не все о нём могли знать, человек поделился

    Reply
  11. 🅵🅾️🆇

    (10) Ну или делать несколько записей в разрезе одного штрихкода.

    Посмотрите как это происходит с подчиненным регистром сведений при проведении документа с табличной частью.

    Да и скорее всего вам не нужна табличная часть, а нужен план видов характеристик.

    Тк штрихкодами, как правило, маркируют товар, а товар описывают с помощью пвх.

    Если у Вас не большая база и вопрос оптимизации не стоит, то, конечно, можно и справочник.

    Просто предназначение справочника не в этом, справочник это скорее перечисление в которое возможно добавлять элементы.

    Reply
  12. pro-rok

    День добрый, а я решал подобные задачи тоже через справочник. Наступал на те же грабли, первый раз реализовал через регистр сведений, потом пришлось писать приличный объем кода только потому что это был РС + логика была немного «шаткая». На мой субъективный взгляд очень даже удобно работать со справочником. Были случаи когда нужно три табличные части хранить или порядка 20 реквизитов. Только называл я его серийный номер. Зато по ссылке на элемент получаешь легко и без гемороя доступ к нужным реквизитам, пользователь открывая карточку серийного номера видит всю необходимую информацию (из чего собрали, кто собирал, кому отгрузили и т.д.)

    Reply
  13. zsrg

    (2) Если уж все сделано на основе справочника, то зачем ограничивать функциональность вводя «Параметр1», «Парамтр2» и т.д.? Почему не использовать штатные средства той же торговли: «Свойства объектов» и «Категории объектов», добавив в план видов характеристик «Назначение свойств и категорий объектов» ваш справочник «Универсальный штрих-код»??? Тогда можно легко настраивать перечень свойств/категорий сохраняемых для штрих-кода без необходимости лезть в конфигуратор. А главное: набор не абстрактных «Параметр1», «Параметр2» и т.д., а набор конкретных свойств с наименование и типом значения…

    Reply
  14. torch

    (13)Коллега, абсолютно с Вами согласен. Я пробовал использовать ПВХ, но когда надо было вставить в штрих-код таб. часть, то не смог это культурно реализовать. Но в целом идея, конечно, годная.

    Reply
  15. zsrg

    (14) Если поиск по табличной части не нужен, а надо только хранить данные — то я использую «ХранилищеЗначения» и помещаю в него таблицу значений. Таким образом без проблем получается хранить табличные части в регистрах сведений. Если же надо делать поиск / выполнять запрос по данным в табличной части — тогда да, приходится использовать справочник

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *