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

Программист 1С v8.3 (Обычные формы) Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При программном создании документов в среде «1С:Предприятие» разработчики часто сталкиваются с неприятной проблемой: вместо ожидаемого продолжения цепочки номеров (например, создания документа с номером АД000124 после существующего АД000123) платформа генерирует начальный номер АД000001 или даже 00000001 без префикса. При этом интерактивное (ручное) создание документов в пользовательском интерфейсе продолжает работать абсолютно корректно.

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

1. Разбор логической ошибки в общем модуле (на примере БГУ)

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

{ОбщийМодуль.ОбщегоНазначения.Модуль(8602)}: Поле объекта не обнаружено (Организация)

Давайте проанализируем строку кода, на которой происходит сбой:


Если Не ОбщегоНазначения.ЕстьРеквизитДокумента("Учреждение", МетаданныеДокумента) 
   Или НЕ ЗначениеЗаполнено(ДокументОбъект.Организация.Префикс) Тогда
   // Логика обработки номера
КонецЕсли;

Почему происходит падение:

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

В нашем случае в конфигурации БГУ у документа присутствует реквизит Учреждение (вместо привычной для БП Организации). Функция ЕстьРеквизитДокумента("Учреждение", ...) возвращает значение Истина. Соответственно, левая часть выражения с оператором отрицания НЕ превращается в Ложь.

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

Как исправить этот баг в коде:

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


НужноПропустить = Истина;
Если ОбщегоНазначения.ЕстьРеквизитДокумента("Организация", МетаданныеДокумента) Тогда
    Если ЗначениеЗаполнено(ДокументОбъект.Организация.Префикс) Тогда
        НужноПропустить = Ложь;
    КонецЕсли;
ИначеЕсли ОбщегоНазначения.ЕстьРеквизитДокумента("Учреждение", МетаданныеДокумента) Тогда
    Если ЗначениеЗаполнено(ДокументОбъект.Учреждение.Префикс) Тогда
        НужноПропустить = Ложь;
    КонецЕсли;
КонецЕсли;

Если НужноПропустить Тогда
    // Альтернативная обработка
КонецЕсли;

2. Почему метод УстановитьНовыйНомер() сбрасывает префикс при записи?

Разработчики часто пытаются принудительно задать префикс перед записью документа программным путем:

НовыйДокумент.УстановитьНовыйНомер("АД");

Однако при вызове метода НовыйДокумент.Записать() номер все равно сбрасывается на 00000001. Выясним причину этого поведения.

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

Если при программном создании документа реквизит Организация или Учреждение остался незаполненным, подписка на событие определит префикс как пустую строку и принудительно перезапишет ранее назначенный вами префикс "АД". В результате платформа начнет нумерацию с чистого листа, выдав номер 00000001.

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

3. Проблема смешения кириллицы и латиницы в префиксах

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

Если в вашей базе ранее создавались документы с префиксом "AD" (где "A" — латинская), а программный код пытается применить префикс "АД" (где "А" — кириллическая), система посчитает, что это новая серия документов, и начнет нумерацию заново с 000001.

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


ВЫБРАТЬ
    КОДСИМВОЛА(ПОДСТРОКА(ОС_ВнутреннееПеремещение.Номер, 1, 1)) КАК КодПервогоСимвола,
    КОДСИМВОЛА(ПОДСТРОКА(ОС_ВнутреннееПеремещение.Номер, 2, 1)) КАК КодВторогоСимвола,
    ОС_ВнутреннееПеремещение.Номер,
    ОС_ВнутреннееПеремещение.Ссылка
ИЗ
    Документ.ОС_ВнутреннееПеремещение КАК ОС_ВнутреннееПеремещение
УПОРЯДОЧИТЬ ПО
    ОС_ВнутреннееПеремещение.Дата УБЫВ

Проанализируем результаты выполнения запроса:

  1. Если код первого символа равен 1040 — это русская буква «А» (кириллица).
  2. Если код первого символа равен 65 — это английская буква «A» (латиница).

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

4. Практические способы решения проблемы

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

Способ А. Использование стандартных процедур БСП

Вместо прямой записи номера используйте вызов стандартных функций общего назначения конфигурации, которые корректно учитывают все подписки и префиксы ИБ/Организаций. Например:


// Перед записью обязательно заполняем организационные реквизиты
НовыйДокумент.Учреждение = ВыбранноеУчреждение;

// Используем типовой механизм для установки префиксов и номеров
ОбщегоНазначения.УстановитьНомерДокумента(НовыйДокумент);
НовыйДокумент.Записать();

Способ Б. Ручной «толчок» механизма автонумерации

Если автонумератор платформы «зациклился» на некорректном диапазоне номеров, можно исправить ситуацию вручную:

  1. Создайте один документ программно или интерактивно, позволив ему записаться с неправильным номером (например, АД000001).
  2. Вручную измените его номер в форме документа на правильный следующий по порядку номер (например, АД000124) и сохраните документ.
  3. Последующие документы, создаваемые как интерактивно, так и программно, продолжат корректную цепочку нумерации (АД000125, АД000126 и так далее). Исправленный документ при необходимости можно удалить.

Способ В. Программный обход через вычисление максимального номера

Если стандартный механизм автонумерации заблокирован или работает некорректно из-за закрытого кода подписок, вы можете рассчитать следующий номер вручную с помощью несложного запроса перед вызовом метода Записать():


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ ПЕРВЫЕ 1
    |	ОС_ВнутреннееПеремещение.Номер КАК Номер
    |ИЗ
    |	Документ.ОС_ВнутреннееПеремещение КАК ОС_ВнутреннееПеремещение
    |ГДЕ
    |	ОС_ВнутреннееПеремещение.Номер ПОДОБНО &ШаблонНомера
    |
    |УПОРЯДОЧИТЬ ПО
    |	ОС_ВнутреннееПеремещение.Номер УБЫВ";

// Ищем существующие номера с нужным префиксом
Запрос.УстановитьПараметр("ШаблонНомера", "АД%");
РезультатЗапроса = Запрос.Выполнить();

Если Не РезультатЗапроса.Пустой() Тогда
    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующий();
    СтарыйНомер = Выборка.Номер;
    
    // Выделяем числовую часть, увеличиваем на 1 и форматируем обратно
    // Предполагаем длину номера 11 символов, префикс занимает 2 символа
    ЧисловойНомер = Число(Сред(СтарыйНомер, 3));
    НовыйЧисловойНомер = ЧисловойНомер + 1;
    
    НовыйДокумент.Номер = "АД" + Формат(НовыйЧисловойНомер, "ЧГ=0; ЧЦ=9; ЧВН=");
Иначе
    НовыйДокумент.Номер = "АД000000001";
КонецЕсли;

НовыйДокумент.Записать();

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

← На главную