При автоматизации складских процессов и адресного хранения типового функционала штрихкодирования часто оказывается недостаточно. Классический штрихкод формата EAN-13 позволяет хранить всего 12 значащих цифр (13-й символ является контрольной суммой). Когда в один штрихкод требуется поместить признак операции, код организации, номер накладной, год, этаж сборки или сразу несколько номеров документов для групповой печати, емкость EAN-13 исчерпывается.
В этой статье мы подробно разберем, почему возникает данное ограничение, как правильно перейти на универсальный стандарт Code 128, как генерировать штрихкод через внешние компоненты и шрифты, а также рассмотрим альтернативные архитектурные решения.
---
Проанализируем структуру штрихкодов, чтобы понять, какой стандарт выбрать для решения складских задач:
FNC1. Для внутренних задач склада (внутрифирменная маркировка) данный стандарт избыточен и сложен в поддержке.#, ;, ,). Именно этот стандарт является оптимальным для кодирования составных параметров документов.Рассмотрим несколько вариантов решения задачи расширенного штрихкодирования в 1С.
---
Разберем наиболее прямолинейный и удобный подход: кодирование параметров через символы-разделители. Мы формируем строковый штрихкод вида "ПРЕМ#000123#2024#ЭТ2" или "W00001444C0016".
Преимущества такого подхода:
ОбработкаВнешнегоСобытия без необходимости вручную декодировать контрольные разряды — контрольная сумма проверяется сканером на аппаратном уровне.# или ;).Посмотрим на пример разбора считанного штрихкода в процедуре обработки сканирования:
// Процедура разбора считанного штрихкода формата Code 128
Процедура ОбработатьШтрихкод(Знач СтрШК)
СтрШК = СокрЛП(СтрШК);
// Преобразуем строку с разделителями в список значений
СписокПараметров = СоздатьОбъект("СписокЗначений");
СтрШК = СтрЗаменить(СтрШК, "#", РазделительСтрок);
Для Индекс = 1 По СтрКоличествоСтрок(СтрШК) Цикл
ТекЗнач = СтрПолучитьСтроку(СтрШК, Индекс);
СписокПараметров.ДобавитьЗначение(ТекЗнач);
КонецЦикла;
Если СписокПараметров.РазмерСписка() >= 4 Тогда
ТипДокумента = СписокПараметров.ПолучитьЗначение(1);
НомерДокумента = СписокПараметров.ПолучитьЗначение(2);
ГодДокумента = СписокПараметров.ПолучитьЗначение(3);
ЭтажСборки = СписокПараметров.ПолучитьЗначение(4);
Сообщить("Считан документ: " + ТипДокумента + " № " + НомерДокумента + " за " + ГодДокумента + " г., Этаж: " + ЭтажСборки);
Иначе
Предупреждение("Неверный формат штрихкода документа!");
КонецЕсли;
КонецПроцедуры
---
Если в конфигурации не используется внешняя компонента 1CBarCod.ocx, штрихкод можно вывести при помощи специального TrueType-шрифта (например, Barcode или Code128). Для этого исходную строку необходимо преобразовать по алгоритму расчета контрольной суммы mod 103 и расстановки стартовых/стоповых символов.
Рассмотрим алгоритм подготовки строки для шрифта Code 128 на встроенном языке 1С 7.7:
// Функция определения типа символа
Функция ТипСимв(КодСмв)
Если КодСмв < 32 Тогда
Возврат(1); // Служебная команда
ИначеЕсли (48 <= КодСмв) И (КодСмв <= 57) Тогда
Возврат(3); // Цифра
Иначе
Возврат(2); // Буква, знак
КонецЕсли;
КонецФункции
// Функция вычисления остатка от деления
Функция Мод(Ч, З)
Возврат(Ч - Цел(Ч / З) * З);
КонецФункции
// Основная функция генерации строки штрихкода Code 128 для шрифта
Функция БарКод(Вход, БазаМодеС = 6)
АскиБар =
"155515551449485845458494854548584944056416452065425461560506542164524212245605641254614650" +
"11919191108980988109881889018890898001:0928120290:18212211829021281:0122209281:01218290:10" +
"2305<0;0004=0<540=4<1<05<4105<0=441<4=0<14<50=4050<320=04830047407443074434470344704740113" +
"13131100;0838030380;0308380023032203302";
ВыхТ = СоздатьОбъект("ТаблицаЗначений");
ВыхТ.НоваяКолонка("А",,,,"Аск", 4);
Если Вход = "" Тогда
Возврат("");
КонецЕсли;
ВыхТ.УдалитьСтроки();
Дл = СтрДлина(СокрЛП(Вход));
ТекСимв = КодСимв(Сред(Вход, 1, 1));
ТипТекСимв = ТипСимв(ТекСимв);
Если Дл > 1 Тогда
СлСимв = КодСимв(Сред(Вход, 2, 1));
ТипСлСимв = ТипСимв(СлСимв);
Иначе
ТипСлСимв = 2;
КонецЕсли;
Моде = ТипТекСимв;
Если (ТипТекСимв = 3) И (ТипСлСимв = 3) Тогда
Моде = 3;
КонецЕсли;
ВыхТ.НоваяСтрока();
ВыхТ.А = 102 + Моде;
Вых = Симв(64 + Моде);
Для Сч = 1 По Дл Цикл
ТекСимв = КодСимв(Сред(Вход, Сч, 1));
Если ТекСимв > 127 Тогда
Сообщить("Символ № " + Сч + " со значением = " + ТекСимв + " не разрешен в штрихкоде");
Продолжить;
КонецЕсли;
ТипТекСимв = ТипСимв(ТекСимв);
Если ТипТекСимв <> Моде Тогда
Если ТипТекСимв < 3 Тогда
ВыхТ.НоваяСтрока();
Если Моде = 1 Тогда
ВыхТ.А = 100; // Переключение в режим B
Иначе
ВыхТ.А = 101; // Переключение в режим A
КонецЕсли;
Моде = ТипТекСимв;
Иначе
ДлМ = ?(Дл < Сч + БазаМодеС - 1, Дл, Сч + БазаМодеС - 1);
СчЦ = 0;
Для СчМ = Сч По ДлМ Цикл
МодМ = ТипСимв(КодСимв(Сред(Вход, СчМ, 1)));
Если МодМ = 3 Тогда
СчЦ = СчЦ + 1;
Продолжить;
Иначе
СчЦ = 0;
Прервать;
КонецЕсли;
КонецЦикла;
Если СчЦ - БазаМодеС = 0 Тогда
Моде = 3;
ВыхТ.НоваяСтрока();
ВыхТ.А = 99; // Переключение в режим C
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если Моде = 3 Тогда
СлСимв = КодСимв(Сред(Вход, Сч + 1, 1));
ТипСлСимв = ТипСимв(СлСимв);
Если (Сч = Дл) Или (ТипТекСимв <> 3) Или (ТипСлСимв <> 3) Тогда
Моде = 2;
ВыхТ.НоваяСтрока();
ВыхТ.А = 100;
Иначе
ВыхТ.НоваяСтрока();
ВыхТ.А = Число(Симв(ТекСимв) + Симв(СлСимв));
Сч = Сч + 1;
Продолжить;
КонецЕсли;
КонецЕсли;
ВыхТ.НоваяСтрока();
Если Моде = 1 Тогда
ВыхТ.А = ТекСимв + 64;
Иначе
ВыхТ.А = ТекСимв - 32;
КонецЕсли;
КонецЦикла;
ВыхТ.ВыбратьСтроки();
Сум = 0;
Ном = 0;
Пока ВыхТ.ПолучитьСтроку() = 1 Цикл
Если Ном > 0 Тогда
Сум = Мод(Сум + ВыхТ.А * Ном, 103);
Вых = Вых + Сред(АскиБар, (ВыхТ.А + 1) * 3 - 2, 3);
Иначе
Сум = Мод(ВыхТ.А, 103);
КонецЕсли;
Ном = Ном + 1;
КонецЦикла;
Возврат(Вых + Сред(АскиБар, (Сум + 1) * 3 - 2, 3) + "@");
КонецФункции
Сформированная строка передается в ячейку печатной формы, для которой установлен шрифт Barcode.
---
Если на предприятии принципиально используются сканеры, настроенные исключительно на EAN-13, либо требуется сохранить компактность штрихкода на термоэтикетках, параметры можно упаковать в 12 десятичных цифр с помощью шестнадцатеричной/позиционной конвертации.
Проанализируем схему распределения байт:
Итого 5 байт (10 шестнадцатеричных символов), что в десятичном представлении дает число до 1 099 511 627 775, которое гарантированно помещается в 12 знаков EAN-13.
Посмотрим на пример функций кодирования и декодирования (1С:Предприятие 8 / управляемые формы):
&НаКлиенте
Функция Код(Значение, знач Байт)
Р = DecToAny(Значение, 16); // Перевод в шестнадцатеричную систему
Д = СтрДлина(Р);
Байт = Байт * 2;
Если Д < Байт Тогда
Для Счетчик = 1 По Байт - Д Цикл
Р = "0" + Р;
КонецЦикла;
КонецЕсли;
Возврат Р;
КонецФункции
&НаКлиенте
Функция КодироватьВEAN13(ЭтоПеремещение, Фирма, Номер, Год, Этаж)
Признак = ?(ЭтоПеремещение = 1, 128, 0);
Р = Код(Признак + Фирма, 1);
Р = Р + Код(Номер, 2);
Р = Р + Код(Год, 1);
Р = Р + Код(Этаж, 1);
// Переводим 16-ричную строку обратно в десятичное 12-значное число
Результат12Знаков = AnyToDec(Р, 16);
// Дописываем контрольный символ EAN-13
Возврат ДописатьКонтрольныйСимволEAN13(Результат12Знаков);
КонецФункции
&НаКлиенте
Функция ДекодироватьИзEAN13(знач ШтрихкодEAN13, ЭтоПеремещение, Фирма, Номер, Год, Этаж)
// Убираем контрольный 13-й символ
Зн = Сред(ШтрихкодEAN13, 1, 12);
ШестнСтрока = DecToAny(Число(Зн), 16);
ШестнСтрока = Код(ШестнСтрока, 5);
Байт1 = AnyToDec(Сред(ШестнСтрока, 1, 2), 16);
ЭтоПеремещение = ?(Байт1 > 127, 1, 0);
Фирма = ?(ЭтоПеремещение = 0, Байт1, Байт1 - 128);
Номер = AnyToDec(Сред(ШестнСтрока, 3, 4), 16);
Год = AnyToDec(Сред(ШестнСтрока, 7, 2), 16);
Этаж = AnyToDec(Сред(ШестнСтрока, 9, 2), 16);
Возврат Истина;
КонецФункции
---
При групповой печати перемещений попытка «впихнуть» в один линейный штрихкод список из 5–10 документов приводит к резкому росту длины штрихкода (до 15–20 см). Считывать такой широкий код ручным сканером крайне неудобно.
Наиболее масштабируемое решение — отказаться от кодирования всех реквизитов внутри самого штрихкода и применить агрегацию:
EAN-13 или Code 128).---
1CBarCod.ocx), достаточно просто передать строку с разделителями (# или ;), расчет контрольных сумм компонента выполнит самостоятельно.