При настройке правил обмена в конфигурации Конвертация данных 2.x разработчики нередко сталкиваются с ситуацией, когда иерархический справочник переносится некорректно: вместо помещения элементов в уже существующую в базе-приемнике папку создается новая группа-дубль с таким же наименованием и кодом. Разберем по шагам, почему возникает эта ошибка, как работает механизм идентификации объектов в универсальном обмене и как правильно настроить правила конвертации для групп и элементов.
Проанализируем базовый механизм сопоставления объектов платформы 1С при загрузке данных. По умолчанию в правиле конвертации объекта (ПКО) активен флаг Искать объект приемника по внутреннему идентификатору (GUID). Механизм загрузки отрабатывает по следующему алгоритму:
ПолучитьСсылку.Рассмотрим самое простое и быстрое решение, которое применимо в большинстве типовых переносов. Для устранения дублирования папок нам требуется изменить логику поиска на вкладке настроек соответствующего правила конвертации объектов:
Номенклатура).Код, а при необходимости и ЭтоГруппа) стоял флаг Поиск.После изменения этих параметров выгрузим новые правила обмена и повторим загрузку данных.
Часто встречается ситуация, когда в источнике длина кода справочника составляет 10 символов, а в приемнике — 11 символов. Если просто включить типовое приведение длины, строка кода может быть дополнена пробелами справа, тогда как нумератор типовой конфигурации 1С формирует текстовые коды с ведущими нулями слева (например, код 0000000005 в базе с 11 знаками должен стать 00000000005). Если количество ведущих нулей не совпадает, точное строковое равенство не сработает, и группа снова создастся повторно.
Разберем, как программно дополнить код нулями слева до нужной разрядности приемника. Для этого перейдем в ПКС для реквизита Код и в обработчике Перед выгрузкой напишем следующий код:
Значение = Прав("00000000000" + СокрЛП(Источник.Код), 11);
Такое преобразование гарантирует, что поиск по коду в базе-приемнике найдет именно существующую группу без создания дубликата из-за несовпадающего строкового представления.
В сложных обменах наиболее надежным решением является физическое разделение логики переноса элементов и папок на два разных правила конвертации объектов. Рассмотрим, как реализовать такую архитектуру:
Номенклатура_Элементы. В обработчике Перед выгрузкой этого ПКО установим условие:
Если Источник.ЭтоГруппа Тогда
Отказ = Истина;
КонецЕсли;
Номенклатура_Группы. В его обработчике Перед выгрузкой пропишем обратное условие:
Если Не Источник.ЭтоГруппа Тогда
Отказ = Истина;
КонецЕсли;
Номенклатура_Группы полностью отключим поиск по внутреннему идентификатору и укажем поля поиска Код или Наименование. Для защиты структуры папок приемника от перезаписи можно также включить флаг Не замещать существующие объекты при загрузке (обновлять только пустые).Номенклатура_Элементы для ПКС Родитель явно укажем правило конвертации: Номенклатура_Группы.Такой подход полностью изолирует настройки поиска папок от настроек конечных номенклатурных позиций.
Если стандартных флагов недостаточно или требуется реализовать индивидуальное поведение поиска только для определенных категорий объектов, используем обработчик ПоляПоиска на стороне приемника в соответствующем ПКО.
Посмотрим на пример переопределения поиска для папок через коллекцию СвойстваПоиска:
Если СвойстваПоиска["ЭтоГруппа"] = Истина Тогда
НайденнаяГруппа = Справочники.Номенклатура.НайтиПоКоду(СвойстваПоиска["Код"]);
Если ЗначениеЗаполнено(НайденнаяГруппа) Тогда
СсылкаНаОбъект = НайденнаяГруппа;
ПрекратитьПоиск = Истина;
КонецЕсли;
КонецЕсли;
Переменная ПрекратитьПоиск = Истина сообщает механизму загрузки, что сопоставление успешно завершено, и стандартные механизмы сравнения по идентификаторам или таблицам полей поиска вызываться больше не будут.
Если стоит задача не просто сопоставить папки, а принудительно сложить всю выгружаемую номенклатуру в конкретную заранее созданную папку приемника, удобнее всего сделать это в обработчике Перед загрузкой или При загрузке объекта-приемника.
Рассмотрим пример кода в обработчике ПКО При загрузке:
Если Не Объект.ЭтоГруппа Тогда
ЦелеваяПапка = Справочники.Номенклатура.НайтиПоКоду("00000000005");
Если ЗначениеЗаполнено(ЦелеваяПапка) Тогда
Объект.Родитель = ЦелеваяПапка;
КонецЕсли;
КонецЕсли;
При использовании данного способа выгрузку ПКС для реквизита Родитель можно вовсе отключить, чтобы не передавать лишние ссылки и не создавать нежелательные группы в целевой базе.