Рано или поздно многие разработчики и администраторы систем на платформе «1С:Предприятие» сталкиваются с неприятной ситуацией: при попытке создания нового документа система отказывается автоматически присваивать ему номер или начинает бесконечно предлагать один и тот же последний номер (например, ОТЧТ99999). Это сигнализирует о том, что свободный диапазон номеров для данного типа документа полностью исчерпан.
В этой статье мы подробно разберем, почему возникает эта проблема, как работает механизм автонумерации «под капотом» платформы 1С и СУБД, а также рассмотрим несколько практических сценариев решения — от быстрых «костылей» для оперативного восстановления работы базы до красивых архитектурных решений на перспективу.
Рассмотрим ситуацию, когда разработчик пытается решить проблему «в лоб»: увеличивает длину номера в конфигураторе (например, с 9 до 10 символов) и вручную переименовывает самый последний документ с номера ОТЧТ99999 на ОТЧТ099999, рассчитывая, что система продолжит нумерацию дальше. Однако при создании следующего документа автонумератор снова выдает ошибку или предлагает старый номер. Выясним, почему так происходит.
Дело в том, что строковые данные в базах данных (будь то SQL Server, PostgreSQL или файловая СУБД 1С) сравниваются посимвольно слева направо по таблице кодов (ASCII/Unicode), а не по математическому значению. Платформа 1С определяет максимальный существующий номер в базе данных с помощью стандартного SQL-запроса с функцией MAX() по полю номера документа.
Проанализируем, как СУБД сравнивает два номера разной длины: ОТЧТ99998 (длина 9) и новый измененный ОТЧТ099999 (длина 10):
ОТЧТ).9 и символ 0.9 больше, чем код символа 0, СУБД делает однозначный вывод: строка ОТЧТ99998 больше, чем ОТЧТ099999.В результате СУБД всегда считает старые короткие номера «более старшими», чем новые длинные номера с лидирующими нулями. Автонумератор находит старый документ ОТЧТ99998 (или ОТЧТ99999) в качестве максимального, прибавляет к нему единицу и снова пытается записать документ с номером ОТЧТ99999, вызывая конфликт уникальности.
Важное правило: Если вы увеличиваете разрядность кода или номера в метаданных, вам необходимо перенумеровать абсолютно все существующие документы этого типа в базе данных, добавив в них лидирующие нули (например, превратить ОТЧТ00001 в ОТЧТ000001). В противном случае автонумератор всегда будет спотыкаться о старые короткие номера.
В современных версиях платформы «1С:Предприятие» (начиная с 8.1) работает специальный оптимизированный менеджер автонумерации. Для снижения блокировок таблиц СУБД при параллельной работе пользователей сервер приложений кэширует порции свободных номеров в оперативной памяти.
Если вы перенумеровали документы программно или вручную непосредственно в базе данных, кэш сервера 1С об этом не узнает. Он продолжит выдавать старые номера из своей памяти. Чтобы заставить систему полностью очистить кэш и заново просканировать физические таблицы СУБД для поиска актуального максимального номера, необходимо применить метод ОбновитьНумерациюОбъектов().
Для этого мы можем запустить короткий фрагмент кода в консоли кода или во внешней обработке:
// Обновление нумерации конкретного типа документа
ОбновитьНумерациюОбъектов(Метаданные.Документы.НетиповойОтчет);
В клиент-серверном варианте базы данных альтернативой этому коду является перезапуск службы сервера 1С, однако вызов метода программно является более щадящим и не прерывает работу пользователей.
Для правильного проектирования нумерации важно понимать, как именно платформа выделяет префикс и число из текстового поля «Номер»:
Рассмотрим на примерах:
ОТЧТ99999 числовая часть — 99999, префикс — ОТЧТ.ОТЧТ99-99 числовая часть — 99, префикс — ОТЧТ99-. При автонумерации следующий номер будет ОТЧТ99-100.ОТЧТ99999А), числовая часть распознана не будет, автонумерация для этого префикса прекратит корректно работать.Давайте подробно рассмотрим четыре практических способа решения возникшей проблемы, оценив их плюсы и минусы.
Самый простой и быстрый способ вернуть систему к жизни без изменения метаданных конфигурации — это использование нового префикса. Если ваш старый префикс был ОТЧТ, вы можете создать следующий документ и вручную задать ему номер с новым префиксом, например ОТЧА00001 или ОТЧ000001 (сократив буквенную часть префикса для увеличения разрядности под цифры).
Платформа автоматически распознает новый префикс и продолжит автонумерацию с него: ОТЧА00002, ОТЧА00003 и так далее.
Преимущества:
Недостатки:
Наиболее правильное архитектурное решение для документов с высокой интенсивностью создания — включение периодичности нумерации «В пределах года».
Посмотрим на алгоритм реализации этого решения:
ПриУстановкеНовогоНомера.ОТЧТ26-00001, в 2027 году — ОТЧТ27-00001.При таком подходе каждый год нумерация будет сбрасываться в единицу, что навсегда исключает проблему переполнения разрядов.
Что делать с документами текущего года до изменения периодичности?
Так как год только начался, документов создано немного. Их необходимо перенумеровать программной обработкой под новый формат префикса (например, с ОТЧТ99999 на ОТЧТ26-00001 и так далее), после чего обновить нумерацию объектов в кэше.
Если бизнес-требования категорически запрещают менять префиксы или вводить периодичность (нужна сквозная единая нумерация за все годы), то единственным выходом будет увеличение длины номера в конфигураторе и последующая полная перенумерация базы данных.
Допустим, мы увеличили длину номера с 9 до 11 символов. Теперь нам нужно превратить все старые номера вида ОТЧТ00001 в ОТЧТ0000001. Для этого напишем и запустим несложный скрипт:
Выборка = Документы.НетиповойОтчет.Выбрать();
СистематизированныйПрефикс = "ОТЧТ";
ЦелеваяДлинаНомера = 11; // Новая длина из метаданных
Пока Выборка.Следующий() Цикл
ТекущийНомер = Выборка.Номер;
// Выделяем чистую числовую часть номера
ЧисловойНомер = Сред(ТекущийНомер, СтрДлина(СистематизированныйПрефикс) + 1);
// Формируем новый номер с лидирующими нулями
КоличествоНулей = ЦелеваяДлинаНомера - СтрДлина(СистематизированныйПрефикс) - СтрДлина(ЧисловойНомер);
НовыеНули = "";
Для Сч = 1 По КоличествоНулей Цикл
НовыеНули = НовыеНули + "0";
КонецЦикла;
НовыйНомер = СистематизированныйПрефикс + НовыеНули + ЧисловойНомер;
Если ТекущийНомер <> НовыйНомер Тогда
ОбъектДок = Выборка.ПолучитьОбъект();
ОбъектДок.Номер = НовыйНомер;
// Отключаем обмен и проверки при перезаписи старых периодов, если необходимо
ОбъектДок.ОбменДанными.Загрузка = Истина;
ОбъектДок.Записать(РежимЗаписиДокумента.Запись);
КонецЕсли;
КонецЦикла;
// Сбрасываем кэш номеров на сервере
ОбновитьНумерациюОбъектов(Метаданные.Документы.НетиповойОтчет);
Преимущества:
Недостатки:
Если пользователи не могут работать, а времени на написание обработок и согласование изменения конфигурации прямо сейчас нет, можно использовать интересную особенность сортировки строк в СУБД. Нам достаточно временно перешагнуть через чисто числовую нумерацию, вставив в номер букву.
Достаточно создать один документ и вручную присвоить ему номер вида ОТЧТа0001. Платформа распознает строку ОТЧТа как новый префикс, а последующие цифры 0001 — как числовую часть. Все последующие создаваемые документы будут автоматически получать номера ОТЧТа0002, ОТЧТа0003 и так далее.
Этот способ позволяет мгновенно продолжить выписку документов в критической ситуации и выиграть время для полноценного тестирования и подготовки плановых обновлений конфигурации на выходных.
Если вы работаете в конфигурации «Управление торговлей 10.3» (или других решениях на обычных формах), обратите внимание на следующий нюанс. При создании нетипового документа разработчики часто забывают включить его в состав источников стандартной подписки на событие установки нового номера (обычно она называется УстановитьНовыйНомерДокумента или аналогично).
Если документ не включен в эту подписку:
Поэтому при реализации изменений обязательно проверьте, чтобы ваш нетиповой документ был назначен источником в соответствующей подписке на событие ПриУстановкеНовогоНомера, а сам алгоритм назначения префиксов организации корректно отрабатывал при создании новых объектов.