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

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

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

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

Анализ архитектурной ошибки: почему нельзя просто сделать регистр «движением» документа?

Часто на форумах (как, например, в Сообщении 8 исходной темы) новичкам советуют добавить регистр сведений в метаданные документа-приемника в качестве его движений. Однако в случае с независимым регистром сведений такой совет технически неверен и вреден по следующим причинам:

  1. Независимый регистр не подчинен регистратору. У независимого регистра сведений по определению отсутствует стандартное измерение Регистратор. Он не может выступать в роли движения документа. Попытка привязать его к документу потребует изменения структуры метаданных в конфигураторе приемника — изменения режима записи регистра на «Подчинение регистратору».
  2. Нарушение типовой архитектуры. Изменение режима записи регистра с независимого на подчиненный приведет к необходимости снимать объект с поддержки, переписывать существующие запросы, формы и механизмы записи в базе-приемнике. Это крайне нежелательно, если вы стремитесь сохранить конфигурацию типовой для упрощения последующих обновлений.

Поэтому решать задачу необходимо исключительно на уровне правил обмена в КД 2.1, не затрагивая конфигурацию-приемник. Рассмотрим, как это сделать правильно.

---

Способ 1. Построчная выгрузка через программный вызов «ВыгрузитьПоПравилу» (Рекомендуемый путь)

Этот способ является классическим для КД 2.1. Мы создадим отдельное правило конвертации объектов (ПКО) для регистра сведений и будем принудительно вызывать его для каждой строки табличной части во время выгрузки самого документа.

Шаг 1. Создание ПКО для регистра сведений

В первую очередь нам необходимо подготовить правило, которое умеет записывать данные в регистр сведений приемника, получая их из внешней структуры (входящих данных):

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

Шаг 2. Написание алгоритма выгрузки в ПКО документа-источника

Теперь перейдем в ПКО нашего документа-источника. Нам нужно перехватить момент, когда документ уже выгружен, чтобы у нас была гарантированно сформирована его уникальная ссылка в файле обмена. Для этого отлично подходит обработчик события «После выгрузки» ПКО документа.

Проанализируем и напишем в этом обработчике следующий код:


// Циклом обходим каждую строку табличной части документа-источника
Для Каждого СтрокаТЧ Из Источник.ИмяТабличнойЧасти Цикл
    
    // Формируем структуру. Ключи структуры должны строго совпадать 
    // с именами свойств приемника в ПКО нашего регистра сведений
    ВходящиеДанныеРегистра = Новый Структура;
    ВходящиеДанныеРегистра.Вставить("СсылкаНаДокумент", Источник.Ссылка);
    ВходящиеДанныеРегистра.Вставить("НомерСтроки", СтрокаТЧ.НомерСтроки);
    ВходящиеДанныеРегистра.Вставить("Склад", СтрокаТЧ.Склад);
    ВходящиеДанныеРегистра.Вставить("ДатаПроведения", СтрокаТЧ.ДатаПроведения);
    
    // Вызываем программную выгрузку по подготовленному ранее ПКО
    // Передаем структуру в качестве параметра "ВходящиеДанные"
    ВыгрузитьПоПравилу(,, ВходящиеДанныеРегистра,, "ИмяПКО_РегистраСведений");
    
КонецЦикла;

При такой настройке КД 2.1 для каждой строки табличной части сгенерирует в XML-файле отдельный узел с записью регистра сведений. При загрузке эти узлы будут прочитаны и записаны в базу-приемник как независимые записи.

---

Способ 2. Передача таблицы значений с последующей программной записью (Альтернативный путь)

Если строк в документах очень много, построчный вызов функции ВыгрузитьПоПравилу может увеличить размер XML-файла и замедлить выгрузку. В таком случае целесообразно использовать альтернативный вариант: «упаковать» всю табличную часть в таблицу значений, передать ее в параметрах документа и записать в регистр одним пакетом на стороне приемника.

Шаг 1. Сбор и подготовка данных при выгрузке

В ПКО документа-источника откроем обработчик события «Перед выгрузкой». Здесь мы выгрузим нужные колонки табличной части в таблицу значений и поместим ее в специальную коллекцию параметров объекта:


// Выгружаем табличную часть источника, отбирая только необходимые колонки
ТаблицаДляРегистра = Источник.ИмяТабличнойЧасти.Выгрузить(, "НомерСтроки, Склад, ДатаПроведения");

// Инициализируем коллекцию параметров выгружаемого объекта, если она не была создана ранее
Если ПараметрыОбъекта = Неопределено Тогда
    ПараметрыОбъекта = Новый Соответствие;
КонецЕсли;

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

Шаг 2. Разбор параметров и запись в регистр при загрузке

Теперь перейдем в ПКО документа на стороне приемника. Нам нужно обработать полученные данные после того, как сам документ-приемник будет записан в базу данных и получит валидную ссылку. Откроем обработчик события «После загрузки» документа-приемника и напишем следующий алгоритм:


// Извлекаем переданную таблицу значений из параметров объекта
ТаблицаДанных = ПараметрыОбъекта.Получить("ДанныеДляРегистра");

Если ТаблицаДанных <> Неопределено И ТаблицаДанных.Количество() > 0 Тогда
    
    // Создаем набор записей регистра сведений для программной записи
    НаборЗаписей = РегистрыСведений.ИмяВашегоРегистра.СоздатьНаборЗаписей();
    
    // Обязательно устанавливаем отбор по документу, чтобы перезаписать старые движения
    НаборЗаписей.Отбор.СсылкаНаДокумент.Установить(Объект.Ссылка);
    
    // Заполняем набор записей данными из переданной таблицы
    Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
        
        НоваяЗапись = НаборЗаписей.Добавить();
        НоваяЗапись.СсылкаНаДокумент = Объект.Ссылка;
        НоваяЗапись.НомерСтроки     = СтрокаДанных.НомерСтроки;
        
        // ВАЖНО: Если справочники (например, Склады) в базах имеют разные внутренние идентификаторы (GUID),
        // прямое присвоение СтрокаДанных.Склад может вернуть "Битую ссылку".
        // Если базы не идентичны по GUID, рекомендуется предварительно найти ссылку в приемнике по коду/наименованию:
        // НоваяЗапись.Склад = Справочники.Склады.НайтиПоКоду(СтрокаДанных.Склад.Код);
        
        НоваяЗапись.Склад            = СтрокаДанных.Склад; 
        НоваяЗапись.ДатаПроведения  = СтрокаДанных.ДатаПроведения;
        
    КонецЦикла;
    
    // Записываем набор. Старые записи по этому документу автоматически удалятся, 
    // благодаря установленному ранее отбору.
    Попытка
        НаборЗаписей.Записать(Истина);
    Исключение
        ЗаписьЖурналаРегистрации("ОбменДанными", УровеньЖурналаРегистрации.Ошибка,,, 
            "Ошибка записи в регистр для документа " + Строка(Объект.Ссылка) + ": " + ОписаниеОшибки());
    КонецПопытки;
    
КонецЕсли;

---

Важные нюансы и советы для начинающих разработчиков в КД 2.1

Оба рассмотренных метода являются стандартными и активно используются при профессиональной разработке правил обмена в КД 2.1. Выбор конкретного подхода зависит от объемов переносимых данных и требований к чистоте кода в правилах обмена.

← На главную