Почему в подписке на событие Обработка проведения Источник.Ссылка возвращает пустую ссылку?

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

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

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

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

  1. Вызов метода Записать с режимом Проведение.
  2. Событие ПередЗаписью (в модуле объекта и в подписках). На этом этапе у нового документа ссылка еще действительно может быть пустой.
  3. Запись объекта в базу данных и фиксация ссылки.
  4. Событие ПриЗаписи.
  5. Событие ОбработкаПроведения. На этом этапе ссылка обязана быть заполненной.

Проанализируем ситуацию: если в отладчике проверка Источник.Ссылка.Пустая() возвращает Истина, первое, что нужно проверить — не перепутано ли событие в самой подписке в дереве метаданных. Часто разработчики по ошибке назначают один и тот же обработчик на ПередЗаписью и ОбработкаПроведения, что и создает иллюзию аномального поведения.

Проблема передачи параметров по ссылке (ByRef)

Одной из самых коварных особенностей платформы является способ передачи параметров в процедуры-обработчики. В 1С параметры в подписки передаются по ссылке. Это означает, что переменная Источник во всех подписках — это один и тот же указатель на объект в памяти.

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

Посмотрим на пример ошибочного кода в «соседней» подписке:


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

Как мы видим, прямое присваивание значения переменной Источник «ломает» логику для всех остальных участников процесса. Выясним причину, почему это происходит: платформа не копирует объект для каждой подписки ради экономии ресурсов, поэтому любые манипуляции с указателем объекта становятся глобальными в рамках текущего стека вызовов.

Использование стека вызовов для диагностики

Если вы столкнулись с пустой ссылкой, когда ее там быть не должно, проанализируем ситуацию с помощью отладчика. Остановившись в точке перелома (в вашем обработчике), откройте окно Стек вызовов (Call Stack). Это позволит увидеть:

Рассмотрим вариант ручного вызова. Иногда в коде обработок можно встретить подобное:


НовыйДок = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();
// Объект еще не записан, ссылки нет
НовыйДок.ОбработкаПроведения(Отказ, РежимПроведения); // Прямой вызов обработчика

В этом случае подписки также сработают, но так как физической записи в БД не было, Источник.Ссылка будет пустой. Это является грубым нарушением стандартов разработки 1С.

Влияние расширений конфигурации

Современные конфигурации часто используют расширения. Необходимо проверить, нет ли в расширениях аннотаций &Перед или &Вместо для метода ОбработкаПроведения или для самих процедур-обработчиков подписок.

Если в расширении используется аннотация &Вместо, и разработчик написал код следующим образом:


&Вместо("ОбработкаПроведения")
Процедура Расш_ОбработкаПроведения(Источник, Отказ, РежимПроведения)
    // Если здесь не вызвать ПродолжитьВызов() или передать в него пустые параметры,
    // логика основной конфигурации может быть нарушена.
    ПродолжитьВызов(Неопределено, Отказ, РежимПроведения); 
КонецПроцедуры

Такие манипуляции могут привести к тому, что контекст объекта будет потерян или подменен еще до того, как управление попадет в вашу подписку.

Рекомендации по написанию безопасных обработчиков

Для того чтобы ваши подписки были стабильными и не мешали работе других механизмов, придерживайтесь следующих правил:

  1. Никогда не переопределяйте переменную Источник. Если вам нужно выполнить поиск или промежуточные расчеты, создайте локальную переменную, например СсылкаНаОбъект = Источник.Ссылка;.
  2. Проверяйте тип источника. В универсальных подписках, обрабатывающих разные типы документов, всегда делайте проверку типа в начале процедуры.
  3. Используйте отладчик правильно. Если значение кажется неверным, всегда проверяйте свойства самого объекта Источник. Если Источник.Ссылка пустая, но данные внутри (дата, номер, табличные части) заполнены — значит, объект находится в состоянии «перед записью» или его переменная была подменена.

Подведем итог: «чудес» в 1С не бывает. Если в обработке проведения ссылка пуста, значит либо нарушен жизненный цикл объекта (ручной вызов), либо один из предшествующих обработчиков в цепочке подписок некорректно изменил значение параметра Источник, передаваемого по ссылке.

← На главную