Внедрение штрихкодирования печатных форм — стандартная задача при автоматизации документооборота и складского учета. Идея проста: при выводе документа на печать формируется штрихкод, содержащий уникальный идентификатор. При возврате бумажного документа в офис сотрудник сканирует его, и система мгновенно открывает нужную форму в 1С. Однако на практике разработчики часто сталкиваются с аппаратными и программными сложностями: штрихкод получается слишком длинным и не считывается, при сканировании «сбивается» раскладка клавиатуры, или на печать выводятся некорректные символы.
В этой статье мы подробно разберем, как обойти ограничения стандарта Code128, оптимизировать длину кодируемой строки, победить зависимость от раскладки клавиатуры и написать производительный код для быстрого поиска документов в базе данных.
Начнем с базовых правил работы со стандартом Code128. Часто у начинающих разработчиков возникает вопрос, почему при передаче русской строки штрихкод не формируется или выводится некорректно. Разберем технические особенности этого типа кодирования.
Штрихкод Code128 не поддерживает кириллицу. Попытка закодировать в него русские буквы приведет к ошибке генерации компоненты печати. Стандарт работает исключительно с символами ASCII в диапазоне от 0 до 127. Если вам необходимо передать текстовую информацию, используйте только латинские буквы, цифры и спецсимволы.
Также существует распространенное заблуждение, что Code128 не поддерживает пробелы. Это неверно. Стандарт Code128 разделяется на три подмножества (набора символов): A, B и C:
Современные компоненты печати штрихкодов в 1С (например, внешняя компонента «1С:Печать штрихкодов») автоматически переключаются между этими наборами для оптимального сжатия строки. Чтобы корректно вывести штрихкод на макет, рассмотрим пример заполнения свойств объекта:
// Получаем рисунок из макета, где D2 — имя объекта штрихкода
ОбъектШтрихкода = Макет.Рисунки.D2.Объект;
ОбъектШтрихкода.ТипКода = 4; // Обычно соответствует типу Code128 в компоненте 1С
ОбъектШтрихкода.Сообщение = "DOC-2023-00015"; // Данные для кодирования
ОбъектШтрихкода.ТекстКода = "DOC-2023-00015"; // Текст, отображаемый под кодом
Попытка закодировать результат системной функции ЗначениеВСтрокуВнутр() напрямую в Code128 обречена на провал. Данная строка содержит фигурные скобки, русские названия метаданных и GUID. Полученный штрихкод будет иметь огромную длину. Физическая плотность штрихов окажется настолько высокой, что обычные лазерные или светодиодные сканеры просто не смогут его считать.
Использование «чистого» GUID (36 символов, например, 550e8400-e29b-41d4-a716-446655440000) также формирует достаточно плотный штрихкод. Проанализируем, как можно сократить длину строки GUID почти в два раза.
Логически GUID — это 128-битное число, состоящее из 16 байт. Текстовое представление с дефисами — лишь один из способов его записи. Мы можем преобразовать эти 16 байт в компактную строку формата Base64. Длина сократится с 36 до 22 символов.
Разберем по шагам алгоритм сжатия и восстановления идентификатора в 1С:
// Функция сжимает GUID в короткую строку Base64
Функция СжатьGUID(Знач СсылкаНаОбъект) Экспорт
УникальныйИд = СсылкаНаОбъект.УникальныйИдентификатор();
// Убираем дефисы из строкового представления GUID (получаем 32 символа HEX)
СтрокаHEX = СтрЗаменить(Строка(УникальныйИд), "-", "");
// Преобразуем HEX-строку в двоичные данные
ДвоичныеДанныеGUID = ПолучитьДвоичныеДанныеИзГексагональнойСтроки(СтрокаHEX);
// Кодируем двоичные данные в Base64 (получаем строку длиной 24 символа с "==" на конце)
СтрокаBase64 = ПолучитьBase64СтрокуИзДвоичныхДанных(ДвоичныеДанныеGUID);
// Убираем символы заполнения "=" и заменяем неподдерживаемые символы для безопасности
СтрокаBase64 = СтрЗаменить(СтрокаBase64, "+", "-");
СтрокаBase64 = СтрЗаменить(СтрокаBase64, "/", "_");
СтрокаBase64 = СтрЗаменить(СтрокаBase64, "=", "");
Возврат СтрокаBase64; // Получаем строку длиной всего 22 символа!
КонецФункции
Для обратного преобразования при считывании штрихкода сканером используем следующую функцию:
// Функция восстанавливает исходный GUID из сжатой строки Base64
Функция ВосстановитьGUID(Знач СжатаяСтрока) Экспорт
// Возвращаем на место символы Base64
СтрокаBase64 = СтрЗаменить(СжатаяСтрока, "-", "+");
СтрокаBase64 = СтрЗаменить(СжатаяСтрока, "_", "/");
// Восстанавливаем символы выравнивания "=" до кратности 4
Остаток = СтрДлина(СтрокаBase64) % 4;
Если Остаток > 0 Тогда
СтрокаBase64 = СтрокаBase64 + Лев("==", 4 - Остаток);
КонецЕсли;
// Декодируем из Base64 в двоичные данные, затем в HEX
ДвоичныеДанные = ПолучитьДвоичныеДанныеИзBase64Строки(СтрокаBase64);
СтрокаHEX = ПолучитьГексагональнуюСтрокуИзДвоичныхДанных(ДвоичныеДанные);
// Восстанавливаем дефисы для стандартного формата GUID (8-4-4-4-12)
ФорматныйGUID = Сред(СтрокаHEX, 1, 8) + "-" +
Сред(СтрокаHEX, 9, 4) + "-" +
Сред(СтрокаHEX, 13, 4) + "-" +
Сред(СтрокаHEX, 17, 4) + "-" +
Сред(СтрокаHEX, 21);
Возврат Новый УникальныйИдентификатор(ФорматныйGUID);
КонецФункции
Этот метод позволяет существенно укоротить штрихкод Code128, сделав его легко читаемым для любого 1D-сканера без потери уникальности идентификации.
Если сканер штрихкодов подключен к компьютеру в режиме эмуляции клавиатуры (HID-mode), то при сканировании символы передаются операционной системе так, будто их быстро вводит пользователь на клавиатуре. Из-за этого возникает критическая проблема: если на компьютере в момент сканирования активна русская раскладка клавиатуры (РУС), то латинские буквы превратятся в русские (например, латинская «e» превратится в русскую «у», «w» — в «ц» и так далее).
Выясним, какие существуют пути решения этой проблемы.
Если у вас нет физического доступа к оборудованию клиентов или нет возможности перенастроить сканеры, можно написать функцию перекодирования символов. Она сопоставляет символы русской раскладки с латинскими клавишами.
Посмотрим на пример реализации такой процедуры в модуле формы или общем модуле:
Процедура ПерекодировкаРУС2Англ(Текст) Экспорт
СимволыАнгл = "~@#$^&QWERTYUIOP{}ASDFGHJKL:""ZXCVBNM<>?`qwertyuiop[]asdfghjkl;'zxcvbnm,./";
СимволыРУС = "Ё""№;:?ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,ёйцукенгшщзхъфывапролджэячсмитьбю.";
ТекстАнгл = "";
Для Сч = 1 ПО СтрДлина(Текст) Цикл
СимволИсточника = Сред(Текст, Сч, 1);
ПозицияСимвола = Найти(СимволыРУС, СимволИсточника);
Если ПозицияСимвола <> 0 Тогда
СимволРезультата = Сред(СимволыАнгл, ПозицияСимвола, 1);
Иначе
СимволРезультата = СимволИсточника;
КонецЕсли;
ТекстАнгл = ТекстАнгл + СимволРезультата;
КонецЦикла;
Текст = ТекстАнгл;
КонецПроцедуры
Недостатки метода: Этот способ решает проблему лишь локально. Он требует постоянного контроля фокуса ввода (курсор должен быть установлен строго в соответствующее текстовое поле). Если пользователь случайно переключит фокус на другой элемент или операционная система пропустит часть быстрых нажатий клавиатуры от сканера, данные будут безнадежно испорчены.
Чтобы полностью исключить зависимость от раскладки клавиатуры и фокуса ввода, необходимо перевести сканер в режим работы через виртуальный COM-порт. При этом данные передаются в 1С в виде «сырого» потока байтов напрямую, минуя буфер клавиатуры Windows.
Проанализируем шаги настройки этого режима:
COM3).COM3), скорость передачи (обычно 9600) и сохраните настройки.При такой настройке при сканировании в 1С будет срабатывать предопределенное событие ОбработкаВнешнегоСобытия. Раскладка клавиатуры больше не имеет никакого значения — данные всегда приходят в корректной кодировке ASCII.
Рассмотрим еще одну частую ошибку разработчиков при поиске документов по считанному идентификатору. Часто в коде используют неоптимальный перебор коллекций метаданных, нагружающий базу данных:
// НЕОПТИМАЛЬНЫЙ КОД (Избегайте этого подхода!)
Для Каждого Менеджер Из Документы Цикл
СсылкаНаОбъект = Менеджер.ПолучитьСсылку(УникальныйИдентификатор);
Если СсылкаНаОбъект.ПолучитьОбъект() <> Неопределено Тогда
СсылкаНаОбъект.ПолучитьОбъект().ПолучитьФорму().Открыть();
Прервать;
КонецЕсли;
КонецЦикла;
Почему это плохо: Метод ПолучитьОбъект() выполняет тяжелый SQL-запрос к СУБД, считывая все реквизиты и табличные части документа. Если в вашей базе данных более 100 видов документов, система сделает до 100 ресурсоемких запросов, пытаясь выгрузить несуществующие объекты в оперативную память. Это приведет к сильным зависаниям интерфейса.
Разберем, как сделать поиск максимально легким с помощью запроса к СУБД, который проверяет только факт существования ссылки:
// ОПТИМАЛЬНЫЙ КОД поиска документа по GUID
Функция НайтиИОткрытьДокументПоИдентификатору(Знач Идентификатор) Экспорт
Для Каждого МетаданныеДокумента Из Метаданные.Документы Цикл
ИмяТаблицы = МетаданныеДокумента.Имя;
// Формируем быструю ссылку без обращения к базе данных
Ссылка = Документы[ИмяТаблицы].ПолучитьСсылку(Идентификатор);
// Легким запросом проверяем физическое наличие записи в конкретной таблице
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Т.Ссылка КАК Ссылка
|ИЗ
| Документ." + ИмяТаблицы + " КАК Т
|ГДЕ
| Т.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
// Объект найден. Открываем форму
ПараметрыФормы = Новый Структура("Ключ", Ссылка);
ОткрытьФорму("Документ." + ИмяТаблицы + ".ФормаОбъекта", ПараметрыФормы);
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
Этот код работает в десятки раз быстрее, так как СУБД выполняет только проверку наличия индексированного поля Ссылка, не загружая в память лишние данные.
Если ваша конфигурация построена на базе БСП (Библиотеки Стандартных Подсистем), рекомендуем использовать готовую подсистему «Штрихкодирование печатных форм». Она автоматически берет на себя формирование, печать и распознавание штрихкодов документов.
БСП формирует штрихкод по оптимальному алгоритму, кодируя тип документа коротким числовым префиксом, а номер — в формате EAN-13 или укороченном символьном представлении. Это избавляет от необходимости генерировать и сжимать GUID вручную.
Если бизнес-процессы вашей компании всё же требуют передачи больших объемов структурированной информации (например, GUID, дата, сумма и склад одновременно), рассмотрите переход на использование 2D-кодов (QR-код или DataMatrix). Платформа 1С v8.3 начиная с релиза 8.3.16 имеет встроенные инструменты для генерации QR-кодов прямо на уровне платформы без использования сторонних внешних компонент. 2D-коды обладают колоссальной плотностью записи и механизмами коррекции ошибок чтения, что делает сканирование стабильным даже при повреждении или загрязнении распечатанного документа.