1. Теория
В штатной справке по Конвертации данных об этих параметрах написано следующее:
ВходящиеДанные - Произвольный - произвольные вспомогательные данные, переданные правилу конвертации из других правил (например из правила выгрузки данных или правила конвертации свойств). Значение параметра, как правило, имеет тип Структура, где ключи значений соответствуют структуре свойств объекта приемника. Таким образом, при конвертации свойств (в правиле конвертации свойств), конвертируемые данные (или часть данных) могут быть получены из этого параметра.
ИсходящиеДанные - Произвольный - произвольные вспомогательные данные. Данные передаются по следующим правилам:
1) ПВД.ИсходящиеДанные -> ПКО.ВходящиеДанные
2) ПКО.ВходящиеДанные -> ПКС.ВходящиеДанные
3) ПКС.ИсходящиеДанные -> ПКО.ВходящиеДанные
Попробуем разобраться подробнее, как передаются данные параметры.
Шаг 1. ПВД (Правило выгрузки данных)
В правилах выгрузки данных создаем параметр ИсходящиеДанные и помещаем в него некоторое значение.
Шаг 2. ПКО (Правило конвертации объектов)
После выполнения ПВД, параметр передается в ПКО-приемник уже как ВходящиеДанные. К этому параметру можно обратиться в коде, например, поместив еще один элемент в структуру.
Если будет установлено хотя бы одно поле, получаемое из входящих данных, в ПКО добавится вкладка "Параметры, получаемые из входящих данных", где будет отображаться список соответствующих полей. Также отобразится кнопка "Структура запрашиваемых данных", которая позволит посмотреть, какую структуру входящих данных нужно передать в ПКО.
Шаг 3. ПКС (Правило конвертации свойств)
После выполнения кода в ПКО, параметр будет передан в ПКС как ВходящиеДанные. Здесь обращаем внимание на следующую особенность: из ПВД уходят ИсходящиеДанные, в ПКО приходят ВходящиеДанные. Из ПКО уходят ВходящиеДанные, в ПКС также приходят ВходящиеДанные.
Для того, чтобы свойству было присвоено значение из входящих данных, выставляем галку "Получить из входящих данных". Поле Источник очистится, т.к. оно уже потеряло свой смысл.
При совпадении наименовании ключа структуры входящих данных, поля будут заполнятся автоматически из входящих данных. Если наименование в структуре различаются, значение необходимо переназначить в ПКС вручную.
Шаг 4. Снова ПКО
Если поле имеет не примитивный тип данных, то система продолжит конвертацию объекта по правилу. Параметр ИсходящиеДанные, заданный в ПКС, будет передан в ПКО как ВходящиеДанные.
2. Практика
Задача: Необходимо настроить передачу документа (для примера будем использовать документ ПоступлениеТоваровУслуг) из базы Источника(1С:ERP Управление предприятием 2) в базу Приемник(Управление производственным предприятием 1.3) через регистр сведений "Сопоставление номенклатуры". У документа есть табличная часть Товары, в которой имеется поле "Номенклатура.
Номенклатура базы Источника должна заменяться на номенклатуру базы Приемника на основании найденного сопоставления, т.к. это эквивалентные номенклатуры, только хранящиеся в разных базах и имеющих разные наименования. В случае, если сопоставление не найдено - отказ в выгрузке всего документа.
Все передаваемые объекты, содержащие в себе поле Номенклатура, должны выгружаться через регистр сопоставлений.
Регистр хранится в базе Источнике.
Решение:
Для начала создадим ПКО для документа ПриобретениеТоваровУслуг, в качестве приемника необходимо указать документ ПоступлениеТоваровУслуг. На вопрос создать ли правила конвертации свойств автоматически, отвечаем утвердительно. Проверяем автоматически созданные ПКС на корректность. Далее создаем ПВД. Теперь можно приступать к доработке правил сопоставления.
Необходимо создать новую табличную часть Товары, в которой заменить номенклатуру Источника на номенклатуру Приемника. Если для выгружаемой Номенклатуры не будет найдено сопоставление, то отказ в выгрузке всего документа. Для этого в ПКО ПриобретениеТоваровУслуг в обработчике события Перед Выгрузкой добавим следующий код:
//Формируем Новую табличную часть, которую будем помещать во входящие данные
ТЧ = Источник.Товары.Выгрузить();
//Массив Номенклатур для загрузки в колонку ТЧ
МассивНоменклатур = Новый Массив;
//для того, чтобы не выполнять запрос в цикле, помещаем в запрос всю ТЧ Источника
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СопоставлениеНоменклатурыУППERP.НоменклатураУПП КАК НоменклатураУПП,
| ПриобретениеТоваровУслугТовары.Номенклатура КАК Номенклатура
|ИЗ
| Документ.ПриобретениеТоваровУслуг.Товары КАК ПриобретениеТоваровУслугТовары
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.pll_СопоставлениеНоменклатурыУППERP КАК СопоставлениеНоменклатурыУППERP
| ПО ПриобретениеТоваровУслугТовары.Номенклатура = СопоставлениеНоменклатурыУППERP.НоменклатураERP
|ГДЕ
| ПриобретениеТоваровУслугТовары.Ссылка = &Источник"
Запрос.УстановитьПараметр("Источник", Источник);
РезультатЗапроса = Запрос.Выполнить();
ДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ДетальныеЗаписи.Следующий() Цикл
//проверяем, найдено ли соответствие
Если ЗначениеЗаполнено(ДетальныеЗаписи.НоменклатураУПП) Тогда
МассивНоменклатур.Добавить(ДетальныеЗаписи.НоменклатураУПП);
Иначе
//Отказ, если ничего не найдено
Сообщить("Для документа " + Источник.Ссылка + " не найдено соответствие номенклатур ERP-УПП. Номенклатура "
+ДетальныеЗаписи.Номенклатура.Наименование+". Выгрузка документа отменена!");
Отказ = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
Если НЕ Отказ Тогда
//помещаем новую табличную часть во входящие данные
ТЧ.Колонки.Удалить("Номенклатура");
ТЧ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.НоменклатураУПП"));
ТЧ.ЗагрузитьКолонку(МассивНоменклатур,"Номенклатура");
ВходящиеДанные = Новый Структура;
ВходящиеДанные.Вставить("Товары",ТЧ);
КонецЕсли;
Правила обмена почти готовы. Теперь необходимо установить галку для Свойства "Получить из входящих данных" для табличной части Товары.
Правила обмена готовы. Сохраняем созданные правила. Попытаемся выгрузить из базы Источника и загрузить в Приемник тестовый документ. После загрузки в Приемник видим, что номенклатура была передана корректно, но колонка ЕдиницаИзмерения не загрузилась.
Связана эта ситуация с тем, что свойство ЕдиницаИзмерения привязана к номенклатуре-владельцу. Следовательно, нужно передать из ПКС единиц измерения номенклатуру-владельца в ПКО ЕдиницыИзмерения.
Добавим в обработчик события Перед выгрузкой для ПКС ЕдиницаИзмерения следующий код:
ИсходящиеДанные = Новый Структура("Владелец");
ИсходящиеДанные.Владелец = ОбъектКоллекции.Номенклатура;
То, что указываем в ПКС как ИсходящиеДанные, в ПКО будет уже ВходящиеДанные.
В ПКО ЕдиницыИзмерения установим Галку "Получить из входящих данных" для Поля "Владелец".
Также не забудем дописать в ПКО ПриобретениеТоваровУслуг строку кода для выгрузки единиц измерений в ТЧ
//Формируем Новую табличную часть, которую будем помещать во входящие данные
ТЧ = Источник.Товары.Выгрузить();
//Массив Номенклатур для загрузки в колонку ТЧ
МассивНоменклатур = Новый Массив;
МассивЕдиницИзмерения = Новый Массив;
//для того, чтобы не выполнять запрос в цикле, помещаем в запрос всю ТЧ Источника
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СопоставлениеНоменклатурыУППERP.НоменклатураУПП КАК НоменклатураУПП,
| ПриобретениеТоваровУслугТовары.Номенклатура КАК Номенклатура
|ИЗ
| Документ.ПриобретениеТоваровУслуг.Товары КАК ПриобретениеТоваровУслугТовары
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.pll_СопоставлениеНоменклатурыУППERP КАК СопоставлениеНоменклатурыУППERP
| ПО ПриобретениеТоваровУслугТовары.Номенклатура = СопоставлениеНоменклатурыУППERP.НоменклатураERP
|ГДЕ
| ПриобретениеТоваровУслугТовары.Ссылка = &Источник";
Запрос.УстановитьПараметр("Источник", Источник);
РезультатЗапроса = Запрос.Выполнить();
ДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ДетальныеЗаписи.Следующий() Цикл
//проверяем, найдено ли соответствие
Если ЗначениеЗаполнено(ДетальныеЗаписи.НоменклатураУПП) Тогда
МассивНоменклатур.Добавить(ДетальныеЗаписи.НоменклатураУПП);
МассивЕдиницИзмерения.Добавить(ДетальныеЗаписи.Номенклатура.ЕдиницаИзмерения);
Иначе
//Отказ, если ничего не найдено
Сообщить("Для документа " + Источник.Ссылка + " не найдено соответствие номенклатур ERP-УПП. Номенклатура "+ДетальныеЗаписи.Номенклатура.Наименование+
". Выгрузка документа отменена!");
Отказ = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
Если НЕ Отказ Тогда
//помещаем новую табличную часть во входящие данные
ТЧ.Колонки.Удалить("Номенклатура");
ТЧ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.НоменклатураУПП"));
ТЧ.ЗагрузитьКолонку(МассивНоменклатур,"Номенклатура");
ТЧ.Колонки.Добавить("ЕдиницаИзмерения", Новый ОписаниеТипов("СправочникСсылка.УпаковкиЕдиницыИзмерения"));
ТЧ.ЗагрузитьКолонку(МассивЕдиницИзмерения,"ЕдиницаИзмерения");
ВходящиеДанные = Новый Структура;
ВходящиеДанные.Вставить("Товары",ТЧ);
КонецЕсли;
Как видим на рисунке ниже, табличная часть выгрузилась и загрузилась корректно.
Послесловие
Исходящие и Входящие данные -- неотъемлемый функционал КД2. Без него невозможно представить сложных обменов. К сожалению, на Инфостарте я не нашел статьи, в которой бы разбирались эти моменты, потому решил написать самостоятельно.
Для ситуации, если регистр сопоставления расположен в базе-приемнике, а не источнике, рекомендую прочесть эту статью.
Правила обмена разрабатывались в системе Конвертация данных, редакция 2.1 (2.1.8.2) для конфигураций 1С:ERP Управление предприятием 2 (2.4.10.62) и Управление производственным предприятием, редакция 1.3 (1.3.86.3). Справочник НоменклатураУПП и регистр сведений СопоставлениеНоменклатурыУППERP являются самостоятельно добавленными объектами и отсутствуют в типовой версии 1С:ERP Управление предприятием 2.
UPD.
За два с лишним месяца, прошедших с написания статьи, правила обмена были переосмыслены и переписаны с нуля несколько раз. Во многом благодаря комментариям ниже к посту.
Внесенные изменения и отпимизации:
1) Общая оптимизация (не нужно выгружать результат запроса в таблицу значений, обращаться через точку к переменным ссылочного типа и проч.);
2) В случаях, когда входящих и исходящих данных может быть несколько, либо вы дорабатываете уже существующие правила, неплохо бы делать такую вот проверку:
Если ТипЗнч(ВходящиеДанные) <> Тип("Структура") Тогда
ВходящиеДанные = Новый Структура;
КонецЕсли;
Чтобы случайно не "обнулить" уже существующие данные в переменной.
3) Реализована подмена номенклатуры на сопоставленную на уровне запроса, а не его пост-обработкой в таблице значений;
4) "Сообщить()" везде заменено на "ОбщегоНазначения.СообщитьПользователю()";
5) Реализовано разделение табличной части Товары на две табличных части Товары и Услуги в зависимости от типа номенклатуры. (т.к. в УПП две табличных части, а не одна).
Отредактированный пример кода:
ТЗТовары = Новый ТаблицаЗначений();
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| pll_СопоставлениеНоменклатурыУППERP.НоменклатураУПП КАК Номенклатура,
| ХарактеристикиНоменклатурыДополнительныеРеквизиты.Значение КАК Серия,
| ПриобретениеТоваровУслугТовары.Номенклатура.Представление КАК ПредставлениеНоменклатуры,
| ПриобретениеТоваровУслугТовары.Номенклатура.Типноменклатуры КАК ТипНоменклатуры,
| ПриобретениеТоваровУслугТовары.Номенклатура.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
| ПриобретениеТоваровУслугТовары.*
|ИЗ
| Документ.ПриобретениеТоваровУслуг.Товары КАК ПриобретениеТоваровУслугТовары
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ХарактеристикиНоменклатуры.ДополнительныеРеквизиты КАК ХарактеристикиНоменклатурыДополнительныеРеквизиты
| ПО ПриобретениеТоваровУслугТовары.Характеристика = ХарактеристикиНоменклатурыДополнительныеРеквизиты.Ссылка
| И ХарактеристикиНоменклатурыДополнительныеРеквизиты.Свойство = &СвойствоСерия
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.pll_СопоставлениеНоменклатурыУППERP КАК pll_СопоставлениеНоменклатурыУППERP
| ПО ПриобретениеТоваровУслугТовары.Номенклатура = pll_СопоставлениеНоменклатурыУППERP.НоменклатураERP
|ГДЕ
| ПриобретениеТоваровУслугТовары.Ссылка = &Ссылка";
СвойствоСерия = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Серия продукции");
Запрос.УстановитьПараметр("Ссылка", Источник);
Запрос.УстановитьПараметр("СвойствоСерия", СвойствоСерия);
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Отказ = Истина;
КонецЕсли;
МассивУдаляемыхКолонок = Новый Массив;
МассивУдаляемыхКолонок.Добавить("ПредставлениеНоменклатуры");
МассивУдаляемыхКолонок.Добавить("ТипНоменклатуры");
МассивУдаляемыхКолонок.Добавить("Номенклатура1");
МассивУдаляемыхКолонок.Добавить("Серия1");
Для Каждого Колонка из РезультатЗапроса.Колонки Цикл
НайденныйЭлемент = МассивУдаляемыхКолонок.Найти(Колонка.Имя);
Если НайденныйЭлемент = Неопределено Тогда
ТЗТовары.Колонки.Добавить(Колонка.Имя);
КонецЕсли;
КонецЦикла;
ТЗУслуги = ТЗТовары.СкопироватьКолонки();
Выборка = РезультатЗапроса.Выбрать();
ПредставлениеИсточника = Строка(Источник);
Пока Выборка.Следующий() Цикл
Если Выборка.Номенклатура = NULL Тогда
Отказ = Истина;
ЗначениеСобытия = Новый Структура("ИмяСобытия, ПредставлениеУровня, Комментарий, ДатаСобытия");
ЗначениеСобытия.ИмяСобытия = "Обмен данными. Ошибка сопоставления номенклатур";
ЗначениеСобытия.ПредставлениеУровня = "Ошибка";
ЗначениеСобытия.Комментарий = "Для объекта "+ПредставлениеИсточника +" и номенклатуры "+Выборка.ПредставлениеНоменклатуры+
" не найдено сопоставление номенклатур. Объект не выгружен!";
Параметры.СобытияДляЖурналаРегистрации.Добавить(ЗначениеСобытия);
//Сообщаем пользователю
ОбщегоНазначения.СообщитьПользователю(ЗначениеСобытия.Комментарий);
ИначеЕсли Выборка.ТипНоменклатуры = Перечисления.ТипыНоменклатуры.Услуга Тогда
ТЗ = ТЗУслуги;
Иначе
ТЗ = ТЗТовары;
КонецЕсли;
Если НЕ Отказ Тогда
СтрокаТЗ = ТЗ.Добавить();
ЗаполнитьЗначенияСвойств(СтрокаТЗ,Выборка);
КонецЕсли;
КонецЦикла;
Если Не Отказ Тогда
Если ТипЗнч(ВходящиеДанные) <> Тип("Структура") Тогда
ВходящиеДанные = Новый Структура;
КонецЕсли;
ВходящиеДанные.Вставить("Товары", ТЗТовары);
ВходящиеДанные.Вставить("Услуги", ТЗУслуги);
КонецЕсли;