Как создать свой нумератор для уникального штрихкода в 1С: Регистр сведений или Справочник?

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

В практике разработки на платформе 1С часто возникает задача генерации уникальных последовательностей цифр, которые не вписываются в стандартную нумерацию документов. Типичный пример — создание собственного штрихкода формата EAN-13. Нам необходимо получить 12 значащих цифр (где первые 2-3 цифры — префикс, остальные — уникальный номер) и рассчитать 13-е контрольное число. Основной вопрос: какой объект метаданных лучше использовать для хранения и получения следующего номера в многопользовательской среде?

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

Способ 1. Использование системной нумерации справочника

Многие разработчики, особенно имеющие опыт работы с ранними версиями платформы, предпочитают использовать Справочники. Этот метод основан на том, что платформа 1С «из коробки» умеет эффективно работать с уникальностью кодов. Мы можем создать вспомогательный справочник, назначить ему длину кода 10-12 символов и тип «Число» или «Строка».

Преимущества этого подхода:

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

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

Способ 2. Реализация нумератора через Регистр Сведений

Рассмотрим более гибкий и «профессиональный» метод — использование независимого регистра сведений. Это решение позволяет избежать раздувания таблиц справочников и дает полный контроль над логикой получения номера. Чтобы этот метод корректно работал при одновременной работе 50-100 пользователей, необходимо использовать механизм управляемых блокировок.

Разберем конкретный пример реализации функции получения номера. Создадим РегистрСведений.Нумераторы с измерением ИмяНумератора (тип Строка) и ресурсом Значение (тип Число).

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


Функция ПолучитьЗначениеНумератора(ИмяНумератора = "ШтрихкодыДокументов") Экспорт
    
    ТекущееЗначение = 0;
    
    // Начинаем транзакцию, чтобы заблокировать запись от чтения другими сеансами
    НачатьТранзакцию(РежимУправленияБлокировкойДанных.Управляемый);
    
    Попытка
        // Устанавливаем исключительную блокировку на конкретный нумератор
        Блокировка = Новый БлокировкаДанных;
        ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.Нумераторы");
        ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
        ЭлементБлокировки.УстановитьЗначение("ИмяНумератора", ИмяНумератора);
        Блокировка.Заблокировать();
        
        // Читаем текущее значение
        Запрос = Новый Запрос;
        Запрос.Текст = 
        "ВЫБРАТЬ
        |	Нумераторы.Значение КАК Значение
        |ИЗ
        |	РегистрСведений.Нумераторы КАК Нумераторы
        |ГДЕ
        |	Нумераторы.ИмяНумератора = &ИмяНумератора";
        
        Запрос.УстановитьПараметр("ИмяНумератора", ИмяНумератора);
        Выборка = Запрос.Выполнить().Выбрать();
        
        Если Выборка.Следующий() Тогда
            ТекущееЗначение = Выборка.Значение;
        КонецЕсли;
        
        // Увеличиваем счетчик и записываем обратно
        МенеджерЗаписи = РегистрыСведений.Нумераторы.СоздатьМенеджерЗаписи();
        МенеджерЗаписи.ИмяНумератора = ИмяНумератора;
        МенеджерЗаписи.Значение = ТекущееЗначение + 1;
        МенеджерЗаписи.Записать();
        
        ЗафиксироватьТранзакцию();
        
        // Возвращаем отформатированную строку (например, 10 знаков с ведущими нулями)
        Возврат Формат(ТекущееЗначение + 1, "ЧЦ=10; ЧН=0; ЧВН=; ЧГ=0");
        
    Исключение
        ОтменитьТранзакцию();
        ЗаписьЖурналаРегистрации("Ошибка нумератора", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
        Возврат Неопределено;
    КонецПопытки;
    
КонецФункции

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

Особенности формирования EAN-13

Получение уникального числа — это только половина задачи. Если вы планируете печатать штрихкод в формате EAN-13, необходимо помнить о структуре этого кода. Рассмотрим структуру подробнее:

  1. Префикс (2-3 знака): Для внутренних нужд предприятия (не для продажи в розничных сетях) принято использовать префиксы, начинающиеся с 20 до 29. Например, можно зарезервировать "200".
  2. Данные (9-10 знаков): Это и есть наше уникальное число, полученное из нумератора.
  3. Контрольный разряд (1 знак): Рассчитывается математически на основе первых 12 цифр.

Посмотрим на пример функции расчета контрольного числа для 12-значной последовательности цифр:


Функция РассчитатьКонтрольноеЧислоEAN13(Штрихкод12) Экспорт
    Четные = 0;
    Нечетные = 0;
    
    Для Индекс = 1 По 12 Цикл
        Цифра = Число(Сред(Штрихкод12, Индекс, 1));
        Если Индекс % 2 = 0 Тогда
            Четные = Четные + Цифра;
        Иначе
            Нечетные = Нечетные + Цифра;
        КонецЕсли;
    КонецЦикла;
    
    Сумма = Нечетные + Четные * 3;
    Контрольное = (10 - (Сумма % 10)) % 10;
    
    Возврат Строка(Контрольное);
КонецФункции

Альтернативные варианты: GUID и Unix Time

В ходе обсуждения часто звучат предложения использовать УникальныйИдентификатор (GUID) или текущее время в формате Unix Time. Проанализируем эти варианты:

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

Unix Time (количество секунд с 1970 года): На текущий момент это число состоит из 10 знаков. Казалось бы, идеальный кандидат для части штрихкода. Однако в высоконагруженных системах, где документы могут создаваться несколькими пользователями в одну и ту же секунду, этот метод гарантированно приведет к дублям. Его можно использовать только как «соль» в комбинации с префиксом узла или номером сеанса, но классический нумератор в таблице БД гораздо надежнее.

Резюме и рекомендации

Подведем итоги нашего исследования. Если перед вами стоит задача создания уникальных штрихкодов:

Выбор конкретного метода зависит от масштаба вашей системы, но реализация через РегистрСведений с ручным управлением блокировкой является наиболее универсальным и отказоустойчивым решением для программиста 1С.

← На главную