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

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

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

Почему функция СтрЗаменить дает некорректный результат?

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

НовыйНомерДока = СтрЗаменить(Док.Номер, Лев(Док.Номер, 3), НовыйПрефикс);

Функция СтрЗаменить производит поиск и замену всех вхождений переданного образца во всей строке, а не только в ее начале. Если у документа был номер 000000001, выражение Лев(Док.Номер, 3) возвращает подстроку "000". Поскольку эта подстрока встречается в номере три раза подряд (000-000-000-1), функция заменяет каждое такое вхождение на новый префикс. В итоге номер превращается в БУХБУХБУХ1.

Кроме того, при обходе таблицы значений циклом Для каждого Стр Из Выборка Цикл нельзя удалять строки методом Выборка.Удалить(Стр) прямо внутри итератора — это приводит к сдвигу индексов коллекции и пропуску строк.

Корректная замена префикса с помощью строковых функций

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


ДлинаПрефикса = СтрДлина(НовыйПрефикс);
НовыйНомерДока = НовыйПрефикс + Сред(Док.Номер, ДлинаПрефикса + 1);

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

Нюансы использования метода УстановитьНовыйНомер()

Платформа 1С предоставляет встроенный метод УстановитьНовыйНомер(<ПрефиксНомера>). Однако при его прямом вызове на существующих документах следует учитывать важные особенности:

  1. Пересчет числовой части: метод не просто меняет префикс у текущего номера, а генерирует следующий порядковый номер для указанного префикса в пределах установленного периода нумерации.
  2. Подписки на события: в типовых конфигурациях при вызове этого метода срабатывают подписки на события (например, ПриУстановкеНовогоНомераДокумента). Стандартные модули префиксации автоматически конкатенируют префикс узла информационной базы, префикс организации и переданный пользовательский префикс, что может исказить итоговый номер (например, получится БУХККК001 вместо ККК000001).

Оптимальный алгоритм групповой перенумерации

Для корректного и безопасного обновления номеров документов без срабатывания тяжелых проверок бизнес-логики и подписок на события рекомендуется использовать установку флага ОбменДанными.Загрузка = Истина. Рассмотрим готовый пример процедуры:


Процедура ЗаменитьПрефиксыВДокументах(СтарыйПрефикс, НовыйПрефикс)
    
    ДлинаПрефикса = СтрДлина(СтарыйПрефикс);
    
    Для Каждого МетаДокумент Из Метаданные.Документы Цикл
        
        // Проверяем, есть ли у документа номер и строковый ли он
        Если МетаДокумент.ДлинаНомера = 0 Или МетаДокумент.ТипНомера <> Метаданные.СвойстваОбъектов.ТипНомераДокумента.Строка Тогда
            Продолжить;
        КонецЕсли;
        
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ
            |   Док.Ссылка КАК Ссылка,
            |   Док.Номер КАК Номер
            |ИЗ
            |   Документ." + МетаДокумент.Имя + " КАК Док
            |ГДЕ
            |   Док.Номер ПОДОБНО &ШаблонПрефикса";
        
        Запрос.УстановитьПараметр("ШаблонПрефикса", СтарыйПрефикс + "%");
        Выборка = Запрос.Выполнить().Выбрать();
        
        Пока Выборка.Следующий() Цикл
            ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
            
            // Формируем новый номер с сохранением числовой части
            ЧисловаяЧасть = Сред(ДокОбъект.Номер, ДлинаПрефикса + 1);
            ДокОбъект.Номер = НовыйПрефикс + ЧисловаяЧасть;
            
            // Отключаем обработчики бизнес-логики при записи
            ДокОбъект.ОбменДанными.Загрузка = Истина;
            
            Попытка
                // Сохраняем текущий режим записи (проведен/не проведен)
                Если ДокОбъект.Проведен Тогда
                    ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
                Иначе
                    ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
                КонецЕсли;
            Исключение
                Сообщить("Ошибка записи документа " + Строка(Выборка.Ссылка) + ": " + ОписаниеОшибки());
            КонецПопытки;
        КонецЦикла;
        
        // Сбрасываем кэш счетчиков нумерации для текущего вида документа
        ОбновитьНумерациюОбъектов(МетаДокумент);
        
    КонецЦикла;
    
    Сообщить("Замена префиксов успешно завершена!");
    
КонецПроцедуры

Актуализация счетчиков автонумерации

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

← На главную