Как правильно реализовать нестандартную нумерацию документов в 1С и избежать ошибок кастомного нумератора?

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

При разработке конфигураций в 1С часто возникает необходимость внедрить специфическую схему нумерации документов — например, добавлять буквы, буквенные индексы участков или суффиксы (постфиксы) вида 0001/ХРК. Начинающие разработчики нередко пишут собственные алгоритмы поиска последнего номера через запрос и выборку в таблице значений. Разберем, какие критические ошибки скрывает такой подход и как правильно решить задачу средствами платформы 1С.

Основные ошибки при написании собственного нумератора

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

  1. Риск дублирования номеров при параллельной работе. Если два и более пользователя одновременно создают и записывают документ одного вида, запрос в обоих сеансах выберет один и тот же текущий максимальный номер. В результате система попытается присвоить обоим документам одинаковый номер, что приведет к ошибкам записи («Номер документа не уникален») или коллизиям в данных. Чтобы этого избежать при собственном подсчете, требуется использовать механизмы транзакционных управляемых блокировок БлокировкаДанных.
  2. Использование функции Строка() для формирования номера. При преобразовании числа в строку вызовом Строка(Число) платформа 1С автоматически добавляет неразрывные пробелы как разделители триад разрядов, когда число превышает 999 (например, получаем строку "1 000/ХРК" с пробелом внутри). В номерах документов это недопустимо. Для отключения группировки разрядов необходимо использовать функцию Формат(Число, "ЧГ=0").
  3. Жесткое кодирование значений (Hardcode) в теле процедуры. Условия вида Если Участок = Перечисления.УчасткиРК.Хорошево Тогда... привязывают логику к конкретным значениям метаданных. При добавлении нового участка придется изменять исходный код модуля. Все суффиксы, префиксы и настройки нумерации должны храниться в реквизитах справочников или в регистрах сведений.
  4. Использование суффиксов (постфиксов) вместо префиксов. Стандартный нумератор платформы 1С корректно работает и инкрементирует числа только тогда, когда буквенная или текстовая часть находится в начале номера (префикс). Если буквенный код расположен в конце номера (суффикс), автонумератор платформы теряет способность определять числовую часть, что вынуждает разработчиков полностью отказываться от стандартного механизма.

Вариант 1. Использование стандартного нумератора и префиксов

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

Для переопределения префикса используется стандартное событие модуля объекта ПриУстановкеНовогоНомера:


Процедура ПриУстановкеНовогоНомера(СтандартнаяОбработка, Префикс)
    
    // Получаем буквенный код участка из реквизита справочника или регистра
    БуквенныйКод = Источник.УчастокРК.ПрефиксНомера; // Перемещение логики в реквизит
    
    Если ЗначениеЗаполнено(БуквенныйКод) Тогда
        Префикс = БуквенныйКод + "-";
    КонецЕсли;

КонецПроцедуры

В данном случае номер документа будет иметь вид ХРК-000000001. Такой номер легко сортируется в списках, не вызывает сбоев платформы и гарантирует корректную работу при одновременной записи нескольких документов.

Вариант 2. Вынос логики получения суффикса в модуль объекта/менеджера

Если структура с суффиксом строго регламентирована и менять её на префикс запрещено бизнес-требованиями, необходимо как минимум вынести маппинг обозначений из кода процедуры. Для этого создается функция в модуле менеджера или используется реквизит справочника:


Функция ПолучитьСуффиксУчастка(ЗначениеУчастка) Экспорт
    
    Если ЗначениеУчастка = Перечисления.УчасткиРК.Хорошево Тогда
        Возврат "/ХРК";
    ИначеЕсли ЗначениеУчастка = Перечисления.УчасткиРК.Мытищи Тогда
        Возврат "/МРК";
    ИначеЕсли ЗначениеУчастка = Перечисления.УчасткиРК.Ярославль Тогда
        Возврат "/ЯРК";
    ИначеЕсли ЗначениеУчастка = Перечисления.УчасткиРК.Коломна Тогда
        Возврат "/КРК";
    КонецЕсли;
    
    Возврат "";

