Почему сбивается автонумерация в 1С при установке префикса только для части элементов и как это исправить?

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

При разработке часто возникает задача разделить нумерацию элементов справочника или документов по определенному признаку, например, в зависимости от роли или подразделения текущего пользователя. Типичная реализация заключается в попытке назначить префикс только для выделенной группы пользователей, оставив для всех остальных стандартную нумерацию без префикса (пустую строку). Однако при таком подходе система начинает автоматически подставлять префикс даже тем элементам, для которых он явно не назначался. Разберем детально, почему это происходит и как правильно организовать разделение нумерации.

Рассмотрим пример кода в модуле объекта справочника, с которого обычно начинаются подобные сложности:


Процедура ПриУстановкеНовогоКода(СтандартнаяОбработка, Префикс)
    Если РольДоступна("СпециальнаяГруппа") И ЭтоНовый() Тогда
        Префикс = "~";
    КонецЕсли;
КонецПроцедуры

На первый взгляд логика кажется верной: для пользователей с определенной ролью задается префикс ~, а для остальных переменная Префикс остается пустой строкой. Однако при создании нового контрагента обычным пользователем платформа все равно формирует код вида ~000000015. Проанализируем внутренние механизмы платформы «1С:Предприятие», чтобы понять причину такого поведения.

Причина поведения: как работает штатный механизм автонумерации

Выясним причину сбоя нумерации. Механизм автонумерации платформы функционирует по следующим правилам:

  1. Строковый код или номер разделяется платформой на две составляющие: ведущую нечисловую часть (префикс) и завершающую числовую часть (сам порядковый номер).
  2. Когда в процедуру генерации кода передан непустой префикс (например, "~" или "ОСН-"), платформа ищет максимальный номер строго в рамках указанного префикса и увеличивает его числовую часть на единицу.
  3. Если префикс не передан (остается пустая строка ""), платформа не ищет элементы исключительно с пустым префиксом. Вместо этого механизм автонумерации находит лексикографически максимальный префикс среди всех существующих записей в таблице базы данных (по правилам сортировки строковых значений СУБД) и берет его в качестве базового шаблона.

Символ тильды ~ в таблице символов ASCII имеет код 126, что лексикографически старше цифр 0-9 (коды 48–57) и большинства букв. В результате при пустом префиксе СУБД возвращает код, начинающийся с ~, как максимальный, и платформа продолжает тиражировать этот префикс для всех последующих элементов.

Таким образом, в штатной автонумерации 1С не существует изолированной серии для «пустого префикса», если в этой же таблице присутствуют записи с непустыми префиксами. Рассмотрим основные пути решения этой проблемы.

Способ 1. Использование явных префиксов для всех потоков нумерации

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

Посмотрим на пример реализации в событии ПриУстановкеНовогоКода:


Процедура ПриУстановкеНовогоКода(СтандартнаяОбработка, Префикс)
    Если РольДоступна("СпециальнаяГруппа") Тогда
        Префикс = "СПЕЦ-";
    Иначе
        Префикс = "ОСН-";
    КонецЕсли;
КонецПроцедуры

В этом случае платформа видит две четко разделенные серии номеров: СПЕЦ-00001 и ОСН-00001. Нумерация по каждой серии будет вестись полностью независимо, без взаимного влияния и сбоев.

Способ 2. Отключение стандартной обработки и собственный расчет номера

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

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

  1. Отключаем стандартную автонумерацию установкой флага СтандартнаяОбработка = Ложь;.
  2. Определяем, требуется ли префикс текущему пользователю.
  3. Выполняем запрос к информационной базе для получения максимального числового значения кода нужного формата (для беспрефиксных кодов отбираем только цифровые значения).
  4. Формируем следующий номер и дополняем его лидирующими нулями до необходимой длины с помощью функции Формат.

Рассмотрим пример программной реализации:


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

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

Способ 3. Использование подсистемы «Префиксация объектов» БСП

Если разработка ведется в типовой конфигурации на базе «Библиотеки стандартных подсистем» (БСП), не рекомендуется переопределять модуль объекта напрямую. Вместо этого следует использовать встроенные механизмы подсистемы префиксации.

Для добавления пользовательской логики префиксов используется процедура ПриУстановкеНовогоКода общего модуля ПрефиксацияОбъектовПереопределяемый. Это позволяет сохранить совместимость с механизмами нумерации БСП, корректно обрабатывать префиксы узлов РИБ и префиксы организаций, а также гарантирует корректное обновление конфигурации в будущем.

← На главную