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