Внедрение штрихкодирования печатных форм документов в «1С:Бухгалтерия 3» — это отличный способ ускорить обработку бумажного архива и минимизировать ошибки ручного ввода. Типичный сценарий выглядит так: на печатную форму документа выводится уникальный штрихкод. После того как бумажная копия возвращается с подписью контрагента, ответственный сотрудник сканирует этот штрихкод, и система мгновенно находит и открывает нужный документ в базе данных. При большом потоке документов программные роботы на платформе One RPA могут самостоятельно открывать найденные объекты и выполнять с ними нужные операции.
Однако при проектировании этой системы разработчики часто сталкиваются со сложными архитектурными вопросами: какой формат штрихкода выбрать, как избежать дублирования номеров при одновременной работе десятков пользователей и как организовать хранение штрихкодов в информационной базе. Разберем детально несколько эффективных подходов к решению этой задачи, проанализируем их плюсы и минусы, а также посмотрим на практические примеры реализации.
Этот подход активно применяется в современных типовых конфигурациях 1С (таких как «Управление торговлей 11» или «ERP»). Его суть заключается в том, что нам вообще не требуется создавать выделенные регистры сведений или справочники для хранения штрихкодов документов, а также решать проблему конкурентного доступа при записи счетчиков.
У каждого объекта (документа или справочника) в СУБД есть уникальный идентификатор — УникальныйИдентификатор (GUID). Он гарантированно уникален в пределах всей базы данных и даже за ее пределами. Мы можем преобразовать этот GUID в строку, закодировать его в штрихкод формата Code-128 или двухмерный DataMatrix (QR-код) и вывести на печать. Для практической реализации этой задачи в «1С:Бухгалтерии» подойдёт готовая обработка для генерации QR-кода в УПД.
Рассмотрим, как это работает на практике. При генерации печатной формы мы берем GUID документа, удаляем из него дефисы для компактности и передаем в генератор штрихкода:
Функция ПолучитьКодДокументаДляПечати(СсылкаНаДокумент) Экспорт
// Получаем строку уникального идентификатора без дефисов
СтрокаGUID = СтрЗаменить(Строка(СсылкаНаДокумент.УникальныйИдентификатор()), "-", "");
Возврат СтрокаGUID;
КонецФункции
При сканировании такого штрихкода нам достаточно восстановить исходный формат GUID (вернуть дефисы на свои места) и быстро получить ссылку на документ по идентификатору без выполнения тяжелых поисковых запросов к базе данных:
Функция НайтиДокументПоШтрихкодуGUID(Знач ШтрихкодСтрока) Экспорт
Если СтрДлина(ШтрихкодСтрока) <> 32 Тогда
Возврат Неопределено;
КонецЕсли;
// Восстанавливаем дефисы в структуре GUID (8-4-4-4-12)
ШаблонGUID = Сред(ШтрихкодСтрока, 1, 8) + "-" +
Сред(ШтрихкодСтрока, 9, 4) + "-" +
Сред(ШтрихкодСтрока, 13, 4) + "-" +
Сред(ШтрихкодСтрока, 17, 4) + "-" +
Сред(ШтрихкодСтрока, 21, 12);
Попытка
Идентификатор = Новый УникальныйИдентификатор(ШаблонGUID);
// Пример поиска для документа "Реализация товаров и услуг"
СсылкаНаДокумент = Документы.РеализацияТоваровУслуг.ПолучитьСсылку(Идентификатор);
// Проверяем, существует ли реальный документ в базе данных
Если ОбщегоНазначения.СсылкаСуществует(СсылкаНаДокумент) Тогда
Возврат СсылкаНаДокумент;
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации("Штрихкодирование", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;
Возврат Неопределено;
КонецФункции
Преимущества этого метода:
Недостатки:
Code-128 для кодирования 32-36 символов получается достаточно длинным. На маленьких этикетках или узких полях печатной формы он может плохо считываться бюджетными сканерами. Проблема решается переходом на двухмерный штрихкод DataMatrix.Бывают ситуации, когда руководство предприятия жестко настаивает на использовании формата EAN-13 (например, если на предприятии уже закуплены простейшие одномерные сканеры, которые не умеют читать ничего, кроме стандартных «товарных» кодов). Поскольку EAN-13 содержит всего 12 значащих цифровых символов (13-й символ — это контрольное число), закодировать туда GUID физически невозможно. Нам придется вести сквозной счетчик и хранить соответствия в базе.
Для реализации этого подхода создадим независимый непериодический регистр сведений ШтрихкодыДокументов со следующей структурой:
Штрихкод (Тип: Строка, длина 13, индексировать).ДокументСсылка (Тип: ЛюбаяСсылка).При генерации номера штрихкода EAN-13 важно правильно структурировать эти 12 цифр, чтобы избежать коллизий. Проанализируем оптимальную структуру кода:
24.Выясним причину главной проблемы этого метода: если два пользователя одновременно нажмут кнопку печати документов, система попытается прочитать последний номер из регистра, увеличить его на единицу и записать обратно. Без использования механизмов контроля транзакций это неизбежно приведет либо к ошибке блокировки записи, либо к выдаче одинаковых штрихкодов двум разным документам.
Чтобы исключить дублирование номеров при генерации штрихкодов в регистре сведений, нам необходимо использовать механизм управляемых блокировок. Мы должны гарантировать, что в момент получения максимального номера штрихкода из регистра и до момента записи новой строки, ни один другой сеанс не сможет прочитать эти же данные или внести изменения.
Рассмотрим пример функции безопасного получения нового штрихкода с установкой исключительной управляемой блокировки регистра:
Функция ПолучитьНовыйШтрихкодДокумента(СсылкаНаДокумент, ПрефиксУзла = "0", КодТипаДокумента = "01") Экспорт
НачатьТранзакцию();
Попытка
// Устанавливаем управляемую блокировку на регистр штрихкодов
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ШтрихкодыДокументов");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
// Ищем в регистре штрихкод, который уже привязан к этому документу
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Штрихкоды.Штрихкод КАК Штрихкод
|ИЗ
| РегистрСведений.ШтрихкодыДокументов КАК Штрихкоды
|ГДЕ
| Штрихкоды.ДокументСсылка = &СсылкаНаДокумент";
Запрос.УстановитьПараметр("СсылкаНаДокумент", СсылкаНаДокумент);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
ЗафиксироватьТранзакцию();
Возврат Выборка.Штрихкод;
КонецЕсли;
// Если кода еще нет, получаем максимальный порядковый номер для нашей структуры
ЗапросМаксКод = Новый Запрос;
ЗапросМаксКод.Текст =
"ВЫБРАТЬ
| МАКСИМУМ(ПОДСТРОКА(Штрихкоды.Штрихкод, 6, 7)) КАК МаксНомер
|ИЗ
| РегистрСведений.ШтрихкодыДокументов КАК Штрихкоды
|ГДЕ
| Штрихкоды.Штрихкод ПОДОБНО &МаскаШтрихкода";
// Маска для поиска: ПрефиксИспользования(24) + ПрефиксУзла + КодТипаДокумента
Маска = "24" + ПрефиксУзла + КодТипаДокумента + "%";
ЗапросМаксКод.УстановитьПараметр("МаскаШтрихкода", Маска);
РезультатМакс = ЗапросМаксКод.Выполнить();
НовыйНомер = 1;
Если Не РезультатМакс.Пустой() Тогда
ВыборкаМакс = РезультатМакс.Выбрать();
ВыборкаМакс.Следующий();
Если ЗначениеЗаполнено(ВыборкаМакс.МаксНомер) Тогда
НовыйНомер = Число(ВыборкаМакс.МаксНомер) + 1;
КонецЕсли;
КонецЕсли;
// Форматируем номер до 7 символов (дополняем нулями слева)
СтрокаНомера = Формат(НовыйНомер, "ЧЦ=7; ЧДЦ=0; ЧГ=0");
СтрокаНомера = СтрЗаменить(СтрокаНомера, " ", "0");
// Собираем 12 цифр без контрольного символа
ШтрихкодБезКонтрольного = "24" + ПрефиксУзла + КодТипаДокумента + СтрокаНомера;
// Рассчитываем контрольный символ по алгоритму EAN-13
КонтрольныйСимвол = РассчитатьКонтрольныйСимволEAN13(ШтрихкодБезКонтрольного);
ИтоговыйШтрихкод = ШтрихкодБезКонтрольного + Строка(КонтрольныйСимвол);
// Записываем новый штрихкод в регистр
МенеджерЗаписи = РегистрыСведений.ШтрихкодыДокументов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Штрихкод = ИтоговыйШтрихкод;
МенеджерЗаписи.ДокументСсылка = СсылкаНаДокумент;
МенеджерЗаписи.Записать(Истина);
ЗафиксироватьТранзакцию();
Возврат ИтоговыйШтрихкод;
Исключение
ОтменитьТранзакцию();
ВызватьИсключение "Не удалось сгенерировать уникальный штрихкод документа: " + КраткоеОписаниеОшибки(ОписаниеОшибки());
КонецПопытки;
КонецФункции
Функция РассчитатьКонтрольныйСимволEAN13(Штрихкод12)
Четные = 0;
Нечетные = 0;
Для Индекс = 1 По 12 Цикл
Цифра = Число(Сред(Штрихкод12, Индекс, 1));
Если Индекс % 2 = 0 Тогда
Четные = Четные + Цифра;
Иначе
Нечетные = Нечетные + Цифра;
КонецЕсли;
КонецЦикла;
Сумма = Нечетные + (Четные * 3);
Остаток = Сумма % 10;
Если Остаток = 0 Тогда
Возврат 0;
Иначе
Возврат 10 - Остаток;
КонецЕсли;
КонецФункции
Проанализируем этот код подробнее. Использование управляемой блокировки на уровне СУБД гарантирует, что параллельный сеанс, вызвавший эту же функцию, приостановит свое выполнение на строке Блокировка.Заблокировать() и будет ожидать завершения транзакции первого пользователя (пока не выполнится ЗафиксироватьТранзакцию() или ОтменитьТранзакцию()). Это полностью исключает генерацию дубликатов штрихкодов в условиях высокой конкурентной нагрузки.
Еще один популярный вариант, который часто применяется на практике, — кодирование в штрихкод Code-128 понятной человеку текстовой строки. Например, структуры вида: КодОрганизации + КодТипаДокумента + НомерДокумента + ДатаДокумента.
Допустим, документ «Реализация товаров и услуг» № РУ00-00142 от 15 октября 2023 года организации с кодом «МС» можно закодировать строкой: МС-РТУ-00142-15102023.
Рассмотрим особенности этого решения:
Разработчикам современных конфигураций на платформе «1С:Предприятие 8.3» больше нет необходимости устанавливать на компьютеры пользователей устаревшие внешние шрифты или сторонние компоненты ActiveX. В составе Библиотеки стандартных подсистем (БСП) поставляется Native-компонента печати штрихкодов, которая отлично работает как на стороне Windows-клиентов, так и под управлением серверов 1С на ОС Linux. Для удобной доработки печатных форм БСП можно использовать метод постобработки печатных форм с помощью расширения.
Проанализируем пример кода, выводящего сгенерированный штрихкод в область табличного документа печатной формы с использованием механизмов БСП:
Процедура ВывестиШтрихкодВТабличныйДокумент(ТабличныйДокумент, ОбластьМакета, ЗначениеШтрихкода)
// Параметры для формирования штрихкода компонентой БСП
ПараметрыШтрихкода = Новый Структура;
ПараметрыШтрихкода.Вставить("Ширина", 400);
ПараметрыШтрихкода.Вставить("Высота", 150);
ПараметрыШтрихкода.Вставить("ТипКода", 1); // 1 - это тип EAN13. Для Code128 используется значение 4.
ПараметрыШтрихкода.Вставить("ОтображатьТекст", Истина);
ПараметрыШтрихкода.Вставить("РазмерШрифта", 10);
ПараметрыШтрихкода.Вставить("УголПоворота", 0);
ПараметрыШтрихкода.Вставить("Штрихкод", ЗначениеШтрихкода);
// Получаем двоичные данные картинки штрихкода через БСП
КартинкаДвоичныеДанные = МенеджерОборудованияВызовСервера.ПолучитьКартинкуШтрихкода(ПараметрыШтрихкода);
Если КартинкаДвоичныеДанные <> Неопределено Тогда
// Создаем объект Картинка и помещаем его на макет в область рисунка
КартинкаШтрихкода = Новый Картинка(КартинкаДвоичныеДанные);
РисунокМакета = ОбластьМакета.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
РисунокМакета.Картинка = КартинкаШтрихкода;
// Позиционируем рисунок в созданной области макета
РисунокМакета.Расположить(ОбластьМакета.Область("R1C1:R3C5"));
РисунокМакета.ГраницаСверху = Ложь;
РисунокМакета.ГраницаСнизу = Ложь;
РисунокМакета.ГраницаСлева = Ложь;
РисунокМакета.ГраницаСправа = Ложь;
КонецЕсли;
КонецПроцедуры
Мы проанализировали различные варианты организации штрихкодирования документов в 1С. Выбор конкретного подхода зависит от требований вашего бизнеса и инфраструктуры:
DataMatrix или одномерный Code-128. Это современное, быстрое и надежное решение, которое полностью избавит вас от необходимости писать процедуры блокировок, убережет от коллизий в распределенных базах и сохранит высокую производительность системы.EAN-13, используйте Вариант 3 с ведением отдельного регистра сведений и обязательной установкой управляемых исключительных блокировок. Не забудьте выделить отдельные префиксы под типы документов и узлы РИБ, чтобы гарантировать уникальность кодов в распределенной сети компании.