В процессе сопровождения и доработки типовых конфигураций 1С (таких как УПП, Комплексная автоматизация, ERP или Бухгалтерия предприятия) разработчики часто сталкиваются с требованием заказчика или бухгалтерии: организовать сквозную единую нумерацию документов независимо от установленного префикса организации или подразделения. Нередко к этому добавляется требование выводить префиксы в конце номера (например, 00001АМЗ) или разделять номера подразделений через дробь в соответствии с требованиями налоговых органов.
Разберем детально, как устроен встроенный механизм автонумерации платформы 1С:Предприятие, почему нельзя просто добавить символы в конец номера и какими способами можно правильно решить эту задачу без нарушения производительности и целостности данных.
Проанализируем логику, по которой платформа 1С формирует следующий номер документа при вызове метода УстановитьНовыйНомер() или при интерактивном создании объекта:
АМЗ0001 и ОП0001), платформа воспринимает их как две абсолютно независимые последовательности. Сквозной инкремент между ними встроенными средствами невозможен.00001АМЗ), платформа не найдет числовой части справа, и автоматическая нумерация перестанет работать корректно — новые документы будут создаваться с одним и тем же номером или сбрасываться в начало.Выясним причину большинства подобных требований: чаще всего сквозная нумерация и специфический формат требуются для регламентированных печатных форм (счет-фактура, ТОРГ-12, УПД) согласно Постановлению Правительства РФ № 1137, тогда как внутри базы данных документу достаточно иметь уникальный системный идентификатор.
Рассмотрим реализацию через разделение: системный номер формируется стандартными средствами платформы (что гарантирует высокую скорость записи и отсутствие блокировок), а преобразование в нужный формат выполняется исключительно в момент формирования печатной формы или выгрузки в ЭДО.
Разберем пример функции преобразования номера для печатной формы:
Функция СформироватьНомерДляПечати(ИсходныйНомер, ПрефиксОрганизации = "", КодПодразделения = "") Экспорт
// 1. Очищаем номер от типовых лидирующих нулей и служебных префиксов
НомерБезПрефикса = СокрЛП(ИсходныйНомер);
Если Не ПустаяСтрока(ПрефиксОрганизации) И Найти(НомерБезПрефикса, ПрефиксОрганизации) = 1 Тогда
НомерБезПрефикса = Сред(НомерБезПрефикса, СтрДлина(ПрефиксОрганизации) + 1);
КонецЕсли;
// Удаляем ведущие нули
Пока Лев(НомерБезПрефикса, 1) = "0" И СтрДлина(НомерБезПрефикса) > 1 Цикл
НомерБезПрефикса = Сред(НомерБезПрефикса, 2);
КонецЦикла;
// 2. Формируем номер по требованию (например, перенос префикса в конец или добавление дроби)
Результат = НомерБезПрефикса;
Если Не ПустаяСтрока(КодПодразделения) Тогда
Результат = Результат + "/" + СокрЛП(КодПодразделения);
КонецЕсли;
Если Не ПустаяСтрока(ПрефиксОрганизации) Тогда
Результат = Результат + ПрефиксОрганизации;
КонецЕсли;
Возврат Результат;
КонецФункции
Такой подход исключает конфликты блокировок при одновременной работе десятков пользователей и оставляет типовой функционал конфигурации в рабочем состоянии.
Если задача заключается в обеспечении единой сквозной нумерации по организации в целом, а разделение нумерации происходило из-за заполненных префиксов в справочнике Подразделения, проанализируем типовые настройки:
Подразделения (или ПодразделенияОрганизаций).Префикс у подразделений, для которых не требуется отдельная независимая цепочка номеров.ПриУстановкеНовогоНомера проверим, чтобы в формировании префикса участвовал только префикс самой организации.После очистки префиксов подразделений платформа автоматически продолжит единую сквозную нумерацию документов в разрезе организации.
Если бизнес-логика строго требует хранения нестандартного сквозного номера непосредственно в реквизите Номер, реализовывать поиск максимального значения простым запросом к таблице документов категорически не рекомендуется. В многопользовательской среде это неизбежно приведет к возникновению дублей (состоянию гонки) и взаимоблокировкам.
Посмотрим, как правильно организовать генерацию сквозного номера с использованием служебного регистра сведений и управляемых блокировок:
НумерацияДокументов с измерениями Организация, ТипДокумента, ПериодНумерации (Год) и ресурсом ТекущийНомер (Число).ПередЗаписью документа в транзакции выполняем блокировку записи регистра, считываем значение, увеличиваем его на единицу и формируем строковый номер документа.Разберем пример кода генерации номера в модуле объекта:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ЭтоНовый() И ПустаяСтрока(ЭтотОбъект.Номер) Тогда
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.НумерацияДокументов");
ЭлементБлокировки.УстановитьЗначение("Организация", ЭтотОбъект.Организация);
ЭлементБлокировки.УстановитьЗначение("ТипДокумента", ЭтотОбъект.Метаданные().Имя);
ЭлементБлокировки.УстановитьЗначение("ПериодНумерации", НачалоГода(ЭтотОбъект.Дата));
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
МенеджерЗаписи = РегистрыСведений.НумерацияДокументов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Организация = ЭтотОбъект.Организация;
МенеджерЗаписи.ТипДокумента = ЭтотОбъект.Метаданные().Имя;
МенеджерЗаписи.ПериодНумерации = НачалоГода(ЭтотОбъект.Дата);
МенеджерЗаписи.Прочитать();
НовоеЗначение = ?(МенеджерЗаписи.Выбран(), МенеджерЗаписи.ТекущийНомер + 1, 1);
МенеджерЗаписи.Организация = ЭтотОбъект.Организация;
МенеджерЗаписи.ТипДокумента = ЭтотОбъект.Метаданные().Имя;
МенеджерЗаписи.ПериодНумерации = НачалоГода(ЭтотОбъект.Дата);
МенеджерЗаписи.ТекущийНомер = НовоеЗначение;
МенеджерЗаписи.Записать();
// Форматируем номер нужной длины и добавляем суффикс
ЭтотОбъект.Номер = Формат(НовоеЗначение, "ЧЦ=8; ЧВН=; ЧГ=0") + СокрЛП(ЭтотОбъект.Организация.Префикс);
КонецЕсли;
КонецПроцедуры
Данный подход гарантирует уникальность номеров в параллельном режиме работы и исключает падение производительности всей системы.