Как правильно организовать удаление регистрации изменений при обмене данными и почему не выгружаются связанные объекты?

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

При разработке собственных механизмов обмена данными на базе КД2 (Конвертации данных 2.0) и Планов обмена часто возникает задача гарантированной доставки данных. Нам необходимо удалять регистрацию изменений (признак того, что объект нужно выгрузить) только в том случае, если база-приемник успешно получила и сохранила эти данные. Просто удалять регистрацию сразу после формирования файла выгрузки — плохая практика, так как при потере файла или ошибке загрузки изменения будут утрачены навсегда. В некоторых случаях для обеспечения безопасности данных может потребоваться универсальная выгрузка с возможностью шифрования.

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

Механизм квитирования сообщений обмена

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

Суть метода заключается в "рукопожатии" между двумя базами:

  1. База-источник отправляет пакет данных с присвоенным Номером сообщения (например, №10).
  2. База-приемник получает пакет, загружает данные и запоминает, что успешно приняла сообщение №10.
  3. База-приемник при следующей выгрузке (или в специальном служебном сообщении) отправляет обратно информацию: "Я успешно приняла сообщение №10". Это поле называется НомерПринятого (ReceivedNo).
  4. База-источник получает ответ, видит, что №10 принят успешно, и автоматически (или вручную) удаляет регистрацию всех изменений, которые были отправлены в сообщениях с номером 10 и меньше.

Реализация удаления регистрации через код

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

Вариант 1. Удаление конкретных объектов (не рекомендуется для основного обмена)

Если мы передадим в метод ссылку на конкретный объект, регистрация снимется безусловно.


// Узел - ссылка на узел плана обмена
// Данные - ссылка на объект или массив ссылок
ПланыОбмена.УдалитьРегистрациюИзменений(Узел, Данные);

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

Вариант 2. Удаление по номеру сообщения (Правильный способ)

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


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

Давайте посмотрим, как это работает на практике при чтении ответного файла. Если вы используете стандартные механизмы, вам может быть полезна выгрузка и загрузка данных XML с дополнительными опциями, которая расширяет возможности типовых инструментов — решить задачу поможет выгрузка XML с переносом связанных объектов.

Пример алгоритма обработки ответа от приемника:


ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ПутьКФайлуОтвета);

ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);

// В этот момент платформа считывает заголовок файла.
// Если в файле указано поле ReceivedNo (НомерПринятого), 
// платформа АВТОМАТИЧЕСКИ удаляет регистрацию изменений 
// для этого узла по указанный номер включительно.

// Далее читаем данные, если они есть
Пока ВозможностьЧтенияДанных(ЧтениеXML) Цикл
    // Чтение данных...
КонецЦикла;

ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();

Таким образом, если вы правильно формируете ответный файл в базе-приемнике, указывая номер принятого сообщения, то в базе-источнике при чтении этого файла регистрация очистится сама. В архитектурах с шиной данных интересным решением является использование RabbitMQ и КД2 для передачи объектов по одному.

Как сформировать ответную квитанцию?

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


ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКФайлуКвитанции);

ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
УзелПланаОбмена = ПланыОбмена.НашПлан.НайтиПоКоду("КодУзлаИсточника");

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

// Явное указание номера принятого сообщения (если мы знаем его)
// Обычно берется из УзелПланаОбмена.НомерПринятого, который обновляется
// при успешном чтении входящего файла.
ЗаписьСообщения.НомерПринятого = УзелПланаОбмена.НомерПринятого; 

// Можем записать какие-то данные или оставить файл пустым (только заголовки)
ЗаписьСообщения.ЗакончитьЗапись();
ЗаписьXML.Закрыть();

Проблема выгрузки связанных объектов: "Почему не летит Номенклатура?"

Второй важный вопрос, который мы разберем, касается ситуации, когда документ выгружается, а справочники, используемые в нем (Номенклатура, Контрагенты), — нет, в результате чего в приемнике появляются "битые ссылки" (<Объект не найден...>). Чтобы быстро разобраться в связях, используйте портативный обозреватель правил конвертации свойств.

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

Причина: Оптимизация трафика и защита от рекурсии

Если бы система каждый раз при выгрузке документа РеализацияТоваровУслуг выгружала бы всю информацию о Контрагенте и всей Номенклатуре из табличной части, объем файлов обмена вырос бы многократно.

В типовых решениях часто устанавливается флаг:


ОбработкаОбмена.НеВыгружатьОбъектыПоСсылкам = Истина;

Это означает следующее:

  1. Выгружается только тот объект, который явно зарегистрирован в таблице регистрации изменений.
  2. Если изменилась Номенклатура — она регистрируется и выгружается отдельно.
  3. Если изменился Документ, а Номенклатура в нем старая — выгружается только Документ.

Как решить проблему "Битых ссылок"?

  1. Правильный (Регламентный): Выполнить полную синхронизацию НСИ.
  2. Настройка правил (КД2): В правилах конвертации можно управлять поведением выгрузки.
  3. Программная дорегистрация: При регистрации изменений документа можно программно регистрировать и его связанные объекты.
    
    // Пример (псевдокод) при записи документа
    ПланыОбмена.ЗарегистрироватьИзменения(Узел, ЭтотОбъект.Контрагент);
    Для Каждого Стр Из ЭтотОбъект.Товары Цикл
        ПланыОбмена.ЗарегистрироватьИзменения(Узел, Стр.Номенклатура);
    КонецЦикла;
    

Выводы

Чтобы правильно организовать обмен с удалением регистрации:

← На главную