Синхронизация данных между конфигурациями «1С:Розница 2» (включая отраслевые решения, например, от компании «Рарус») и «1С:Бухгалтерия предприятия 2.0» (БП 2) часто строится на классическом механизме обмена данными с использованием правил, созданных в программе «1С:Конвертация данных 2.1» (КД). В процессе эксплуатации таких обменов могут возникать непредвиденные сбои при загрузке документов.
Одной из наиболее коварных является ошибка в обработчике события ПоследовательностьПолейПоиска или ПоляПоиска со следующим текстом:
Ошибка при загрузке данных: {Обработка.КонвертацияОбъектовИнформационныхБаз.МодульОбъекта(...)}: Ошибка в обработчике события ПоследовательностьПолейПоиска. ОписаниеОшибки = Получение элемента по индексу для значения не определено
В этой статье мы подробно проанализируем, почему возникает данная ошибка, разберем внутренние механизмы работы платформы 1С при поиске объектов и предложим несколько эффективных способов решения проблемы.
Данная ошибка на стороне базы-приемника означает, что в коде обработчика происходит попытка обращения к коллекции (например, к соответствию, структуре или массиву) по индексу или ключу (через квадратные скобки [...] или метод Получить()), однако сама коллекция в этот момент имеет значение Неопределено или нужный ключ в ней отсутствует.
Рассмотрим основные причины, почему это происходит в контексте поиска справочника Номенклатура:
СтрокаИменСвойствПоиска (например, задаем строку "Код,Родитель,ЭтоГруппа"), то для каждого из указанных свойств в правилах конвертации свойств (ПКС) данного правила обязательно должен быть установлен флаг «Поиск». Если для какого-то реквизита (например, для Родитель) этот флаг забыли поставить, то свойство не попадет в коллекцию СвойстваПоиска. Попытка движка прочитать его по ключу вызовет сбой.Номенклатура является иерархическим. Группы номенклатуры не обладают многими свойствами, которые есть у элементов (например, у них нет артикула, штрихкода или производителя). Если алгоритм пытается искать группу по свойствам, предназначенным только для элементов, коллекция СвойстваПоиска окажется пустой для этих полей, что приведет к ошибке индексации.ПараметрыОбъекта. Однако, если при выгрузке конкретного объекта параметры не были переданы, сама переменная ПараметрыОбъекта инициализируется как Неопределено. Прямое обращение ПараметрыОбъекта["ИмяПараметра"] гарантированно вызовет ошибку.Рассмотрим подробнее три основных способа решения этой проблемы.
Если нам необходимо выполнять поиск номенклатуры по комбинации реквизитов (например, по коду, родителю и признаку группы), мы должны правильно настроить правила в конфигурации «Конвертация данных 2.1».
Выполним следующие шаги:
Номенклатура и перейдем на вкладку «Конвертация свойств».Код, Родитель и ЭтоГруппа обязательно установим флаг «Поиск» в колонке таблицы.ПоследовательностьПолейПоиска (или ПоляПоиска) и напишем безопасный код, разделяющий логику для групп и элементов справочника.Проанализируем пример безопасного кода обработчика:
// Проверяем, инициализирована ли структура свойств поиска
Если СвойстваПоиска <> Неопределено Тогда
// Проверяем, является ли текущий объект группой
ЭтоГруппаОбъекта = Ложь;
Если СвойстваПоиска.Свойство("ЭтоГруппа") Тогда
ЭтоГруппаОбъекта = СвойстваПоиска["ЭтоГруппа"];
КонецЕсли;
// Динамически управляем полями поиска в зависимости от типа объекта
Если ЭтоГруппаОбъекта = Истина Тогда
// Группы ищем строго по Коду и признаку группы
СтрокаИменСвойствПоиска = "Код,ЭтоГруппа";
Иначе
// Элементы ищем по Коду, Родителю и признаку группы
СтрокаИменСвойствПоиска = "Код,Родитель,ЭтоГруппа";
КонецЕсли;
КонецЕсли;
Использование метода Свойство() позволяет нам безопасно проверять наличие ключа в структуре перед тем, как обращаться к нему по индексу. Это полностью исключает возникновение ошибки «Получение элемента по индексу для значения не определено».
Если логика поиска завязана на дополнительные параметры, которые передаются вместе с объектом (например, артикул поставщика или код старой базы), необходимо всегда делать предварительную проверку переменной ПараметрыОбъекта на равенство значению Неопределено.
Посмотрим на пример правильной реализации:
АртикулДляПоиска = "";
// Проверяем, что параметры были переданы при выгрузке
Если ПараметрыОбъекта <> Неопределено Тогда
// Безопасно получаем значение параметра по ключу
Если ПараметрыОбъекта.Свойство("Артикул") Тогда
АртикулДляПоиска = ПараметрыОбъекта["Артикул"];
КонецЕсли;
КонецЕсли;
// Использование полученного значения в полях поиска
Если ЗначениеЗаполнено(АртикулДляПоиска) Тогда
СтрокаИменСвойствПоиска = "Артикул,ЭтоГруппа";
КонецЕсли;
Такой подход защитит код от падения в тех случаях, когда объект выгружается в составе документа и параметры для него не заполняются.
Если у нас нет возможности оперативно изменить правила обмена (например, они зашиты в конфигурацию или закрыты для редактирования), мы можем воспользоваться стандартным механизмом платформы 1С для сопоставления объектов по уникальным идентификаторам (УИД).
В типовых обменах 1С поиск по полям (полям поиска) запускается только в том случае, если объект не был найден по уникальному идентификатору и связь между объектами не зарегистрирована в специальном регистре сведений.
Связи между объектами баз источника и приемника хранятся в регистре сведений СоответствиеОбъектовИнформационныхБаз. Если мы принудительно запишем туда сопоставление по УИД, система отработает следующим образом:
СоответствиеОбъектовИнформационныхБаз и найдет по этому УИД ссылку на уже существующий элемент номенклатуры в базе-приемнике.ОбъектНайден примет значение Истина.ПоляПоиска и ПоследовательностьПолейПоиска, так как объект уже успешно сопоставлен.Для реализации этого метода мы можем воспользоваться стандартным «Помощником интерактивного сопоставления» при ручном запуске обмена или написать простую обработку, которая свяжет объекты в регистре сведений. Ниже приведен пример кода для программной записи связи в регистр соответствия:
// Создаем запись в регистре соответствия объектов информационных баз
МенеджерЗаписи = РегистрыСведений.СоответствиеОбъектовИнформационныхБаз.СоздатьМенеджерЗаписи();
// Заполняем ключевые измерения
МенеджерЗаписи.УзелИнформационнойБазы = СсылкаНаУзелОбмена; // Узел нашей БП или Розницы
МенеджерЗаписи.СобственнаяСсылка = СсылкаНаНоменклатуруПриемник; // Номенклатура в текущей базе
МенеджерЗаписи.УникальныйИдентификаторИсточника = Строка(УИДНоменклатурыИсточник); // УИД из базы-источника
МенеджерЗаписи.ТипИсточника = "СправочникСсылка.Номенклатура";
МенеджерЗаписи.ТипПриемника = "СправочникСсылка.Номенклатура";
// Записываем соответствие
МенеджерЗаписи.Записать(Истина);
Этот способ является максимально надежным решением, так как он полностью исключает человеческий фактор при автоматическом поиске по строковым реквизитам (где могут мешать лишние пробелы, разный регистр букв или опечатки) и обходит проблемный код обработчиков правил конвертации.