Как зарегистрировать объект к выгрузке обратно в узел-источник в момент его загрузки в 1С

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

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

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

Выясним причину: почему обычная регистрация не работает

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

  1. В момент загрузки сообщения обмена в контексте текущего сеанса устанавливается так называемый Узел-отправитель.
  2. При записи объекта, если в коде или подписках на события вызывается метод ПланыОбмена.ЗарегистрироватьИзменения(), платформа проверяет: не является ли узел, на который мы хотим зарегистрировать объект, тем самым узлом, из которого этот объект сейчас загружается.
  3. Если узел совпадает, платформа игнорирует регистрацию. Это сделано для того, чтобы база не отправляла назад ровно те же данные, которые она только что получила, предотвращая бесконечный обмен.

Рассмотрим ситуацию автора темы: код в подписке выполняется, ошибок нет, но в таблице регистрации изменений (которую можно посмотреть через «Монитор обмена» или программно) запись так и не появляется. Это классический признак работы фильтра узла-отправителя.

Решение №1: Очистка узла-отправителя

Самый прямой способ заставить платформу зарегистрировать изменения — это временно «заставить её забыть», откуда пришел объект. Для этого используется метод ПланыОбмена.УстановитьУзелОтправителя(). Разберем по шагам, как это реализовать в коде подписки на событие ПриЗаписи или ПередЗаписью.

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


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

Важно помнить: очистка узла-отправителя должна происходить внутри транзакции записи, но до её завершения. Метод ПолучитьУзелОтправителя() вернет ссылку на узел только в том случае, если запись инициирована механизмом обмена данными.

Решение №2: Использование коллекции «Получатели»

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

Проанализируем этот подход. Основная сложность здесь заключается в том, что при установленном флаге ОбменДанными.Загрузка = Истина платформа может очищать список получателей. Однако, если мы комбинируем этот метод с очисткой узла-отправителя, результат будет более стабильным.


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

Особенности работы при проведении документа

В тексте обсуждения упоминается, что обработчик срабатывает дважды: один раз с Загрузка = Истина, второй раз с Загрузка = Ложь. Это происходит в тех случаях, когда в правилах обмена (например, в КД 2.0) стоит галочка "Проводить после загрузки".

Разберем ситуацию:

  1. Первая запись: Срабатывает метод Объект.Записать(). Флаг Загрузка равен Истина. В этот момент данные из файла попадают в базу. Это лучший момент для программной регистрации изменений.
  2. Вторая запись (Проведение): Срабатывает Объект.Записать(РежимЗаписиДокумента.Проведение). В зависимости от настроек обмена, флаг Загрузка может быть сброшен в Ложь. Если в этот момент сработает ваша обычная подписка на регистрацию (которая работает для всех документов, создаваемых вручную), регистрация может произойти "сама собой", но уже без привязки к контексту обмена.

Важный совет: всегда делайте проверку на изменение статуса. Не регистрируйте объект просто потому, что у него "Статус 2". Проверяйте, что в базе до этого момента был "Статус 1". Это защитит вас от бесконечной пересылки документа туда-обратно при каждом сеансе связи.

Риски и предостережения

Принудительная регистрация изменений при загрузке — это мощный инструмент, но он требует осторожности. Рассмотрим основные риски:

Бесконечный цикл (Эхо): Если база №1 отправила объект, база №2 его приняла, изменила статус и отправила назад, то база №1 снова его примет. Если в базе №1 также стоит логика "зарегистрировать при загрузке", объект будет бесконечно летать между базами, нагружая каналы связи и сервер.

Производительность: Очистка и установка узла-отправителя в цикле при загрузке тысяч документов может незначительно замедлить процесс, однако это все равно быстрее, чем повторный перебор документов отдельной обработкой после завершения обмена.

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

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

← На главную