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

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

При настройке обмена данными между различными конфигурациями «1С» разработчики часто сталкиваются с нестандартными задачами сопоставления объектов. Типичный сценарий: в базе-источнике ведется детальный учет с разделением номенклатуры по типам, а в базе-приемнике необходимо свернуть эти позиции и сопоставить их с предопределенной или уже существующей номенклатурой, ориентируясь только на текстовое наименование типа источника. При этом перенос происходит внутри табличной части документа.

В этой статье мы подробно проанализируем, почему стандартные механизмы генерации правил могут выдавать пустые значения при загрузке, разберем грубые ошибки программирования в обработчиках конвертации и рассмотрим два надежных архитектурных решения этой задачи.

Анализ исходных ошибок и причин сбоя конвертации

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


КоллекцияОбъектов = Новый Массив; 
КоллекцияОбъектов = Источник.Товары.Выгрузить; 
Для Каждого СтрокаТЧ Из Источник.Товары Цикл 
    НоваяСтрока = КоллекцияОбъектов.Добавить; 
    ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТЧ); 
КонецЦикла;

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

Вторая критическая ошибка возникает при обращении к свойствам источника в обработчике Перед выгрузкой ПКС Наименование в ПКО НоменклатураТип:


Если СокрЛП(источник.ТипНоменклатуры.Наименование)="Сырье и материалы" тогда 
    Значение="10,1 Сырье и материалы";
КонецЕсли;

Если в качестве источника для ПКО выступает сам справочник ТипыНоменклатуры, то у него нет реквизита ТипНоменклатуры. Платформа закономерно вызывает исключение Поле объекта не обнаружено (ТипНоменклатуры). В данном контексте необходимо обращаться напрямую к свойствам текущего выгружаемого объекта: Источник.Наименование.

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

---

Вариант решения А. Настройка ПКО с пустым источником (Рекомендуемый способ)

Самый чистый и надежный способ сопоставить произвольный текст с реальным элементом справочника — использовать правило конвертации объектов (ПКО) с пустым источником. В этом случае мы полностью убираем привязку к уникальным идентификаторам источника и работаем исключительно со строковым значением.

Выполним настройку по шагам:

  1. Создание ПКО без источника:
    • Создайте новое ПКО. Имя правила: НоменклатураПоНаименованиюТипа.
    • Поле Источник оставьте пустым.
    • В поле Приемник выберите справочник СправочникСсылка.Номенклатура.
    • Снимите флаг Искать объект приемника по внутреннему идентификатору..., так как УИД у нас отсутствует.
  2. Настройка ПКС (Правил конвертации свойств):
    • Внутри ПКО добавьте только одно свойство: Наименование. Поля источника у него не будет.
    • Установите для этого ПКС флаг Поиск. Это укажет системе, что загружаемый объект нужно искать по текстовому наименованию.
    • В обработчике Перед выгрузкой для этого ПКС напишите простой код передачи значения: Значение = Источник;
  3. Передача данных из табличной части документа:
    • В ПКС вашей табличной части (например, свойство Номенклатура в ТЧ Товары) в обработчике Перед выгрузкой пропишите алгоритм сопоставления. Здесь мы анализируем тип номенклатуры строки источника, вычисляем нужное текстовое название для приемника и передаем его в созданное ПКО:
    
    // Получаем тип номенклатуры текущей строки табличной части
    ТипНом = ОбъектКоллекции.Номенклатура.ТипНоменклатуры;
    
    Если ЗначениеЗаполнено(ТипНом) Тогда
        ИмяТипа = СокрЛП(ТипНом.Наименование);
        
        // Сопоставляем типы источника с конкретными наименованиями в приемнике
        Если ИмяТипа = "Сырье и материалы" Тогда
            Значение = "10,1 Сырье и материалы";
        ИначеЕсли ИмяТипа = "Материалы и спецоснастка" Тогда
            Значение = "10,10 Специальная оснаска и специальная одежда на";
        ИначеЕсли ИмяТипа = "Запасные части" Тогда
            Значение = "10,5 Запасные части";
        ИначеЕсли ИмяТипа = "Инвентарь и хоз.принадлежности" Тогда
            Значение = "10,9 Инвентарь и хозяйственные принадлежности";
        ИначеЕсли ИмяТипа = "ГСМ и заправочные жидкости" Тогда
            Значение = "10,3 Топливо";
        ИначеЕсли ИмяТипа = "Инструменты" Тогда
            Значение = "10,11,2 Инструменты";
        ИначеЕсли ИмяТипа = "Спецодежда" Тогда
            Значение = "10,11,1 Спецодежда";
        ИначеЕсли ИмяТипа = "Стройматериалы" Тогда
            Значение = "10,8 Строительные материалы";
        Иначе
            Значение = "Прочие материалы"; // Значение по умолчанию
        КонецЕсли;
        
        // Явно указываем созданное нами ПКО для ручного поиска по тексту
        ИмяПКО = "НоменклатураПоНаименованиюТипа";
    Иначе
        // Если тип не задан, исключаем выгрузку номенклатуры для этой строки
        Отказ = Истина;
    КонецЕсли;
    

При таком подходе в выгружаемом XML-файле сформируется чистая текстовая строка в узле свойства, а при загрузке обработчик платформы выполнит поиск в справочнике Номенклатура по точному совпадению наименования.

---

Вариант решения Б. Переопределение поиска на стороне приемника через «Поля поиска»

Бывают ситуации, когда стандартный поиск платформы по наименованию не справляется. Например, в базе-приемнике справочник Номенклатура имеет сложную иерархическую структуру (папки), включен полнотекстовый поиск или наименования могут содержать скрытые пробелы и символы переноса строки. В таких случаях надежнее всего написать собственный алгоритм поиска с помощью запроса непосредственно при загрузке данных.

Для реализации этого варианта выполним следующие действия:

  1. Откройте ПКО НоменклатураПоНаименованиюТипа (настроенное по Варианту А).
  2. Перейдите на вкладку Обработчики событий и выберите обработчик Поля поиска.
  3. Напишем отказоустойчивый алгоритм поиска с использованием запроса к базе данных приемника:

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

Использование обработчика Поля поиска гарантирует, что даже при наличии дублей в базе данных или сложной структуры папок, алгоритм выберет наиболее подходящую номенклатуру по заданному шаблону, минимизируя появление пустых строк в загруженных документах.

← На главную