При работе с инструментом Конвертация данных 2.1 разработчики часто сталкиваются с ситуацией, когда правила обмена идеально работают в обработке УниверсальныйОбменДаннымиXML, но выдают критическую ошибку при запуске через штатный механизм синхронизации (узлы планов обмена). Одной из самых коварных является ошибка Тип не определен, возникающая в модуле обработки КонвертацияОбъектовИнформационныхБаз. Рассмотрим подробнее, почему это происходит и как правильно настроить выгрузку связанных объектов.
Проанализируем сценарий: имеется конфигурация Управление торговлей 10.3 (источник) и Бухгалтерия предприятия 3.0 (приемник). Настроена односторонняя синхронизация. В процессе выгрузки справочника Номенклатура нам необходимо программно сформировать и выгрузить спецификации для комплектов, данные о которых хранятся в регистре сведений КомплектующиеНоменклатуры. Для этого в обработчике ПослеВыгрузкиОбъекта правила ПКО Номенклатура используется метод ВыгрузитьПоПравилу.
Типичный код, который вызывает проблему, выглядит следующим образом:
Если НЕ Источник.Ссылка.ЭтоГруппа Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| КомплектующиеНоменклатуры.Комплектующая КАК Номенклатура,
| КомплектующиеНоменклатуры.Количество
|ИЗ
| РегистрСведений.КомплектующиеНоменклатуры КАК КомплектующиеНоменклатуры
|ГДЕ
| КомплектующиеНоменклатуры.Номенклатура = &Номенклатура";
Запрос.УстановитьПараметр("Номенклатура", Источник.Ссылка);
ИсходныеКомплектующие = Запрос.Выполнить().Выгрузить();
Если ИсходныеКомплектующие.Количество() > 0 Тогда
ИсходящиеДанные = Новый Структура("Владелец, ИсходныеКомплектующие, Наименование");
ИсходящиеДанные.Вставить("Владелец", Источник.Ссылка);
ИсходящиеДанные.Вставить("Наименование", Источник.Ссылка.Наименование);
ИсходящиеДанные.Вставить("ИсходныеКомплектующие", ИсходныеКомплектующие);
// Вызов выгрузки по правилу без явного типа источника в ПКО
ВыгрузитьПоПравилу(Источник.Ссылка, , ИсходящиеДанные, , "СпецификацииНоменклатуры");
КонецЕсли;
КонецЕсли;
Проблема проявляется не при первой выгрузке, а при повторном обмене, когда база-приемник присылает подтверждение о получении данных. Выясним причину этого поведения.
Разберем по шагам, что происходит в системе при использовании планов обмена. В отличие от ручной выгрузки через файл, обмен через узлы подразумевает квитирование (подтверждение) доставки сообщений. Когда объект загружается в базу-приемник, система фиксирует связь между идентификатором (GUID) источника и созданным объектом в регистре сведений СоответствиеОбъектовИнформационныхБаз.
При следующем сеансе обмена приемник отправляет обратно информацию о том, что объект с таким-то GUID успешно загружен. Для этого в XML-файле формируются узлы с информацией о регистрации. Проблема в том, что если в Правиле Конвертации Объектов (ПКО) не указан тип источника, система при выгрузке записывает в файл пустую строку в атрибут ТипИсточника. При чтении этого файла в базе-источнике функция ПрочитатьИнформациюОРегистрацииОбъекта() пытается сопоставить строковое представление типа из файла с метаданными и, встречая пустое значение, выбрасывает исключение Тип не определен.
Проанализируем самый простой и эффективный способ исправления. Чтобы система 1С могла корректно идентифицировать объект при обратном чтении подтверждения, в ПКО СпецификацииНоменклатуры (которое используется в ВыгрузитьПоПравилу) необходимо обязательно заполнить поле "Объект источник".
СпецификацииНоменклатуры.СправочникСсылка.Номенклатура или сам регистр РегистрСведенийМенеджерЗаписи.КомплектующиеНоменклатуры.Важный момент: поскольку мы используем ИсходящиеДанные, фактические данные для заполнения объекта будут браться из структуры, а указанный тип источника будет использоваться только как "заглушка" для механизмов регистрации соответствий.
Посмотрим на ситуацию с другой стороны. Если нам не нужно отслеживать связь между спецификацией в УТ и спецификацией в БП по GUID (например, если мы всегда ищем их по наименованию и владельцу), мы можем приказать системе не запоминать эти связи.
В настройках ПКО на закладке "Настройки выгрузки" можно установить флаг Не запоминать соответствия для этого правила. В этом случае:
СоответствиеОбъектовИнформационныхБаз.Тип не определен не возникнет, так как не будет самой попытки прочитать тип источника.Рассмотрим более сложный, но гибкий вариант. В методе ВыгрузитьПоПравилу первым параметром передается Объект или Ссылка. Если мы передаем Источник.Ссылка, система пытается связать выгружаемую Спецификацию с объектом Номенклатура. Это архитектурно не совсем верно, так как один GUID источника (Номенклатуры) начинает соответствовать двум разным типам в приемнике (Номенклатуре и Спецификации).
Чтобы избежать путаницы в GUID, можно передать Неопределено в качестве первого параметра, если поиск в приемнике настроен только по полям поиска (например, по Владельцу и Наименованию спецификации):
ВыгрузитьПоПравилу(Неопределено, , ИсходящиеДанные, , "СпецификацииНоменклатуры");
В этом случае регистрация соответствия по GUID не будет выполнена, и конфликт типов при квитировании будет исчерпан.
Проанализируем еще один важный нюанс. Поскольку данные о комплектующих хранятся в регистре, который часто не включен в план обмена, изменения в составе комплекта могут не улететь в базу-приемник автоматически. Изменение записей регистра не вызывает автоматической регистрации изменений самой Номенклатуры.
Рекомендуем добавить в модуль набора записей регистра КомплектующиеНоменклатуры следующий код:
Процедура ПриЗаписи(Отказ, Замещение)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Регистрируем владельца (Номенклатуру) на узлах обмена
ПланыОбмена.ЗарегистрироватьИзменения(УзлыДляОбмена, ЭтотОбъект.Отбор.Номенклатура.Значение);
КонецПроцедуры
Это гарантирует, что при любом изменении состава комплектующих сама Номенклатура попадет в очередь на выгрузку, сработает обработчик ПослеВыгрузкиОбъекта, и актуальные спецификации будут переданы в Бухгалтерию предприятия.
Резюме: для стабильной работы обмена через узлы всегда следите за тем, чтобы у ПКО был заполнен тип источника, либо используйте флаг отказа от сохранения соответствий, если объект является производным и создается программно через ВыгрузитьПоПравилу.