Как в Конвертации данных 2.1 перенести один справочник в два, если один из них подчинен третьему?

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

При переносе данных между конфигурациями 1С часто возникает архитектурное несовпадение справочников. Типичный пример — перенос справочника Номенклатура. В базе-источнике базовая единица измерения хранится в виде простой ссылки на классификатор. В базе-приемнике структура сложнее: у номенклатуры есть реквизит ЕдиницаХраненияОстатков, который ссылается на подчиненный справочник ЕдиницыИзмерения, а уже этот подчиненный справочник ссылается на глобальный КлассификаторЕдиницИзмерения.

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

Постановка задачи и анализ структуры данных

Сформулируем исходные условия:

Нам необходимо при выгрузке одной позиции номенклатуры создать в базе-приемнике сразу два объекта:

  1. Элемент справочника ЕдиницыИзмерения, подчиненный нашей номенклатуре.
  2. Связать его с глобальным элементом КлассификаторЕдиницИзмерения.

---

Способ 1. Использование виртуального перенаправления источника в ПКО

Рассмотрим, как реализовать этот перенос стандартными средствами КД 2.1. Многие разработчики сталкиваются с трудностями при сопоставлении владельца подчиненного справочника. Выясним, как работает механизм «виртуального» перенаправления.

В правилах конвертации свойств (ПКС) для свойства ЕдиницаХраненияОстатков (в ПКО Номенклатура) мы указываем правило конвертации объектов (ПКО) ЕдиницыИзмерения. Но в качестве источника для этого свойства мы передаем не единицу измерения, а саму номенклатуру.

Для этого в ПКС ЕдиницаХраненияОстатков в обработчике «Перед выгрузкой» пишем следующий код:

Значение = Источник;

Как это работает изнутри:

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

Настройка ПКС внутри ПКО ЕдиницыИзмерения при этом должна выглядеть так:

---

Анализ ошибки: «Получение элемента по индексу для значения не определено»

Часто при попытке настроить передачу владельца через ИсходящиеДанные возникает ошибка в модуле обработки обмена: «Получение элемента по индексу для значения не определено...».

Проанализируем причину этой ошибки. Если вы решили передавать владельца через структуру параметров:


ИсходящиеДанные = Новый Соответствие;
ИсходящиеДанные.Вставить("Владелец", Источник);

То в подчиненном ПКО ЕдиницыИзмерения для свойства Владелец обязательно должно быть настроено ПКС, у которого установлен флаг «Получить из входящих данных». Если этот флаг не взведен, КД 2.1 пытается прочитать свойство стандартным путем, обращаясь к полям источника по индексу. Так как переданный источник не соответствует ожиданиям или структура пуста, система генерирует критическую ошибку.

Правило простое: Если передаете параметры через ИсходящиеДанные в ПКС родителя — обязательно взводите флаг «Получить из входящих данных» в ПКС подчиненного ПКО.

---

Исключение создания Единиц измерения для Услуг

В реальных базах для услуг (или других типов номенклатуры, не имеющих физического остатка) создавать подчиненные единицы измерения не требуется. Если этого не учесть, система создаст «пустые» или лишние карточки единиц измерения.

Чтобы этого избежать, в ПКО Номенклатура для ПКС ЕдиницаХраненияОстатков в обработчике «Перед выгрузкой» добавим условие отсечения:


// Если в источнике это услуга, отменяем выгрузку подчиненного свойства
Если Источник.Услуга Тогда 
    Отказ = Истина;
КонецЕсли;

Если в ПКС срабатывает Отказ = Истина, вызов подчиненного ПКО ЕдиницыИзмерения для этой строки номенклатуры полностью блокируется, и лишние объекты в приемнике не создаются.

---

Способ 2. Альтернативный (более надежный) подход через обработку «После загрузки»

Описанный выше способ с виртуальными ПКО является классическим, но у него есть существенные недостатки: он перегружает файл XML сложными связями, усложняет отладку правил и чувствителен к порядку выгрузки объектов.

Опытные специалисты по КД 2.1 рекомендуют использовать программный подход на стороне загрузки (в базе-приемнике). При этом правила конвертации остаются максимально простыми, а вся логика создания подчиненных справочников описывается на понятном языке 1С.

При таком подходе мы настраиваем простое ПКО Номенклатура, в котором переносим саму номенклатуру и ее реквизит БазоваяЕдиницаИзмерения (которая переносится напрямую в аналогичный реквизит приемника). Никаких сложных виртуальных связей в ПКС ЕдиницаХраненияОстатков настраивать не нужно.

Всю работу мы переносим в ПКО Номенклатура в обработчик «После загрузки» (или «После загрузки объекта»). Разберем по шагам логику этого обработчика:


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

Преимущества программного подхода:

Выбирайте наиболее удобный для вас вариант. Если вам необходимо строго придерживаться декларативного стиля КД 2.1 — используйте Способ 1 с виртуальным ПКО и обязательной проверкой флагов входящих данных. Если вы хотите сделать правила максимально надежными и простыми в сопровождении — используйте Способ 2 с генерацией подчиненных элементов при загрузке.

← На главную