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