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