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