В практике разработки на платформе 1С:Предприятие 8 часто возникают ситуации, которые кажутся необъяснимыми с точки зрения логики работы объектов. Одной из таких проблем является получение пустой ссылки (ПустаяСсылка) в обработчике подписки на событие ОбработкаПроведения, даже когда документ уже существует в базе и выполняется его перепроведение. На первый взгляд это кажется невозможным, так как проведение всегда следует за записью объекта. Разберем детально причины этого явления и методы диагностики.
Прежде всего, нам необходимо убедиться, что мы действительно находимся в нужном событии. В платформе 1С существует строгая последовательность записи и проведения документа. Рассмотрим стандартный цикл:
Записать с режимом Проведение.ПередЗаписью (в модуле объекта и в подписках). На этом этапе у нового документа ссылка еще действительно может быть пустой.ПриЗаписи.ОбработкаПроведения. На этом этапе ссылка обязана быть заполненной.Проанализируем ситуацию: если в отладчике проверка Источник.Ссылка.Пустая() возвращает Истина, первое, что нужно проверить — не перепутано ли событие в самой подписке в дереве метаданных. Часто разработчики по ошибке назначают один и тот же обработчик на ПередЗаписью и ОбработкаПроведения, что и создает иллюзию аномального поведения.
Одной из самых коварных особенностей платформы является способ передачи параметров в процедуры-обработчики. В 1С параметры в подписки передаются по ссылке. Это означает, что переменная Источник во всех подписках — это один и тот же указатель на объект в памяти.
Рассмотрим ситуацию, когда для одного и того же документа (например, ПоступлениеТоваровУслуг) создано несколько подписок на событие ОбработкаПроведения. Платформа вызывает их последовательно. Если в первой по порядку подписке разработчик допустит ошибку и переопределит саму переменную, это повлияет на все последующие вызовы.
Посмотрим на пример ошибочного кода в «соседней» подписке:
Процедура ОшибочныйОбработчикПодписки(Источник, Отказ, РежимПроведения) Экспорт
// Здесь разработчик решил переиспользовать переменную или совершил опечатку
Источник = Документы.ПоступлениеТоваровУслуг.ПустаяСсылка();
// Теперь во всех следующих подписках Источник будет пустой ссылкой!
КонецПроцедуры
Как мы видим, прямое присваивание значения переменной Источник «ломает» логику для всех остальных участников процесса. Выясним причину, почему это происходит: платформа не копирует объект для каждой подписки ради экономии ресурсов, поэтому любые манипуляции с указателем объекта становятся глобальными в рамках текущего стека вызовов.
Если вы столкнулись с пустой ссылкой, когда ее там быть не должно, проанализируем ситуацию с помощью отладчика. Остановившись в точке перелома (в вашем обработчике), откройте окно Стек вызовов (Call Stack). Это позволит увидеть:
ОбработкаПроведения вызван программно вручную.Рассмотрим вариант ручного вызова. Иногда в коде обработок можно встретить подобное:
НовыйДок = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();
// Объект еще не записан, ссылки нет
НовыйДок.ОбработкаПроведения(Отказ, РежимПроведения); // Прямой вызов обработчика
В этом случае подписки также сработают, но так как физической записи в БД не было, Источник.Ссылка будет пустой. Это является грубым нарушением стандартов разработки 1С.
Современные конфигурации часто используют расширения. Необходимо проверить, нет ли в расширениях аннотаций &Перед или &Вместо для метода ОбработкаПроведения или для самих процедур-обработчиков подписок.
Если в расширении используется аннотация &Вместо, и разработчик написал код следующим образом:
&Вместо("ОбработкаПроведения")
Процедура Расш_ОбработкаПроведения(Источник, Отказ, РежимПроведения)
// Если здесь не вызвать ПродолжитьВызов() или передать в него пустые параметры,
// логика основной конфигурации может быть нарушена.
ПродолжитьВызов(Неопределено, Отказ, РежимПроведения);
КонецПроцедуры
Такие манипуляции могут привести к тому, что контекст объекта будет потерян или подменен еще до того, как управление попадет в вашу подписку.
Для того чтобы ваши подписки были стабильными и не мешали работе других механизмов, придерживайтесь следующих правил:
СсылкаНаОбъект = Источник.Ссылка;.Источник. Если Источник.Ссылка пустая, но данные внутри (дата, номер, табличные части) заполнены — значит, объект находится в состоянии «перед записью» или его переменная была подменена.Подведем итог: «чудес» в 1С не бывает. Если в обработке проведения ссылка пуста, значит либо нарушен жизненный цикл объекта (ручной вызов), либо один из предшествующих обработчиков в цепочке подписок некорректно изменил значение параметра Источник, передаваемого по ссылке.