При настройке обмена данными между конфигурациями 1С с помощью инструмента «Конвертация данных 2.1» (КД 2.1) разработчики часто сталкиваются со стандартными сценариями переноса «один в один» или «один ко многим». Однако бывают специфические задачи, когда структура метаданных в базах-источниках и приемниках принципиально отличается. Типичный пример — необходимость преобразовать каждую строку табличной части (ТЧ) одного исходного документа в отдельный полноценный документ в базе-приемнике. Например, когда документ «Пересортица товаров» в конфигурации «Розница» должен превратиться в несколько документов «Комплектация номенклатуры» в «Бухгалтерии предприятия».
Стандартными интерактивными настройками правил обмена такую задачу решить невозможно. Нам потребуется задействовать механизмы программной выгрузки объектов, использовать специальную функцию ВыгрузитьПоПравилу() и передавать параметры через структуру ВходящиеДанные. В этой статье мы подробно, шаг за шагом, разберем архитектуру такого решения, напишем весь необходимый код и решим важнейшую проблему синхронизации объектов для предотвращения появления дублей при повторных обменах.
Для реализации этой схемы обмена нам нужно спроектировать и настроить три ключевых компонента в правилах конвертации:
ВходящиеДанные.Рассмотрим реализацию каждого шага подробно.
Первым делом подготовим правило, которое будет непосредственно отвечать за создание документа «Комплектация номенклатуры» в базе-приемнике. Назовем это ПКО, например, КомплектацияНоменклатуры.
Поскольку у нас нет прямого физического документа-источника (мы конструируем его программно из строки таблицы), настроим ПКО следующим образом:
ДокументСсылка.КомплектацияНоменклатуры.Теперь переходим на вкладку «Правила конвертации свойств» (ПКС). Нам нужно добавить все реквизиты шапки документа, которые мы планируем заполнять (например, Организация, Склад, Дата, Номенклатура, Количество и др.).
Важное правило: для каждого добавленного ПКС в колонке настроек обязательно устанавливаем флаг «Получить из входящих данных». Это указывает системе, что значения реквизитов не нужно пытаться извлечь из несуществующего объекта-источника, а следует взять из переданной нами структуры параметров.
После настройки шапки займемся заполнением табличной части «Комплектующие» нового документа:
Комплектующие.
КоллекцияОбъектов = ВходящиеДанные.Комплектующие;
Внутри этой группы свойств (ПКГС) создаем обычные ПКС для колонок табличной части (Номенклатура, Количество и т.д.). Для них флаг получения из входящих данных ставить уже не нужно — они будут автоматически считываться из строк таблицы значений, которую мы передали в КоллекцияОбъектов.
Теперь нам нужно определить место, откуда будет запускаться выгрузка. Если сам исходный документ «Пересортица товаров» переносить в базу-приемник не требуется (а нужны только созданные на его основе комплектации), идеальным решением будет написать логику в ПВД (Правиле выгрузки данных) для пересортицы.
Создадим новое ПВД для документа «Пересортица товаров». В настройках способа выборки данных укажем «Произвольный алгоритм». Перейдем в обработчик события «Перед выгрузкой» и напишем код обхода строк.
Проанализируем алгоритм: мы будем циклом перебирать строки табличной части «Товары». На каждую строку мы сформируем структуру ВходящиеДанные, наполним ее реквизитами шапки и сформируем таблицу значений для табличной части комплектующих. Затем мы передадим эту структуру в метод ВыгрузитьПоПравилу().
Рассмотрим пример реализации кода в обработчике «Перед выгрузкой» ПВД:
// Проверяем, что объект не помечен на удаление
Если Не Объект.ПометкаУдаления Тогда
ИндексСтроки = 0;
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
// Создаем структуру, которая заменит нам объект-источник
ВходящиеДанные = Новый Структура;
ВходящиеДанные.Вставить("Дата", Объект.Дата);
ВходящиеДанные.Вставить("Организация", Объект.Организация);
ВходящиеДанные.Вставить("Склад", Объект.Склад);
// Заполняем реквизиты комплекта (шапка создаваемой Комплектации)
// Например, при пересортице оприходуемый товар становится готовым комплектом
ВходящиеДанные.Вставить("Номенклатура", СтрокаТЧ.НоменклатураОприходование);
ВходящиеДанные.Вставить("Количество", СтрокаТЧ.КоличествоОприходование);
// Формируем таблицу комплектующих (списываемый товар пойдет в ТЧ)
ТЗКомплектующие = Новый ТаблицаЗначений;
ТЗКомплектующие.Колонки.Добавить("Номенклатура");
ТЗКомплектующие.Колонки.Добавить("Количество");
НоваяСтрока = ТЗКомплектующие.Добавить();
НоваяСтрока.Номенклатура = СтрокаТЧ.НоменклатураСписание;
НоваяСтрока.Количество = СтрокаТЧ.КоличествоСписание;
// Передаем таблицу в структуру под именем, которое ожидает ПКГС
ВходящиеДанные.Вставить("Комплектующие", ТЗКомплектующие);
// --- СИНХРОНИЗАЦИЯ И ЗАЩИТА ОТ ДУБЛИРОВАНИЯ ---
// Генерируем уникальный детерминированный GUID для каждой комплектации.
// За основу берем GUID исходного документа "Пересортица" и модифицируем его хвостовую часть.
ИсходныйУИД = Строка(Объект.Ссылка.УникальныйИдентификатор());
УникальныйИдентификаторСтроки = Лев(ИсходныйУИД, 24) + Формат(ИндексСтроки, "ЧЦ=12; ЧРГ=; ЧГ=0");
ВходящиеДанные.Вставить("ИдентификаторОбъекта", УникальныйИдентификаторСтроки);
// Вызываем программную выгрузку по нашему настроенному ПКО
ВыгрузитьПоПравилу(,, ВходящиеДанные,, "КомплектацияНоменклатуры");
ИндексСтроки = ИндексСтроки + 1;
КонецЦикла;
КонецЕсли;
// Обязательно отменяем стандартную выгрузку самого документа "Пересортица товаров",
// так как вместо него мы уже выгрузили созданные комплектации
Отказ = Истина;
Если запустить обмен в таком виде, документы успешно создадутся в базе-приемнике. Однако при повторной выгрузке тех же самых данных система создаст точно такие же документы заново, проигнорировав уже существующие. Это происходит потому, что у ПКО отсутствует физический объект-источник, и стандартный механизм поиска по уникальному идентификатору 1С (GUID) не может сопоставить объекты.
Для решения этой проблемы мы применили в коде выше детерминированную генерацию GUID. Мы взяли GUID исходного документа-пересортицы (он всегда статичен) длиной 36 символов, отрезали последние 12 символов и заменили их на индекс строки табличной части, дополненный нулями. Таким образом, для первой строки документа с UUID e1c2d3f4-b5a6-7c8d-9e0f-112233445566 мы получим UUID e1c2d3f4-b5a6-7c8d-9e0f-000000000000, для второй — e1c2d3f4-b5a6-7c8d-9e0f-000000000001 и так далее. Эти идентификаторы никогда не изменятся при повторных обменах, что гарантирует стабильную связь.
Теперь настроим правила поиска в ПКО КомплектацияНоменклатуры, чтобы база-приемник умела обрабатывать эти идентификаторы:
КомплектацияНоменклатуры добавьте новое ПКС для свойства «Ссылка». Источник оставьте пустым, а в качестве приемника выберите Ссылка.КомплектацияНоменклатуры и напишите следующий код:
ГУИД = "";
Если Не ПараметрыОбъекта = Неопределено Тогда
ПараметрыОбъекта.Sвойство("ИдентификаторОбъекта", ГУИД);
КонецЕсли;
Если ЗначениеЗаполнено(ГУИД) Тогда
// Пытаемся получить ссылку в базе-приемнике по нашему детерминированному GUID
СсылкаНаДокумент = Документы.КомплектацияНоменклатуры.ПолучитьСсылку(Новый УникальныйИдентификатор(ГУИД));
// Передаем эту ссылку механизму КД.
// Если документ с таким GUID уже есть в базе — КД найдет его и обновит.
// Если его еще нет — КД автоматически создаст новый пустой документ именно с этим GUID, а затем заполнит его реквизиты.
СсылкаНаОбъект = СсылкаНаДокумент;
ПрекратитьПоиск = Истина;
КонецЕсли;
Этот простой, но крайне эффективный прием полностью решает проблему дублирования данных. Теперь вы можете запускать обмен неограниченное количество раз: документы будут корректно обновляться, не создавая лишних копий в информационной базе приемника.
Мы подробно разобрали сложный сценарий трансформации структуры данных при обмене через «Конвертацию данных 2.1». Использование программного выгрузки через ВыгрузитьПоПравилу() в сочетании с передачей параметров через ВходящиеДанные дает разработчику полную свободу действий. А генерация предсказуемых уникальных идентификаторов на основе исходных объектов позволяет сохранить ссылочную целостность баз данных и защитить систему от дублей. Применяйте эти паттерны в своих правилах обмена для решения нестандартных интеграционных задач любой сложности!