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