В процессе разработки или доработки конфигураций 1С часто возникает задача программной генерации следующего номера документа. Казалось бы, задача проста: взять текущий номер, прибавить единицу и записать обратно. Однако, поскольку номер в 1С — это строка (например, У00000000011), при обычном преобразовании в число и обратно мы теряем и префикс, и ведущие нули, получая на выходе просто число 12. В этой статье мы подробно разберем, как корректно инкрементировать номер, сохраняя его структуру.
Рассмотрим ситуацию: у нас есть номер У00000000011. Если мы используем функцию Число(), платформа отсечет префикс и все ведущие нули. При обратном преобразовании Строка(11 + 1) результат будет "12". Нам же необходимо получить У00000000012. Для этого нужно отдельно обработать текстовый префикс и цифровую часть, обеспечив правильное форматирование последней.
Это наиболее надежный и быстрый способ управления внешним видом числа. Функция Формат() позволяет жестко задать количество знаков и заставить систему заполнять пустые разряды нулями. Проанализируем пример кода, который решает задачу наиболее лаконично:
// Предположим, ТекущийНомер = "У00000000011"
Префикс = "У";
ДлинаЧисловойЧасти = 11; // Общая длина числовой части после префикса
ТолькоЦифры = Число(Прав(ТекущийНомер, ДлинаЧисловойЧасти));
НовоеЧисло = ТолькоЦифры + 1;
// Формируем строку с ведущими нулями
// ЧЦ - общее количество цифр
// ЧВН - выводить ведущие нули
// ЧГ=0 - убирать группировку (пробелы между разрядами)
НовыйНомер = Префикс + Формат(НовоеЧисло, "ЧЦ=" + ДлинаЧисловойЧасти + "; ЧВН=; ЧГ=0");
Важный нюанс: Обратите внимание на параметр ЧГ=0. Если его не указать, 1С может вставить неразрывный пробел в качестве разделителя групп разрядов (например, "1 001"), что недопустимо в номере документа и приведет к ошибкам при записи или поиске.
Прежде чем писать сложный код по замене строк, проанализируем возможности самой платформы. У объектов (Документов, Справочников) существует встроенный метод УстановитьНовыйНомер(). Это "правильный" путь, так как система сама находит последний номер в базе и увеличивает его, соблюдая уникальность.
ДокОбъект = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
// Устанавливает номер с учетом заданного префикса
ДокОбъект.УстановитьНовыйНомер("У");
Однако, как отметили участники обсуждения, этот метод иногда может игнорировать префикс, если в базе уже есть номера, нарушающие логику (например, введенные вручную без префиксов). Если вы работаете в нетиповой конфигурации или создаете специфический механизм нумерации, ручной способ может оказаться предпочтительнее.
В некоторых случаях мы не знаем заранее длину префикса — он может быть как "У", так и "УУ" или "АБ-". Разберем алгоритм, который автоматически определяет, где заканчивается текст и начинается число:
ПоследнийНомер = "УУ0000000045";
Инд = 1;
ДлинаЧисловойЧасти = 0;
// Идем с конца строки, пока находим цифры
Пока Инд < СтрДлина(ПоследнийНомер) Цикл
Символ = Сред(ПоследнийНомер, СтрДлина(ПоследнийНомер) - Инд + 1, 1);
Если Найти("0123456789", Символ) = 0 Тогда
ДлинаЧисловойЧасти = Инд - 1;
Прервать;
КонецЕсли;
Инд = Инд + 1;
КонецЦикла;
ПрефиксЧасть = Лев(ПоследнийНомер, СтрДлина(ПоследнийНомер) - ДлинаЧисловойЧасти);
ЧислоЧасть = Число(Прав(ПоследнийНомер, ДлинаЧисловойЧасти)) + 1;
// Собираем обратно
НовыйНомер = ПрефиксЧасть + Формат(ЧислоЧасть, "ЧЦ=" + ДлинаЧисловойЧасти + "; ЧВН=; ЧГ=0");
Этот метод универсален: он сохранит любую текстовую часть, будь то префикс организации или подразделения, и корректно увеличит только цифры в конце строки.
Если нам нужно создать документ на основании другого и мы хотим гарантированно получить "самый большой" существующий номер в базе, чтобы инкрементировать его, используем запрос. Рассмотрим пример получения последней записи:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Реализация.Номер КАК Номер
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализация
|УПОРЯДОЧИТЬ ПО
| Номер УБЫВ";
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Если Выборка.Следующий() Тогда
// Здесь применяем логику инкремента из способов выше
ТекНомер = Выборка.Номер;
// ... обработка номера ...
КонецЕсли;
Внимание: При работе в многопользовательском режиме (когда несколько человек одновременно создают документы) такой запрос может выдать один и тот же номер двум пользователям. Чтобы избежать конфликтов уникальности, лучше доверять генерацию номера платформенному методу при записи или использовать механизмы блокировок.
Проанализируем основные "подводные камни", с которыми сталкиваются разработчики:
Строка(Число) по умолчанию добавляет разделитель групп разрядов. Если число 1000 превратится в "1 000", это сломает всю дальнейшую логику работы с кодом. Всегда используйте Формат(..., "ЧГ=0").СтрЗаменить(Строка, " ", "") его не удалит.Если вы работаете в современной базе (УТ 11, БП 3.0, ERP), мы рекомендуем не изобретать велосипед, а заглянуть в общий модуль ПрефиксацияОбъектовКлиентСервер. Там реализованы мощные инструменты для работы с номерами, которые учитывают префиксы организаций, префиксы информационных баз в РИБ и корректно разделяют их. Использование стандартов БСП (Библиотеки стандартных подсистем) сделает ваш код более устойчивым к обновлениям платформы.
Выясним причину, по которой ручная нумерация иногда считается плохим тоном. 1С хранит номера в индексированном поле. Как только пользователь "ломает" нумерацию (например, вводит номер 999 вместо 001), автонумерация начинает предлагать 1000. Если же ввести номер максимальной длины из букв, автонумерация может и вовсе остановиться. Поэтому, прежде чем программно увеличивать номер, убедитесь, что это действительно необходимо и нельзя обойтись стандартным функционалом УстановитьНовыйНомер().