Как разделить нумерацию документов, созданных на основании, и независимых документов в 1С?

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

При автоматизации документооборота часто возникает задача: формировать номер документа, созданного на основании, в виде составного индекса (например, НомерОснования/01, НомерОснования/02), а для документов, вводимых вручную без основания, сохранять собственную независимую нумерацию. Однако стандартный механизм автонумерации платформы 1С при появлении дроби начинает воспринимать всю левую часть как префикс и сбивает сквозную нумерацию обычных документов. Выясним причину такого поведения и разберем правильные способы решения этой задачи.

Почему сбивается стандартная нумерация платформы

Проанализируем работу встроенного механизма автонумерации 1С. Платформа парсит строковый реквизит Номер справа налево. Цифры в конце строки считаются инкрементируемым счетчиком, а вся предшествующая часть (включая буквы, разделители /, - и номер документа-основания) расценивается платформой как префикс номера. Когда в базу записывается документ с номером вида 123456/01, платформа запоминает шаблон 123456/ и при создании следующего документа (даже без основания) пытается продолжить именно эту последовательность, выдавая 123456/02.

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

Способ 1. Использование параметра Префикс в событии ПриУстановкеНовогоНомера (рекомендуемый)

Самый надежный и платформенный способ — делегировать автоинкремент самой платформе 1С через предопределенный обработчик ПриУстановкеНовогоНомера в модуле объекта документа. Платформа умеет вести раздельные счетчики для разных префиксов.

Разберем по шагам, как это реализовать:

  1. Открываем модуль объекта нужного документа.
  2. Находим или создаем обработчик события ПриУстановкеНовогоНомера.
  3. Если реквизит ДокументОснование заполнен, передаем в параметр Префикс номер основания со знаком дроби.
  4. Если документ создается без основания, передаем стандартный префикс (или оставляем его пустым).

Посмотрим на пример кода:


Процедура ПриУстановкеНовогоНомера(СтандартнаяОбработка, Префикс)
    
    Если ЗначениеЗаполнено(ДокументОснование) Тогда
        // Формируем префикс на основе номера родительского документа
        Префикс = СокрЛП(ДокументОснование.Номер) + "/";
    Иначе
        // Для независимых документов используем отдельный префикс или префикс по умолчанию
        Префикс = "000000/"; // Либо стандартный префикс организации/узла
    КонецЕсли;
    
КонецПроцедуры

При таком подходе платформа самостоятельно выделит отдельную числовую последовательность под каждый номер основания (123456/01, 123456/02) и отдельную последовательность для независимых документов (000000/01, 000000/02), не требуя ручного вычисления максимального номера через запросы.

Способ 2. Отключение стандартной автонумерации и программное вычисление номера

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

Рассмотрим реализацию в модуле объекта:


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

Важно: При программном формировании номеров запросом обязательно используйте объект БлокировкаДанных с режимом РежимБлокировкиДанных.Исключительный. Без транзакционной блокировки два пользователя, одновременно создающие подчиненный документ на одно основание, получат одинаковый максимальный номер, что приведет к ошибке нарушения уникальности при записи.

Способ 3. Разделение системного номера и пользовательского представления

В архитектурно сложных конфигурациях часто разделяют системную автонумерацию и отображение номера для пользователей. Это позволяет избежать проблем с длиной реквизитов и сбоями платформенных нумераторов.

Рассмотрим альтернативную схему:

  1. Стандартный реквизит Номер оставляем числовым со стандартной сквозной автонумерацией платформы без знаков /.
  2. Добавляем в документ числовой реквизит ИндексРедакции или НомерВерсии.
  3. В печатных формах и в интерфейсе динамически выводим представление номера с помощью конкатенации: ДокументОснование.Номер + "/" + Формат(НомерВерсии, "ЧЦ=2; ЧВН=").

Технические ограничения и возможные проблемы

При реализации нестандартной нумерации необходимо учитывать следующие нюансы платформы 1С:

  1. Длина реквизита «Номер»: Проверьте длину номера в свойствах метаданных документа. При склеивании номера основания, разделителя и порядкового индекса (например, ТД-00001234/01) суммарная длина строки может превысить ограничение метаданных, что вызовет обрезку хвоста номера или ошибку записи.
  2. Кэш автонумерации: Платформа кэширует диапазоны номеров в памяти сервера. Если нумерация сбилась из-за ручного ввода номеров со слэшем, используйте метод ОбновитьНумерациюОбъектов(Метаданные.Документы.ВнутреннийДокумент) для принудительного сброса кэша и восстановления правильного порядка.
← На главную