Как правильно сопоставить номенклатуру по части кода в 1С:Конвертация данных 2.0

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При переносе данных между базами 1С часто возникает ситуация, когда один и тот же справочник (например, Номенклатура) в разных информационных базах велся параллельно. Глобальные идентификаторы (GUID) у элементов, естественно, различаются, а наименования могут быть заполнены хаотично или с опечатками. Единственным надежным зацепным звеном для сопоставления объектов остается код.

Однако структуры кодов в базах-источниках и приемниках могут не совпадать. Представим классическую задачу: в базе-источнике (например, «1С:Розница») код номенклатуры имеет префикс и выглядит как 00-00001515, а в базе-приемнике («1С:Бухгалтерия предприятия 2.0») тот же товар записан с чистым кодом 00001515. Последние 8 символов кода совпадают, и нам необходимо настроить правила обмена так, чтобы объекты корректно сопоставились, а не задвоились при загрузке.

В этой статье мы подробно проанализируем ошибки начинающих разработчиков при решении данной задачи, разберем архитектуру работы механизмов поиска в «1С:Конвертация данных 2.x» (КД) и реализуем два надежных практических способа сопоставления объектов.

Анализ типичной ошибки разработчика

Давайте разберем ошибку, которую совершил автор темы на форуме. В попытке настроить поиск по последним 8 символам кода он написал следующий код в обработчике события ПередВыгрузкой Правила конвертации объектов (ПКО):


// Ошибочный код на стороне источника!
СсылкаНаОбъект = Справочники.Номенклатура.НайтиПоКоду(Прав(СвойстваПоиска["Код"],8));

Этот код не работает и приводит к дублированию данных по нескольким критическим причинам:

  1. Неверная сторона обмена: Обработчик ПередВыгрузкой выполняется исключительно в базе-источнике в процессе формирования XML-файла выгрузки. В этот момент база-приемник еще даже не запущена, и структуры данных приемника недоступны.
  2. Отсутствие контекста поиска: Переменная СвойстваПоиска инициализируется только в базе-приемнике во время чтения XML-файла и сопоставления объектов. Попытка обратиться к ней на этапе выгрузки вызовет системную ошибку или вернет пустое значение (Неопределено).
  3. Бессмысленность поиска в источнике: Вызов метода НайтиПоКоду() на стороне источника пытается найти объект в той же базе, откуда мы его выгружаем. Это бессмысленно, так как ссылка на выгружаемый объект у нас уже есть в переменной Источник.

Чтобы избежать подобных ошибок, нам нужно четко разделять логику работы КД на два этапа: подготовка данных при выгрузке (база-источник) и сопоставление данных при загрузке (база-приемник). Ниже мы разберем два правильных сценария реализации этой задачи.

Способ 1. Приведение кода к единому формату при выгрузке (Рекомендуемый)

Самый простой, элегантный и производительный способ решить проблему — сделать так, чтобы код выгружался в XML-файл уже в правильном, очищенном от префиксов виде. Если мы сразу запишем в XML-файл 8-значный код вместо 11-значного, то база-приемник сможет сопоставить объекты штатным, платформенным механизмом поиска без написания сложных запросов при загрузке.

Рассмотрим по шагам, как настроить этот вариант в конфигурации «Конвертация данных»:

  1. Перейдем в настройки правил и откроем Правило конвертации объектов (ПКО) для справочника Номенклатура.
  2. В списке Правил конвертации свойств (ПКС) найдем строку для реквизита Код.
  3. Откроем свойства этого ПКС двойным кликом мыши и перейдем на вкладку «Обработчики событий».
  4. В обработчике события «Перед выгрузкой» напишем код, который будет отсекать лишние префиксы перед отправкой данных:

// Очищаем код от пробелов и берем только крайние 8 символов справа
Значение = Прав(СокрЛП(Источник.Код), 8);

В этом обработчике переменная Значение определяет то, что фактически запишется в XML-файл для реквизита Код. Переменная Источник хранит ссылку на текущий выгружаемый элемент номенклатуры в базе «1С:Розница».

  1. В настройках этого же ПКС (для реквизита Код) обязательно установим флаг «Поиск». Это укажет универсальной обработке обмена, что по данному полю нужно сопоставлять объекты в приемнике.
  2. Очень важный шаг, о котором часто забывают новички: найдем ПКС для реквизита ЭтоГруппа и также установим для него флаг «Поиск».