КонецФункции

Тогда сборка номера выполняется без громоздких условий ИначеЕсли:


Суффикс = Перечисления.УчасткиРК.ПолучитьСуффиксУчастка(Источник.УчастокРК);
Источник.Номер = Формат(СледующийНомер, "ЧГ=0") + Суффикс;

Вариант 3. Разделение физического номера и его отображения (ПредставлениеНомера)

Чтобы сохранить стандартную надежную нумерацию платформы и одновременно показывать пользователям номер с любыми суффиксами и спецсимволами, применяется подход с пользовательским представлением.

  1. Реквизит Номер оставляют стандартным (например, чисто числовым или с префиксом 000000001).
  2. В документ добавляется дополнительный реквизит ПредставлениеНомера или переопределяется обработчик ОбработкаПолученияПредставления в модуле менеджера документа.

Рассмотрим пример переопределения представления документа в модуле менеджера:


Процедура ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Формируем пользовательское представление номера с суффиксом
    ЧисловойНомер = СокрЛП(СлужебныеФункции.УбратьЛидирующиеНули(Данные.Номер));
    Суффикс = Перечисления.УчасткиРК.ПолучитьСуффиксУчастка(Данные.УчастокРК);
    
    Представление = СтрШаблон("%1 № %2%3 от %4", 
        Метаданные().Синоним, 
        ЧисловойНомер, 
        Суффикс, 
        Формат(Данные.Дата, "ДФ=dd.MM.yyyy"));

КонецПроцедуры

При таком подходе платформа физически хранит строгий уникальный номер, обеспечивающий высокую скорость поиска и отсутствие блокировок, а во всех журналах, печатных формах и отчетах пользователь видит привычный номер вида 15/ХРК.

Вариант 4. Безопасная кастомная нумерация с регистрами сведений и блокировками

Если требуется физически записывать нестандартный номер в поле Номер и нумеровать документы строго по порядку в разрезе участков, корректной архитектурой будет использование вспомогательного регистра сведений (например, СчетчикиНомеровДокументов).

Схема работы включает следующие шаги:

  1. Создается правильная структура регистра с измерением УчастокРК (и при необходимости ПериодГод) и ресурсом ТекущийНомер (Тип: Число).
  2. В момент установки нового номера внутри транзакции записи документа устанавливается управляемая блокировка на запись регистра с соответствующим участком:

Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.СчетчикиНомеровДокументов");
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.УстановитьЗначение("УчастокРК", Источник.УчастокРК);
Блокировка.Заблокировать();

// Читаем текущий номер из регистра, увеличиваем на 1, записываем обратно
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Счетчики.ТекущийНомер КАК ТекущийНомер
    |ИЗ
    |	РегистрСведений.СчетчикиНомеровДокументов КАК Счетчики
    |ГДЕ
    |	Счетчики.УчастокРК = &УчастокРК";

Запрос.УстановитьПараметр("УчастокРК", Источник.УчастокРК);
Выборка = Запрос.Выполнить().Выбрать();

НовыйНомерЧисло = 1;
Если Выборка.Следующий() Тогда
    НовыйНомерЧисло = Выборка.ТекущийНомер + 1;
КонецЕсли;

// Фиксируем новый номер в регистре
МенеджерЗаписи = РегистрыСведений.СчетчикиНомеровДокументов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.УчастокРК = Источник.УчастокРК;
МенеджерЗаписи.ТекущийНомер = НовыйНомерЧисло;
МенеджерЗаписи.Записать();

// Присваиваем номер документу с отключением триад разрядов
Суффикс = Перечисления.УчасткиРК.ПолучитьСуффиксУчастка(Источник.УчастокРК);
Источник.Номер = Формат(НовыйНомерЧисло, "ЧГ=0") + Суффикс;

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

← На главную