Почему при изменении организации в документе срабатывает подписка ПриУстановкеНовогоНомера, а при изменении других реквизитов нет?

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

При разработке и кастомизации конфигураций на платформе 1С:Предприятие 8.3 (особенно на базе БСП, таких как ERP, КА, УТ или БП) разработчики часто сталкиваются с интересным поведением системы: если в уже сохраненном документе изменить реквизит Организация (или дату), то при записи система автоматически генерирует для него новый номер. При этом срабатывает подписка на событие ПриУстановкеНовогоНомера. Однако, если изменить любой другой реквизит (например, контрагента, склад, сумму или договор), номер остается прежним, и подписка не вызывается.

Давайте подробно разберем, как устроен этот механизм "под капотом" платформы и БСП, почему это происходит и какие именно программные механизмы задействованы в данном процессе.

Стандартное поведение платформы 1С

Для начала вспомним, как сама платформа 1С работает с событием ПриУстановкеНовогоНомера. Согласно системной логике, это событие инициируется платформой только в двух случаях:

  1. Когда создается новый объект и для него впервые вызывается автонумерация (при записи или при явном вызове метода УстановитьНовыйНомер()).
  2. Когда у существующего (ранее записанного) объекта программно очищают номер (присваивают ему пустую строку) перед записью, и платформа определяет, что объекту с включенной автонумерацией требуется назначить новый номер.

Платформа сама по себе ничего "не знает" о реквизитах прикладных справочников, таких как Организации, и не может самостоятельно отслеживать их изменение для перезапуска нумерации. Следовательно, вся магия происходит на уровне прикладного кода конфигурации — а именно, в стандартных подписках на события БСП (Библиотеки стандартных подсистем) из подсистемы "Префиксация объектов".

Связка двух подписок БСП: пошаговый алгоритм

В типовых конфигурациях за нумерацию документов с учетом организации отвечает связка из двух подписок на события:

  1. Подписка на событие ПередЗаписью (например, подписка ПроверитьНомерДокументаПоДатеИОрганизации).
  2. Подписка на событие ПриУстановкеНовогоНомера (например, подписка УстановитьПрефиксИнформационнойБазыИОрганизацииНомеруДокумента).

Давайте проанализируем по шагам, что происходит, когда пользователь меняет организацию в документе и нажимает кнопку "Записать".

Шаг 1. Срабатывание подписки "ПередЗаписью"

При вызове записи документа управление сначала передается в обработчик подписки ПередЗаписью. В общем модуле ПрефиксацияОбъектовСобытия срабатывает процедура, которая проверяет, изменились ли ключевые реквизиты, влияющие на префикс номера.

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


Процедура ПроверитьНомерДокументаПоДатеИОрганизации(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
    
    Если Источник.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    // Проверяем, изменились ли ключевые реквизиты: Организация или Дата
    Если ПрефиксацияОбъектовСлужебный.ДатаИлиОрганизацияОбъектаИзменена(Источник) Тогда
        // Ключевое действие: очистка номера!
        Источник.Номер = ""; 
    КонецЕсли;
    
КонецПроцедуры

Шаг 2. Как БСП понимает, что организация изменилась?

Внутри функции ДатаИлиОрганизацияОбъектаИзменена() система выполняет запрос к базе данных. Она считывает старые значения реквизитов Дата и Организация непосредственно из СУБД по ссылке текущего документа и сравнивает их с новыми значениями, которые находятся в свойствах записываемого объекта Источник.

Рассмотрим упрощенный пример того, как выполняется это сравнение:


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

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

Шаг 3. Сброс номера и вызов "ПриУстановкеНовогоНомера"

Если в результате сравнения выясняется, что префикс организации изменился (или дата документа переместилась в другой период нумерации, например, другой год), то в обработчике ПередЗаписью происходит принудительное обнуление номера: Источник.Номер = "".

После завершения всех процедур события ПередЗаписью платформа 1С приступает к непосредственной записи объекта в базу данных. В этот момент платформа обнаруживает, что:

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

В этот момент срабатывает вторая подписка БСП (например, УстановитьПрефиксИнформационнойБазыИОрганизацииНомеруДокумента). Она перехватывает управление, определяет новый префикс информационной базы и новой организации, формирует результирующий префикс (например, ОР00-) и передает его платформе. Платформа генерирует очередной свободный номер в базе данных с учетом этого префикса.

Почему при изменении других реквизитов автонумерация не срабатывает?

Теперь мы можем легко ответить на этот вопрос. Если пользователь меняет в документе любой другой реквизит (например, Контрагент или Склад), то:

  1. Подписка ПередЗаписью по-прежнему запускается.
  2. Функция проверки изменений анализирует дату и префикс организации. Поскольку они остались прежними, функция возвращает Ложь.
  3. Строка кода Источник.Номер = "" не выполняется. Номер документа остается заполненным (тем, который и был сохранен ранее).
  4. Поскольку на момент записи номер документа не является пустым, платформа 1С не видит необходимости генерировать новый номер. Соответственно, событие ПриУстановкеНовогоНомера просто не вызывается.

Важные нюансы и особенности работы механизма

При работе с этим механизмом в реальных проектах внедрения или кастомизации ERP/КА следует учитывать несколько важных особенностей:

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

← На главную