Как исправить автонумерацию в 1С, если документы перехватывают префиксы из обмена?

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

Каждый разработчик 1С рано или поздно сталкивается с загадочным поведением автонумерации. Типичный сценарий: в стабильно работающую базу (например, кастомную «1С:Управление производственным предприятием 1.3») начинают загружаться документы из другой базы (например, «1С:Зарплата и управление персоналом»). Документы из обмена приходят со своими префиксами, а документы, создаваемые пользователями вручную, префиксов иметь не должны. Однако в какой-то момент ручные документы внезапно «подхватывают» префикс документов обмена, и восстановить стандартную нумерацию простым переименованием последнего документа не получается.

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

---

Выясняем причину: почему платформа «подхватывает» чужой префикс?

Для начала проанализируем поведение платформы «1С:Предприятие 8». Процесс генерации нового номера скрыт от разработчика, так как он выполняется на уровне СУБД и внутреннего ядра платформы (на C++). С этим связана главная сложность отладки: если мы попытаемся отследить процесс по шагам, то увидим следующую картину:

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

Это происходит потому, что генерация номера физически выполняется в транзакции записи **после** того, как отработал код ПриУстановкеНовогоНомера, но **до** записи объекта в базу данных. Платформа берет переданный ей префикс и ищет в базе данных документ с максимальным номером, соответствующим этому префиксу.

Алгоритм поиска максимального номера платформой выглядит так:

  1. При создании ручного документа типовой код (например, процедура ДобавитьПрефиксОрганизации) не находит у организации префикса и устанавливает префикс по умолчанию — "0" (внутренний аналог отсутствия префикса).
  2. Из ЗУП прилетают документы с префиксом узла обмена (например, "ЗП"). При записи в УПП они получают префикс вида "0ЗП-".
  3. Платформа делает запрос к таблице документов, отбирая номера, которые начинаются на символ "0". Под этот критерий подходят как ручные цифровые номера (например, "00000000123"), так и номера из обмена (например, "0ЗП-0000001").
  4. Далее платформа выполняет посимвольное строковое сравнение (по кодам Unicode) для нахождения максимального значения. Так как код кириллического символа "З" значительно больше, чем код цифры "0", строка "0ЗП-0000001" признается **большей**, чем строка "00000000123".
  5. Платформа берет этот «максимальный» номер, отсекает его правую числовую часть, увеличивает ее на единицу и возвращает результат: "0ЗП-0000002". Автонумерация ручных документов оказывается «заражена».

Именно по этой причине вызов метода ОбновитьНумерациюОбъектов() не дает никаких результатов. С точки зрения платформы все работает корректно: она находит «наибольший» номер по маске и увеличивает его.

---

Решение проблемы: восстанавливаем правильную автонумерацию

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

Способ 1. Сужение пространства поиска до "00" (Рекомендуемый программный метод)

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

Проанализируем, как это сработает:

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


Процедура ПриУстановкеНовогоНомераДляДокументов(Источник, СтандартнаяОбработка, Префикс) Экспорт
    ДобавитьПрефиксОрганизации(Источник, Префикс);
    ДобавитьПрефиксУзла(Префикс);
    
    // Внедряем разделение нумерации для проблемного документа
    Если ТипЗнч(Источник) = Тип("ДокументОбъект.ЗарплатаКВыплатеОрганизаций") Тогда
        // Если префикс определился как "0" (нет префикса организации/узла)
        Если Префикс = "0" Тогда
            Префикс = "00";
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

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

---

Способ 2. Разделение нумерации по бизнес-логике (Через реквизиты документа)

В документах выплаты зарплаты часто присутствует реквизит, определяющий способ выдачи средств (например, через кассу или через банк). Ручные документы обычно создаются для выплаты через кассу, а документы из обмена предназначены для безналичных зачислений.

Мы можем использовать этот реквизит для разделения префиксов. Например, для кассовых документов будем принудительно устанавливать префикс "К", а банковские оставим без изменений.

Рассмотрим пример реализации такого разделения:


Процедура ПриУстановкеНовогоНомераДляДокументов(Источник, СтандартнаяОбработка, Preфикс) Экспорт
    ДобавитьПрефиксОрганизации(Источник, Префикс);
    ДобавитьПрефиксУзла(Префикс);
    
    Если ТипЗнч(Источник) = Тип("ДокументОбъект.ЗарплатаКВыплатеОрганизаций") Тогда
        // Если это выплата через кассу, присваиваем свой уникальный префикс
        Если Источник.СпособВыплаты = Перечисления.СпособыВыплатыЗарплаты.ЧерезКассу Тогда
            Префикс = "К"; // Номера станут вида К0000000001
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

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

---

Способ 3. Изменение префиксов в источнике данных (Административный метод)

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

  1. В базе ЗУП задайте уникальный префикс информационной базы (например, "ЗП").
  2. В базе УПП также задайте префикс базы (например, "УП").
  3. Все новые документы, создаваемые в УПП вручную, будут автоматически получать префикс "УП". Платформа будет искать максимальный номер только среди документов с префиксом "УП", полностью игнорируя документы с префиксом "ЗП".

Важно: этот способ применим только для будущих документов. Ранее созданные ручные документы без префикса придется переименовать, добавив к ним префикс "УП", чтобы платформа могла продолжить их последовательность.

---

Что необходимо сделать после изменения кода/префиксов?

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

  1. Найдите последний созданный ручной документ (который должен был продолжить правильную числовую нумерацию).
  2. Вручную исправьте его номер на правильный следующий по порядку. Например, если последний хороший номер был "00000000123", установите исправляемому документу номер "00000000124" (или "00-00000124" в зависимости от выбранного Способа 1).
  3. Запишите и проведите документ.
  4. Для того чтобы платформа мгновенно очистила свой внутренний кэш номеров в памяти сервера, выполните в консоли или внешней обработке команду обновления нумерации: ОбновитьНумерациюОбъектов(Метаданные.Документы.ЗарплатаКВыплатеОрганизаций);

После выполнения этих шагов создайте новый документ вручную и нажмите кнопку «Записать». Платформа автоматически присвоит ему корректный следующий номер (например, "00000000125"), и проблема с перехватом префиксов будет полностью устранена.

← На главную