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

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

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

В чем заключается ошибка при использовании функции Формат()?

Рассмотрим исходный фрагмент кода, вызвавший затруднения:


Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
    Док = Результат.Ссылка.ПолучитьОбъект();
    НомерДок = СокрЛП(Док.Номер);
    
    НомерДок = Формат(НомерДок, "ЧЦ=11; ЧВН=; ЧГ=");
    
    Док.Номер = НомерДок;
    Док.Записать();
КонецЦикла;

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

Спецификаторы числового формата (такие как ЧЦ — число целых разрядов, ЧВН — выводить лидирующие нули, ЧГ= — отключение группировки разрядов) платформой 1С:Предприятие применяются исключительно к значениям числового типа. Если первым параметром в функцию Формат() передается значение строкового типа (а реквизит Номер в подавляющем большинстве конфигураций является строкой), платформа не генерирует исключительную ситуацию, а просто возвращает переданную строку в ее исходном виде без изменений.

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

Разберем корректные способы решения поставленной задачи.

Способ 1. Классическое дополнение строки нулями слева

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


Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
    Док = Результат.Ссылка.ПолучитьОбъект();
    НомерБезПробелов = СокрЛП(Док.Номер);
    
    // Дополняем строку слева нулями до 11 знаков
    Док.Номер = Прав("00000000000" + НомерБезПробелов, 11);
    
    Док.Записать();
КонецЦикла;

Этот метод безопасен, так как не вызывает ошибок выполнения даже в том случае, если номер документа содержит нечисловые символы или префиксы (например, "АА0000123").

Способ 2. Использование явного приведения типов при вызове функции Формат()

Если номер документа гарантированно состоит только из цифр и не содержит символьных префиксов, можно применить функцию Формат(), предварительно приведя значение к числу функцией Число():


Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
    Док = Результат.Ссылка.ПолучитьОбъект();
    НомерСтрокой = СокрЛП(Док.Номер);
    
    // Преобразуем строку в число и форматируем с лидирующими нулями
    ЧисловойНомер = Число(НомерСтрокой);
    Док.Номер = Формат(ЧисловойНомер, "ЧЦ=11; ЧВН=; ЧГ=0");
    
    Док.Записать();
КонецЦикла;

Важное предостережение: если в значении НомерСтрокой окажется хотя бы одна буква, пробел внутри строки, дефис или разделитель, вызов Число() вызовет аварийное завершение работы алгоритма с ошибкой «Преобразование значения к типу Число не может быть выполнено».

Способ 3. Использование стандартных библиотечных функций (БСП)

Если конфигурация разработана на базе Библиотеки Стандартных Подсистем (БСП), например «Управление автотранспортом», «ERP», «Комплексная автоматизация» или «Управление торговлей», в конфигурации доступен общий модуль СтроковыеФункцииКлиентСервер. Посмотрим на пример его вызова:


Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
    Док = Результат.Ссылка.ПолучитьОбъект();
    НомерБезПробелов = СокрЛП(Док.Номер);
    
    Док.Номер = СтроковыеФункцииКлиентСервер.ДополнитьСтроку(НомерБезПробелов, 11, "0", "Слева");
    
    Док.Записать();
КонецЦикла;

Если требуется корректно выделить числовой номер с сохранением префиксов узлов РИБ или организаций, рекомендуется задействовать процедуры и функции специализированного модуля БСП ПрефиксацияОбъектовКлиентСервер.

Важные нюансы при пакетной перенумерации документов

Разберем по шагам тонкости платформенных механизмов, о которых необходимо помнить при изменении номеров:

  1. Кэш автонумерации: После принудительного изменения номеров через код платформа удерживает в оперативной памяти последний присвоенный номер. При создании следующего документа вручную система может выдать сообщение о нарушении уникальности номера. Чтобы очистить платформенный счетчик, после завершения цикла перенумерации обязательно вызываем метод глобального контекста:
    ОбновитьНумерациюОбъектов(Метаданные.Документы.ИмяДокумента);
  2. Контроль уникальности номеров: Если у документа включен контроль уникальности, попытка записать объект с номером, который уже существует у другого документа в базе (в пределах установленной периодичности), приведет к ошибке. Если целевые номера пересекаются с существующими, перенумерацию выполняют в два этапа: сначала присваивают промежуточные технические номера (например, добавляя префикс "TMP_"), а вторым проходом выставляют финальные значения.
  3. Периодичность нумерации: Обратите внимание на свойство документа «Периодичность» в метаданных (в пределах года, месяца или дня). Запрос на выборку документов для перенумерации должен учитывать границы периода нумерации и сортироваться по дате.
  4. Общие нумераторы: Если документ связан со специальным объектом конфигурации — нумератором, изменение логики нумерации повлияет на все остальные виды документов, привязанные к этому нумератору.
← На главную