В процессе разработки правил обмена в Конвертации данных 2.1 (КД 2.1) часто возникает архитектурная дилемма: в базе-источнике (например, ERP 2.5) данные хранятся в одном универсальном документе, а в базе-приемнике (например, Бухгалтерия предприятия 3.0) эти данные должны быть разнесены по разным типам документов. Типичный пример — документ Установка цен номенклатуры, который может содержать и товары, и услуги, в то время как в приемнике для них предусмотрены разные объекты метаданных.
В этой статье мы подробно разберем, как технически реализовать такое разделение, настроить регистрацию объектов и обеспечить уникальность ссылок и корректную синхронизацию данных при повторных обменах.
Проанализируем самый распространенный и надежный метод (часто используемый для переноса данных из УПП 1.3 в БП 3.0). Суть его заключается в создании двух отдельных Правил конвертации объектов (ПКО) для каждого типа документа в приемнике. Рассмотрим этот процесс по шагам.
Шаг 1. Настройка ПКО
Создадим два правила:
УстановкаЦен_Товары (Источник: УстановкаЦенНоменклатуры -> Приемник: УстановкаЦенНаТовары).УстановкаЦен_Услуги (Источник: УстановкаЦенНоменклатуры -> Приемник: УстановкаЦенНаРаботы). Подобные правила обмена в КД 2.0 создаются для каждой пары объектов.Шаг 2. Инициация выгрузки в ПВД
В Правиле выгрузки данных (ПВД) для документа-источника мы не просто указываем ПКО по умолчанию, а используем обработчик Перед выгрузкой. Здесь мы должны дважды инициировать процесс выгрузки для одного и того же объекта Источник.
// Выгружаем документ как "Товары"
ВыгрузитьПоПравилу(Источник, , , , "УстановкаЦен_Товары");
// Выгружаем этот же документ как "Услуги"
ВыгрузитьПоПравилу(Источник, , , , "УстановкаЦен_Услуги");
Шаг 3. Фильтрация строк в ПКС
В каждом ПКО для табличной части необходимо прописать условие, чтобы в документ попадали только нужные строки. В обработчике Перед выгрузкой табличной части (или конкретной группы свойств) проанализируем тип номенклатуры:
// Пример для ПКО "УстановкаЦен_Товары"
Если ОбъектКоллекции.Номенклатура.ТипНоменклатуры <> Перечисления.ТипыНоменклатуры.Товар Тогда
Отказ = Истина;
КонецЕсли;
Выясним важную техническую деталь: если мы выгружаем один объект в два разных документа с одним и тем же Уникальным Идентификатором (GUID), это может привести к конфликтам в механизмах БСП (Библиотеки стандартных подсистем). Регистр сведений Соответствия объектов информационных баз может некорректно сопоставлять ссылки.
Разберем, как программно изменить GUID для второго (производного) документа, сохранив его детерминированность (чтобы при повторной выгрузке он оставался неизменным). Рассмотрим пример генерации нового идентификатора на основе существующего в обработчике Перед выгрузкой ПКО:
// Генерируем новый GUID на основе исходного, заменяя часть символов
ИсходныйГУИД = XMLСтрока(Источник.Ссылка);
НовыйГУИДСтрокой = "f" + Сред(ИсходныйГУИД, 2); // Заменяем первый символ на "f"
УзелСвойства = СоздатьУзел("Ссылка");
УстановитьАтрибут(УзелСвойства, "Нпп", НовыйГУИДСтрокой);
В качестве альтернативы можно использовать хеширование MD5 от ссылки и префикса, что гарантирует уникальность для каждого вида документа в приемнике.
Проанализируем ситуацию, когда документ-источник очень большой. Выгружать его дважды и дважды перебирать табличные части неэффективно. В этом случае мы можем подготовить данные заранее в ПВД и передать их в ПКО через параметр ВходящиеДанные.
Рассмотрим алгоритм в ПВД:
ВходящиеДанные.
СтруктураДанных = Новый Структура;
СтруктураДанных.Вставить("ТаблицаТоваров", ТЗ_Товары);
СтруктураДанных.Вставить("ТаблицаУслуг", ТЗ_Услуги);
ВыгрузитьПоПравилу(Источник, , СтруктураДанных, , "УстановкаЦен_Товары");
В ПКО в обработчике Перед выгрузкой табличной части мы укажем:
КоллекцияОбъектов = ВходящиеДанные.ТаблицаТоваров;
Важный момент, который часто упускают: если в исходном документе были только товары, документ по услугам в базе-приемнике создаваться не должен. Если мы просто вызовем ВыгрузитьПоПравилу, мы получим "пустышку".
Для решения этой задачи в обработчике Перед выгрузкой ПКО разберем следующий код:
// Проверяем наличие строк нужного типа
ЕстьНужныеСтроки = Ложь;
Для Каждого СтрокаТЧ Из Источник.Товары Цикл
Если СтрокаТЧ.Номенклатура.ТипНоменклатуры = Перечисления.ТипыНоменклатуры.Услуга Тогда
ЕстьНужныеСтроки = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
Если НЕ ЕстьНужныеСтроки Тогда
Отказ = Истина;
КонецЕсли;
Рассмотрим сценарий, когда из документа-источника удалили все услуги. Ранее выгруженный документ в приемнике должен быть помечен на удаление. Для этого в ПКО приемника можно использовать следующий прием:
В обработчике После загрузки проанализируем количество строк в объекте. Если строк ноль, а документ не помечен на удаление в источнике, мы можем либо пометить его, либо отказаться от записи, если объект новый:
Если Объект.Товары.Количество() = 0 Тогда
Объект.ПометкаУдаления = Истина;
// Либо Отказ = Истина, если не хотим плодить пустые объекты
КонецЕсли;
Так как из одного документа получается два, они не могут иметь одинаковые номера (если в приемнике включен контроль уникальности). Посмотрим, как добавить суффикс к номеру производного документа в Правиле конвертации свойства (ПКС) для Номер:
// Для ПКО услуг добавляем префикс "У"
Значение = "У" + Источник.Номер;
Таким образом, мы обеспечим прозрачность и легкий поиск документов в базе-приемнике, понимая, на основании какого именно документа источника они были созданы.