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