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