В какой момент у документа в 1С появляется номер и как правильно записать его в дополнительный реквизит?

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

При разработке расширений для ЗУП 3.1 или других современных конфигураций на базе БСП программисты часто сталкиваются с задачей: нужно создать дополнительный реквизит (например, НумОт_НомерТ60), который должен в точности повторять основной номер документа. Казалось бы, простая задача превращается в проблему, так как в привычных событиях объект еще не имеет номера или уже записан в базу, что делает его изменение невозможным без повторной записи.

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

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

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

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

В современных версиях 1С используется так называемая отложенная нумерация. Платформа старается выдать номер в самый последний момент — непосредственно во время транзакции записи. Именно поэтому в процедуре ПередЗаписью номер зачастую еще пуст.

Разбор ошибки: почему не работает код в событии ПриЗаписи?

Рассмотрим типичную ошибку начинающего разработчика, которая упоминалась в обсуждении. Попытка присвоить значение в процедуре ПриЗаписи выглядит логично, так как номер уже точно сформирован. Однако, как гласит справка 1С:

"Обработчик ПриЗаписи вызывается после записи объекта в базу данных, но до окончания транзакции записи."

Это означает, что данные уже "сброшены" в таблицы БД. Если вы напишете Объект.ДополнительныйРеквизит = Объект.Номер, значение изменится только в оперативной памяти (в текущем экземпляре объекта), но не в самой базе данных. Чтобы сохранить это изменение, пришлось бы вызывать метод Записать() повторно, что приведет к бесконечной рекурсии и аварийному завершению работы.

Способ 1: Принудительная генерация в ПередЗаписью

Один из вариантов решения — принудительно заставить платформу выдать номер перед тем, как объект будет зафиксирован в базе. Разберем пример кода, который можно внедрить через расширение в процедуру ПередЗаписью:


&После("ПередЗаписью")
Процедура НумОт_ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Проверяем, что это новый документ и номер еще не назначен
    Если Не Отказ И ЭтоНовый() И ЗначениеЗаполнено(Номер) = Ложь Тогда
        // Принудительно генерируем номер прямо сейчас
        УстановитьНовыйНомер();
        // Теперь мы можем скопировать его в наш реквизит
        НумОт_НомерТ60 = Номер;
    КонецЕсли; 
    
КонецПроцедуры

Важный нюанс этого метода: Вызывая УстановитьНовыйНомер(), вы берете на себя ответственность за этот номер. Если после этого в коде возникнет ошибка или отказ от записи (параметр Отказ = Истина), номер все равно будет считаться "выданным" платформой, и в последовательности номеров может возникнуть пропуск.

Способ 2: Использование события ПриУстановкеНовогоНомера

Это наиболее "чистый" и правильный с точки зрения архитектуры способ. Событие ПриУстановкеНовогоНомера специально предназначено для вмешательства в процесс нумерации. Рассмотрим алгоритм его использования:

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

Пример реализации:


&После("ПриУстановкеНовогоНомера")
Процедура НумОт_ПриУстановкеНовогоНомера(СтандартнаяОбработка, Префикс)
    // К этому моменту Номер уже содержит сгенерированное значение
    НумОт_НомерТ60 = Номер;
КонецПроцедуры

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

Способ 3: Получение номера без записи основного объекта (Служебное копирование)

Проанализируем ситуацию, когда нам нужно узнать будущий номер документа еще до того, как мы нажали кнопку "Записать" (например, для вывода в печатную форму в режиме предпросмотра). Для этого можно использовать метод временного копирования объекта, как было предложено в одном из сообщений форума:


// Устанавливаем привилегированный режим для работы с нумерацией
УстановитьПривилегированныйРежим(Истина);

// Получаем объект из реквизитов формы
ДокументОбъект = РеквизитФормыВЗначение("Объект");

// Создаем временную копию
ВременныйОбъект = ДокументОбъект.Скопировать();
ВременныйОбъект.Дата = Объект.Дата;

// Генерируем номер для копии
ВременныйОбъект.УстановитьНовыйНомер();

// Будущий номер теперь известен
БудущийНомер = ВременныйОбъект.Номер;

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

Выводы и рекомендации

Подведем итог нашего исследования механизмов работы с номерами в 1С:

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

← На главную