Зачем нужен поиск по реквизиту «ЭтоГруппа»? В реальных базах данных коды элементов и папок (групп) могут пересекаться. Например, у вас может быть папка товаров с кодом 00001515 и обычный товар с кодом 00001515. Если вы не включите ЭтоГруппа в поля поиска, система КД может сопоставить выгружаемый товар с существующей группой в базе-приемнике. Это приведет к критическому повреждению структуры справочника, при котором элементы начнут вести себя некорректно, а документы откажутся проводиться из-за несоответствия типов.

  1. В самом ПКО Номенклатура (на закладке «Параметры») снимем флаг «Искать по уникальному идентификатору». Так как базы велись независимо, GUID объектов не совпадают, и поиск по UID будет приводить к постоянному созданию дублей вместо сопоставления по коду.

При использовании этого способа в XML запишется подготовленный 8-значный код. При загрузке в «Бухгалтерию предприятия» стандартный быстрый индексный поиск платформы найдет нужную номенклатуру без написания строчки кода на стороне загрузки.

Способ 2. Динамический поиск по подстроке при загрузке (через Поля поиска)

Иногда первый способ применить невозможно. Например, если исходный код в полном формате (с префиксом 00-00001515) обязательно должен быть перенесен в приемник в первозданном виде, либо если логика синхронизации требует хранения полных кодов в файле обмена. В этом случае нам придется оставить передачу кода как есть, а всю интеллектуальную логику сопоставления перенести на сторону загрузки в обработчик ПКО ПоляПоиска.

Давайте разберем по шагам, как реализовать этот алгоритм:

  1. В ПКО Номенклатура убедимся, что для свойств Код и ЭтоГруппа установлены флаги «Поиск». Это необходимо, чтобы значения данных реквизитов были переданы в структуру СвойстваПоиска при чтении файла обмена.
  2. Снимем флаг «Искать по уникальному идентификатору» в настройках ПКО.
  3. Откроем свойства ПКО Номенклатура, перейдем на вкладку «Обработчики событий» и найдем обработчик «Поля поиска».
  4. Напишем отказоустойчивый и оптимизированный алгоритм поиска на основе запроса:

// Выполняем поиск только на первом варианте сопоставления
Если НомерВариантаПоиска = 1 Тогда
    
    // Защита от незаполненных данных в файле обмена
    Если СвойстваПоиска.Свойство("Код") И СвойстваПоиска.Свойство("ЭтоГруппа") Тогда
        
        // Извлекаем переданный код и вырезаем значимую часть из 8 символов
        ИсходныйКод = СвойстваПоиска["Код"];
        ИскомыйКод = Прав(СокрЛП(ИсходныйКод), 8);
        ЭтоГруппа = СвойстваПоиска["ЭтоГруппа"];
        
        // Используем запрос для поиска объекта в базе-приемнике.
        // Запрос работает значительно быстрее и надежнее, чем метод НайтиПоКоду(), 
        // так как позволяет жестко разграничить поиск групп и элементов.
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1
            |   Номенклатура.Ссылка КАК Ссылка
            |ИЗ
            |   Справочник.Номенклатура КАК Номенклатура
            |ГДЕ
            |   Номенклатура.Код ПОДОБНО &Код
            |   И Номенклатура.ЭтоГруппа = &ЭтоГруппа
            |   И Номенклатура.ПометкаУдаления = ЛОЖЬ"; // отдаем приоритет живым объектам
            
        // Задаем маску поиска: код в приемнике должен заканчиваться на наши 8 цифр
        Запрос.УстановитьПараметр("Код", "%" + ИскомыйКод);
        Запрос.УстановитьПараметр("ЭтоГруппа", ЭтоГруппа);
        
        РезультатЗапроса = Запрос.Выполнить();
        
        Если Не РезультатЗапроса.Пустой() Тогда
            Выборка = РезультатЗапроса.Выбрать();
            Выборка.Следующий();
            
            // Если объект найден, передаем его ссылку в предопределенную переменную КД
            СсылкаНаОбъект = Выборка.Ссылка;
        КонецЕсли;
        
        // Сообщаем движку конвертации данных, что мы выполнили поиск самостоятельно 
        // и стандартные механизмы сопоставления запускать не требуется.
        ПрекратитьПоиск = Истина;
        
    КонецЕсли;
    
КонецЕсли;

Преимущества использования запроса в «Полях поиска»

Многие разработчики вместо написания запросов пытаются использовать стандартные методы менеджеров справочников, например: Справочники.Номенклатура.НайтиПоКоду(ИскомыйКод). Давайте проанализируем, почему подход с запросом является гораздо более предпочтительным:

Используя один из предложенных методов, мы гарантируем корректное сопоставление номенклатуры между базами «1С:Розница» и «1С:Бухгалтерия», полностью исключив задвоение позиций и сохранив целостность иерархии справочников.

← На главную