Почему при повторном вызове метода УстановитьНовыйНомер увеличивается номер документа и как это исправить?

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

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

Выясним причину: как работает менеджер автонумерации платформы

Проанализируем внутреннее поведение платформы при выполнении метода УстановитьНовыйНомер():

  1. Блокировка номера в памяти сервера. Когда вызывается метод генерации номера, система обращается к внутреннему менеджеру автонумерации. Менеджер вычисляет максимальный номер среди записанных объектов с учетом периода и переданного префикса, прибавляет единицу и резервирует полученное значение в оперативной памяти текущего сеанса. Это необходимо для предотвращения дублирования номеров в многопользовательском режиме.
  2. Повторный вызов метода. Если мы повторно вызываем УстановитьНовыйНомер() для того же объекта или пока старый объект все еще удерживается в памяти, менеджер видит, что предыдущий номер уже зарезервирован. Чтобы избежать коллизии, система выдает следующий свободный номер — на единицу больше.
  3. Влияние свойства конфигурации. В свойствах корневого узла метаданных конфигурации есть пункт Режим автонумерации объектов. Если установлено значение Не освобождать автоматически, зарезервированные в памяти номера не возвращаются в пул свободных номеров вплоть до перезапуска сеанса или завершения транзакции, даже если документ не был записан.

Почему режим «Освобождать автоматически» не решает проблему полностью

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

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

Архитектурно правильное решение: перенос нумерации на момент записи

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

Разберем, как реализовать этот подход:

  1. Отказ от ручного вызова метода в форме. Исключим вызов УстановитьНовыйНомер() из событий ПриСозданииНаСервере или ПриОткрытии формы. Поле номера на форме должно оставаться пустым.
  2. Использование событий объекта или подписок. Платформа автоматически вызывает назначение номера в начале транзакции записи нового документа. Для централизованного управления префиксами используется либо модуль самого документа, либо общая ПодпискаНаСобытие для метаданных с событием ПриУстановкеНовогоНомера.

Посмотрим на пример обработчика в модуле документа:


Процедура ПриУстановкеНовогоНомера(СтандартнаяОбработка, Префикс)
    
    // Добавляем к номеру префикс организации или узла распределенной базы
    Префикс = Префикс + "ОФ_";
    
КонецПроцедуры

При таком подходе номер формируется ровно в момент записи. Если пользователь передумал и закрыл форму нового документа, никакого резервирования в базе не происходит, и «дырок» в нумерации не возникает.

Что делать, если номера уже «убежали» вперед: метод ОбновитьНумерациюОбъектов

Если в процессе тестирования или сбоев счетчик зафиксировал завышенное значение, даже после удаления ошибочных документов система может продолжать выдавать завышенные номера. Для синхронизации кэша менеджера автонумерации с фактическими данными таблиц базы используется метод глобального контекста ОбновитьНумерациюОбъектов().

Посмотрим на пример сброса счетчиков для конкретного типа документов:


// Сброс и пересчет автонумерации для одного вида документов
ОбновитьНумерациюОбъектов(Метаданные.Документы.РеализацияТоваровУслуг);

// Если вызвать метод без параметров, нумерация пересчитается для всей конфигурации
ОбновитьНумерациюОбъектов();

Альтернативные варианты отображения номера

Рассмотрим ситуации, когда бизнес-процесс требует показать пользователю будущий номер документа еще до записи:

  1. Предварительный расчет без фиксации. Не вызываем платформенный метод УстановитьНовыйНомер(). Вместо этого выполняем запрос к таблице документов, находим максимальный номер за текущий период с требуемым префиксом, прибавляем единицу и выводим полученную строку во вспомогательную надпись или реквизит формы. При этом реквизит документа Номер остается пустым вплоть до записи.
  2. Собственный регистр нумерации для строгой отчетности. Для объектов, где пропуски номеров категорически недопустимы законодательством, штатный менеджер автонумерации не гарантирует непрерывность при откате транзакций записи. В таких задачах создают отдельный регистр сведений, хранящий текущие значения счетчиков, и увеличивают их строго внутри транзакции записи с применением управляемой блокировки.
← На главную