При программном создании документов в среде «1С:Предприятие» разработчики часто сталкиваются с неприятной проблемой: вместо ожидаемого продолжения цепочки номеров (например, создания документа с номером АД000124 после существующего АД000123) платформа генерирует начальный номер АД000001 или даже 00000001 без префикса. При этом интерактивное (ручное) создание документов в пользовательском интерфейсе продолжает работать абсолютно корректно.
В этой статье мы подробно разберем, почему автонумерация ведет себя подобным образом при программном вызове, проанализируем внутренние механизмы платформы и типовых конфигураций, а также рассмотрим пошаговые методы устранения этой неисправности.
Очень часто сбои при программном назначении номеров сопровождаются падением системы с системной ошибкой. Рассмотрим классический баг, который встречается при переносе механизмов нумерации между конфигурациями «Бухгалтерия предприятия» (БП) и «Бухгалтерия государственного учреждения» (БГУ). На этапе записи нового документа система может выдать следующую ошибку:
{ОбщийМодуль.ОбщегоНазначения.Модуль(8602)}: Поле объекта не обнаружено (Организация)
Давайте проанализируем строку кода, на которой происходит сбой:
Если Не ОбщегоНазначения.ЕстьРеквизитДокумента("Учреждение", МетаданныеДокумента)
Или НЕ ЗначениеЗаполнено(ДокументОбъект.Организация.Префикс) Тогда
// Логика обработки номера
КонецЕсли;
Почему происходит падение:
В платформе 1С применяется оптимизированная (сокращенная) оценка логических выражений. Если при вычислении оператора ИЛИ левая часть возвращает значение Истина, то правая часть даже не вычисляется, так как результат всего выражения уже гарантированно будет истинным.
В нашем случае в конфигурации БГУ у документа присутствует реквизит Учреждение (вместо привычной для БП Организации). Функция ЕстьРеквизитДокумента("Учреждение", ...) возвращает значение Истина. Соответственно, левая часть выражения с оператором отрицания НЕ превращается в Ложь.
Так как левая часть равна Ложь, платформа вынуждена вычислить правую часть, чтобы определить конечный результат операции ИЛИ. В этот момент происходит обращение к свойству ДокументОбъект.Организация.Префикс. Но поскольку у данного документа нет реквизита Организация (вместо него используется Учреждение), система аварийно завершает работу.
Как исправить этот баг в коде:
Если ваша конфигурация находится на поддержке с возможностью изменения, перепишите данное условие так, чтобы проверка наличия реквизита и обращение к нему были разделены на независимые блоки:
НужноПропустить = Истина;
Если ОбщегоНазначения.ЕстьРеквизитДокумента("Организация", МетаданныеДокумента) Тогда
Если ЗначениеЗаполнено(ДокументОбъект.Организация.Префикс) Тогда
НужноПропустить = Ложь;
КонецЕсли;
ИначеЕсли ОбщегоНазначения.ЕстьРеквизитДокумента("Учреждение", МетаданныеДокумента) Тогда
Если ЗначениеЗаполнено(ДокументОбъект.Учреждение.Префикс) Тогда
НужноПропустить = Ложь;
КонецЕсли;
КонецЕсли;
Если НужноПропустить Тогда
// Альтернативная обработка
КонецЕсли;
УстановитьНовыйНомер() сбрасывает префикс при записи?Разработчики часто пытаются принудительно задать префикс перед записью документа программным путем:
НовыйДокумент.УстановитьНовыйНомер("АД");
Однако при вызове метода НовыйДокумент.Записать() номер все равно сбрасывается на 00000001. Выясним причину этого поведения.
При вызове метода Записать() в платформе инициируется транзакция записи. На этом этапе срабатывают глобальные подписки на события, такие как ПриУстановкеНовогоНомераДокумента. Стандартный механизм префиксации, встроенный в современные конфигурации (БСП), перехватывает управление и пытается заново вычислить префикс документа на основе заполненных реквизитов (например, префикса организации или префикса информационной базы).
Если при программном создании документа реквизит Организация или Учреждение остался незаполненным, подписка на событие определит префикс как пустую строку и принудительно перезапишет ранее назначенный вами префикс "АД". В результате платформа начнет нумерацию с чистого листа, выдав номер 00000001.
Решение: Перед записью документа всегда проверяйте, заполнены ли реквизиты, отвечающие за префиксацию (Организация, Учреждение, Подразделение), и только после этого вызывайте методы работы с номером.
Одной из наиболее скрытных причин нарушения сквозной автонумерации является визуальное совпадение букв русского и английского алфавитов. Например, русская буква "А" выглядит абсолютно идентично английской букве "A", но для платформы «1С:Предприятие» это два совершенно разных символа с разными цифровыми кодами.
Если в вашей базе ранее создавались документы с префиксом "AD" (где "A" — латинская), а программный код пытается применить префикс "АД" (где "А" — кириллическая), система посчитает, что это новая серия документов, и начнет нумерацию заново с 000001.
Чтобы гарантированно проверить коды символов в префиксах уже существующих документов, мы рекомендуем воспользоваться встроенной консолью запросов и выполнить следующий запрос:
ВЫБРАТЬ
КОДСИМВОЛА(ПОДСТРОКА(ОС_ВнутреннееПеремещение.Номер, 1, 1)) КАК КодПервогоСимвола,
КОДСИМВОЛА(ПОДСТРОКА(ОС_ВнутреннееПеремещение.Номер, 2, 1)) КАК КодВторогоСимвола,
ОС_ВнутреннееПеремещение.Номер,
ОС_ВнутреннееПеремещение.Ссылка
ИЗ
Документ.ОС_ВнутреннееПеремещение КАК ОС_ВнутреннееПеремещение
УПОРЯДОЧИТЬ ПО
ОС_ВнутреннееПеремещение.Дата УБЫВ
Проанализируем результаты выполнения запроса:
Обнаружив расхождение, приведите префиксы в коде или в справочнике организаций к единому алфавитному стандарту.
Для восстановления правильной нумерации программно создаваемых документов можно применить один из следующих подходов в зависимости от степени кастомизации вашей базы данных.
Вместо прямой записи номера используйте вызов стандартных функций общего назначения конфигурации, которые корректно учитывают все подписки и префиксы ИБ/Организаций. Например:
// Перед записью обязательно заполняем организационные реквизиты
НовыйДокумент.Учреждение = ВыбранноеУчреждение;
// Используем типовой механизм для установки префиксов и номеров
ОбщегоНазначения.УстановитьНомерДокумента(НовыйДокумент);
НовыйДокумент.Записать();
Если автонумератор платформы «зациклился» на некорректном диапазоне номеров, можно исправить ситуацию вручную:
АД000001).АД000124) и сохраните документ.АД000125, АД000126 и так далее). Исправленный документ при необходимости можно удалить.Если стандартный механизм автонумерации заблокирован или работает некорректно из-за закрытого кода подписок, вы можете рассчитать следующий номер вручную с помощью несложного запроса перед вызовом метода Записать():
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ОС_ВнутреннееПеремещение.Номер КАК Номер
|ИЗ
| Документ.ОС_ВнутреннееПеремещение КАК ОС_ВнутреннееПеремещение
|ГДЕ
| ОС_ВнутреннееПеремещение.Номер ПОДОБНО &ШаблонНомера
|
|УПОРЯДОЧИТЬ ПО
| ОС_ВнутреннееПеремещение.Номер УБЫВ";
// Ищем существующие номера с нужным префиксом
Запрос.УстановитьПараметр("ШаблонНомера", "АД%");
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
СтарыйНомер = Выборка.Номер;
// Выделяем числовую часть, увеличиваем на 1 и форматируем обратно
// Предполагаем длину номера 11 символов, префикс занимает 2 символа
ЧисловойНомер = Число(Сред(СтарыйНомер, 3));
НовыйЧисловойНомер = ЧисловойНомер + 1;
НовыйДокумент.Номер = "АД" + Формат(НовыйЧисловойНомер, "ЧГ=0; ЧЦ=9; ЧВН=");
Иначе
НовыйДокумент.Номер = "АД000000001";
КонецЕсли;
НовыйДокумент.Записать();
Используя предложенные методы анализа префиксов и логики общих модулей, вы легко вернете автонумерацию документов в стабильное рабочее состояние.