Постановка задачи
Суть задачи в следующем. В базе Источнике есть документ, который при передаче данных в базу Получатель должен формировать документы по каждой строке табличной части Источника.
При этом должна быть обеспечена ссылочная связанность объектов в базах: корректировка документа в Источнике (например, удаление строки ТЧ) должна вызывать корректное изменение в Получателе (лишние документы должны быть удалены).
Для конкретности, опишу задачу целиком.
База Источник-ЕРП 2.5 (кратко, ЕРП)
База Получатель-Бухгалтерия предприятия (кратко, БП - бухгалтерия одной из стран СНГ).
В Источнике есть документ «Производство без Заказа», в документе есть ТЧ Продукция и ТЧ Материалы. Каждая строка ТЧ Материалы связана с ТЧ Продукция через реквизит-ключ Номер строки затрат.
В БП есть документ Отчет производства за смену, который содержит ТЧ продукция, но не содержит ТЧ Материалы. Есть также документ Требование-накладная, который содержит ТЧ Материалы, а также в Шапке содержит Продукцию, на которую пошли материалы.
Для корректного отражения «Производства без заказа» в бухгалтерской программе был выбран вариант разбиения документа на строки. Строка ТЧ Продукции формирует в БП документ Отчет продукции за смену, а также документ «Требование накладная» с выборкой строк «Материалы», которые относятся к выбранной строке Продукции
Исходный документ
Документы в БП
Решение
Поскольку строка документа 1С не является самостоятельной сущностью, создать документ из строки документа можно при наличии идентификатора строки ТЧ. Этот идентификатор может храниться как в сторонней таблице, так и непосредственно в ТЧ. В нашем случае этот идентификатор присутствовал и в ТЧ Продукция и в ТЧ Материалы. (к счастью, 1С в новых конфигурациях добавила реквизит Идентификатор строки почти во все табличные части документов).
Второй момент, дилемма: в какой момент преобразовывать объект XDTO, на этапе формирования исходящего пакета или при обработке входящего сообщения в БП.
Вначале мне казалось, что на стороне приемника это сделать проще и надежнее. Однако, после анализа кода на стороне Приемника, я не нашел простого решения, как вклиниться в код, чтобы разбить один объект XDTO на массив нужных нам объектов.
А вот разбить один объект на массив объектов стороне Источника оказалось несложно.
-
Устанавливаем возможность дополнительной обработки для наших правил конвертации объектов.
&ИзменениеИКонтроль("КоллекцияПравилКонвертации")
Функция БПро_КоллекцияПравилКонвертации(ВерсияФорматаМенеджераОбмена)
// Инициализация таблицы правил конвертации.
ПравилаКонвертации = Новый ТаблицаЗначений;
ПравилаКонвертации.Колонки.Добавить("ИмяПКО", Новый ОписаниеТипов("Строка"));
ПравилаКонвертации.Колонки.Добавить("ОбъектДанных");
ПравилаКонвертации.Колонки.Добавить("ОбъектФормата", Новый ОписаниеТипов("Строка"));
ПравилаКонвертации.Колонки.Добавить("ТипПолученныхДанныхСтрокой", Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(300)));
ПравилаКонвертации.Колонки.Добавить("ИмяТаблицыПолученныхДанных", Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(300)));
ПравилаКонвертации.Колонки.Добавить("ПредставлениеТипаПолученныхДанных", Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(300)));
ПравилаКонвертации.Колонки.Добавить("Свойства", Новый ОписаниеТипов("ТаблицаЗначений"));
ПравилаКонвертации.Колонки.Добавить("ПоляПоиска", Новый ОписаниеТипов("Массив"));
ПравилаКонвертации.Колонки.Добавить("ПоляПредставленияОбъекта", Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(300)));
ПравилаКонвертации.Колонки.Добавить("РеквизитыШапкиПолученныхДанных", Новый ОписаниеТипов("Массив"));
ПравилаКонвертации.Колонки.Добавить("ПриОтправкеДанных", Новый ОписаниеТипов("Строка"));
ПравилаКонвертации.Колонки.Добавить("ПриКонвертацииДанныхXDTO", Новый ОписаниеТипов("Строка"));
ПравилаКонвертации.Колонки.Добавить("ПередЗаписьюПолученныхДанных", Новый ОписаниеТипов("Строка"));
ПравилаКонвертации.Колонки.Добавить("ПослеЗагрузкиВсехДанных", Новый ОписаниеТипов("Строка"));
ПравилаКонвертации.Колонки.Добавить("ПравилоДляГруппыСправочника", Новый ОписаниеТипов("Булево"));
ПравилаКонвертации.Колонки.Добавить("ВариантИдентификации", Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(60)));
ПравилаКонвертации.Колонки.Добавить("АлгоритмПоиска", Новый ОписаниеТипов("Строка"));
ПравилаКонвертации.Колонки.Добавить("Расширения", Новый ОписаниеТипов("Соответствие"));
ПравилаКонвертации.Колонки.Добавить("ПространствоИмен", Новый ОписаниеТипов("Строка"));
ПравилаКонвертации.Колонки.Добавить("РазрешитьСоздаватьОбъектИзСтруктуры");
Если ВерсияФорматаМенеджераОбмена = "1" Тогда
ОписаниеТиповСвойстваТЧ = Новый ОписаниеТипов("Структура");
ПравилаКонвертации.Колонки.Добавить("СвойстваТабличныхЧастейОбработанные", Новый ОписаниеТипов("ТаблицаЗначений"));
Иначе
ОписаниеТиповСвойстваТЧ = Новый ОписаниеТипов("ТаблицаЗначений");
КонецЕсли;
ПравилаКонвертации.Колонки.Добавить("СвойстваТабличныхЧастей", ОписаниеТиповСвойстваТЧ);
#Вставка
ПравилаКонвертации.Колонки.Добавить("БПро_СпецОбработка", Новый ОписаниеТипов("Булево"));
#КонецВставки
Возврат ПравилаКонвертации;
КонецФункции
-
В модуле МенеджерОбменаЧерезУниверсальныйФормат формируем для одного объекта ЕРП два правила конвертации объекта и устанавливаем признак необходимости вызова дополнительного метода (ПравилоКонвертации.БПро_СпецОбработка = Истина) при обработке объекта XDTO также в сами правила: ДобавитьПКО_Документ_ПроизводствоБезЗаказа_Отправка и БПро_Добавить_ПКО_Документ_ПроизводствоБезЗаказаВТребованиеНакладная_Отправка
-
Производство без заказа в Отчет производства за смену
-
Производство без заказа в Требование-накладную
-
&ИзменениеИКонтроль("ДобавитьПКО_Документ_ПроизводствоБезЗаказа_Отправка")
Процедура БПро_ДобавитьПКО_Документ_ПроизводствоБезЗаказа_Отправка(ПравилаКонвертации)
ПравилоКонвертации = ОбменДаннымиXDTOСервер.ИнициализироватьПравилоКонвертацииОбъекта(ПравилаКонвертации);
ПравилоКонвертации.ИмяПКО = "Документ_ПроизводствоБезЗаказа_Отправка";
ПравилоКонвертации.ОбъектДанных = Метаданные.Документы.ПроизводствоБезЗаказа;
ПравилоКонвертации.ПриОтправкеДанных = "ПКО_Документ_ПроизводствоБезЗаказа_Отправка_ПриОтправкеДанных";
ПравилоКонвертации.ОбъектФормата = "Документ.ВыпускПродукции"; //@NON-NLS-1
#Вставка
ПравилоКонвертации.БПро_СпецОбработка = Истина;
#КонецВставки
***********
Процедура БПро_Добавить_ПКО_Документ_ПроизводствоБезЗаказаВТребованиеНакладная_Отправка(ПравилаКонвертации)
ПравилоКонвертации = ОбменДаннымиXDTOСервер.ИнициализироватьПравилоКонвертацииОбъекта(ПравилаКонвертации);
ПравилоКонвертации.ИмяПКО = "БПро_ПКО_Документ_ПроизводствоБезЗаказаВТребованиеНакладная_Отправка";
ПравилоКонвертации.ОбъектДанных = Метаданные.Документы.ПроизводствоБезЗаказа;
ПравилоКонвертации.ПриОтправкеДанных = "БПро_ПКО_Документ_ПередачаМатериаловВПроизводство_Отправка_ПриОтправкеДанных";
ПравилоКонвертации.ОбъектФормата = "Документ.ПередачаМатериаловВПроизводство"; //@NON-NLS-1
ПравилоКонвертации.БПро_СпецОбработка = Истина;
**********
-
В процедуре ВыгрузкаОбъектаВыборки добавляем вставку вызова метода дополнительной обработки структуры XDTO
&ИзменениеИКонтроль("ВыгрузкаОбъектаВыборки")
Процедура БПро_ВыгрузкаОбъектаВыборки(КомпонентыОбмена, Объект, ПравилоОбработки)
ОбъектСсылочногоТипа = (ТипЗнч(Объект) <> Тип("Структура"))
И ОбщегоНазначения.ЭтоОбъектСсылочногоТипа(Объект.Метаданные());
Если (ТипЗнч(Объект) <> Тип("Структура"))
И ПравилоОбработки = Неопределено Тогда
ПолучитьПравилоОбработкиДляОбъекта(КомпонентыОбмена, Объект, ПравилоОбработки);
КонецЕсли;
КомпонентыОбмена.ВыгруженныеОбъекты.Добавить(?(ОбъектСсылочногоТипа, Объект.Ссылка, Объект));
// Отработка ПОД
ИспользованиеПКО = Новый Структура;
Для Каждого ТекущееПКО Из ПравилоОбработки.ИспользуемыеПКО Цикл
ИспользованиеПКО.Вставить(ТекущееПКО, Истина);
КонецЦикла;
ПрерватьОбработку = Ложь;
ВзвестиФлагОшибки = Ложь;
ПриОбработкеПОД(
КомпонентыОбмена,
ПравилоОбработки,
Объект,
ИспользованиеПКО,
ПрерватьОбработку);
Если ПрерватьОбработку Тогда
ВзвестиФлагОшибки = Истина;
КонецЕсли;
Если Не ПрерватьОбработку Тогда
// Отработка ПКО
НесколькоПКО = (ИспользованиеПКО.Количество() > 1);
ЕстьКолонкаОчисткаДанных = КомпонентыОбмена.ПравилаОбработкиДанных.Колонки.Найти("ОчисткаДанных") <> Неопределено;
Для Каждого ТекущееПКО Из ИспользованиеПКО Цикл
ПравилоКонвертации = КомпонентыОбмена.ПравилаКонвертацииОбъектов.Найти(ТекущееПКО.Ключ, "ИмяПКО");
Если ПравилоКонвертации = Неопределено Тогда
// Допустимо указание ПКО, не предназначенного для текущей версии формата данных.
Продолжить;
КонецЕсли;
Если Не ОбъектФорматаПроходитПоФильтруXDTO(КомпонентыОбмена, ПравилоКонвертации.ОбъектФормата) Тогда
Продолжить;
КонецЕсли;
Если Не ТекущееПКО.Значение Тогда
// Если правил конвертации несколько, и некоторые из них не используются -
// необходимо выгрузить удаление объекта на случай если ранее он был выгружен по этим правилам.
Если НесколькоПКО
И ОбъектСсылочногоТипа
И (Не ЕстьКолонкаОчисткаДанных
Или ПравилоОбработки.ОчисткаДанных) Тогда
ВыгрузитьУдаление(КомпонентыОбмена, Объект.Ссылка, ПравилоКонвертации);
КонецЕсли;
Продолжить;
КонецЕсли;
ПропуститьОбработку = Ложь;
Попытка
// 2. Конвертируем Данные в Структуру по правилам конвертации.
ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
ДанныеXDTO = ДанныеXDTOИзДанныхИБ(КомпонентыОбмена, Объект, ПравилоКонвертации, Неопределено);
#Вставка
Если ПравилоКонвертации.БПро_СпецОбработка Тогда
МенеджерОбменаЧерезУниверсальныйФормат.AdditionalInfoВставить(ДанныеXDTO, "ЭтоКорневойДокумент", Истина);
МенеджерОбменаЧерезУниверсальныйФормат.AdditionalInfoВставить(ДанныеXDTO, "КорневойДокумент", XMLСтрока(Объект.Ссылка));
БПро_ВыгрузкаДопОбъектаВыборки(КомпонентыОбмена, ПравилоКонвертации, ПравилоОбработки, ДанныеXDTO, Объект, ПрерватьОбработку, ВзвестиФлагОшибки);
МассивДанныеXDTO = БПро_СпецОбработка(ДанныеXDTO, Объект, ПравилоКонвертации.ИмяПКО);
Сч = 0;
Для каждого ДанныеXDTO Из МассивДанныеXDTO Цикл
Сч = Сч + 1;
МенеджерОбменаЧерезУниверсальныйФормат.AdditionalInfoВставить(ДанныеXDTO, "ЭтоКорневойДокумент", Ложь);
Если Сч < МассивДанныеXDTO.Количество() Тогда
БПро_ВыгрузкаДопОбъектаВыборки(КомпонентыОбмена, ПравилоКонвертации, ПравилоОбработки, ДанныеXDTO, Объект, ПрерватьОбработку, ВзвестиФлагОшибки);
КонецЕсли;
Если ПрерватьОбработку или ВзвестиФлагОшибки Тогда
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
#КонецВставки
Событие = "ДанныеXDTOИзДанныхИБ." + ПравилоКонвертации.ИмяПКО;
ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
ВремяНачала, Событие, Объект, КомпонентыОбмена,
ОбменДаннымиОценкаПроизводительности.ТипСобытияБиблиотека());
Если ДанныеXDTO = Неопределено Тогда
Продолжить;
КонецЕсли;
// 3. Конвертируем Структуру в ОбъектXDTO.
ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер();
СсылкиИзОбъекта = Новый Массив;
ОбъектXDTO = ОбъектXDTOИзДанныхXDTO(КомпонентыОбмена, ДанныеXDTO, ПравилоКонвертации.ТипXDTO, СсылкиИзОбъекта, , ПравилоКонвертации.Расширения);
Событие = "ОбъектXDTOИзДанныхXDTO." + ПравилоКонвертации.ИмяПКО;
ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер(
ВремяНачала, Событие, Объект, КомпонентыОбмена,
ОбменДаннымиОценкаПроизводительности.ТипСобытияБиблиотека());
Исключение
ПропуститьОбработку = Истина;
ВзвестиФлагОшибки = Истина;
ОписаниеОшибки = ОписаниеОшибкиПКО(
КомпонентыОбмена.НаправлениеОбмена,
ПравилоОбработки.Имя,
ПравилоКонвертации.ИмяПКО,
ПредставлениеОбъектаДляПротокола(Объект, ПравилоКонвертации.ОбъектДанных),
ИнформацияОбОшибке());
ЗафиксироватьПроблемуПриОбработкеОбъекта(КомпонентыОбмена,
Объект,
Перечисления.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриОтправкеДанных,
ОписаниеОшибки.ПодробноеПредставление,
ОписаниеОшибки.КраткоеПредставление);
КонецПопытки;
Если Не ПропуститьОбработку Тогда
ОшибкаПроверкиПоСхеме = Ложь;
ОписаниеОшибкиПроверкиПоСхеме = Неопределено;
Контекст = Новый Структура;
Контекст.Вставить("НаправлениеОбмена", КомпонентыОбмена.НаправлениеОбмена);
Контекст.Вставить("ИмяПОД", ПравилоОбработки.Имя);
Контекст.Вставить("ИмяПКО", ПравилоКонвертации.ИмяПКО);
Контекст.Вставить("ПредставлениеОбъекта", ПредставлениеОбъектаДляПротокола(Объект, ПравилоКонвертации.ОбъектДанных));
ПроверитьОбъектXDTOПоСхеме(ОбъектXDTO, ПравилоКонвертации.ТипXDTO, Контекст, ОшибкаПроверкиПоСхеме, ОписаниеОшибкиПроверкиПоСхеме);
Если ОшибкаПроверкиПоСхеме Тогда
ПропуститьОбработку = Истина;
ЗафиксироватьПроблемуПриОбработкеОбъекта(КомпонентыОбмена,
Объект,
Перечисления.ТипыПроблемОбменаДанными.ОшибкаПроверкиСконвертированногоОбъекта,
ОписаниеОшибкиПроверкиПоСхеме.ПодробноеПредставление,
ОписаниеОшибкиПроверкиПоСхеме.КраткоеПредставление);
КонецЕсли;
КонецЕсли;
Если ПропуститьОбработку Тогда
ПрерватьОбработку = Истина;
Продолжить;
КонецЕсли;
ВыгрузитьОбъектыПоСсылке(КомпонентыОбмена, СсылкиИзОбъекта);
// 4. Записываем ОбъектXDTO в XML-файл.
ФабрикаXDTO.ЗаписатьXML(КомпонентыОбмена.ФайлОбмена, ОбъектXDTO);
КонецЦикла;
КонецЕсли;
Если ПрерватьОбработку Тогда
КомпонентыОбмена.НеВыгруженныеОбъекты.Добавить(?(ОбъектСсылочногоТипа, Объект.Ссылка, Объект));
КонецЕсли;
Если ВзвестиФлагОшибки Тогда
КомпонентыОбмена.ФлагОшибки = Истина;
КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка;
КонецЕсли;
КонецПроцедуры
-
Добавляем в AdditionalInfo информацию: корневой ли это объект или преобразованный и ссылку на корневой документ (см скрин выше).
-
Отправляем основной объект (он технический и проводиться на стороне БП не должен!). У него в доп свойствах указываем признак «Корневой» = Истина
-
А также производим нужные нам преобразования объекта: из одного объекта XDTO получаем массив нужных нам «дочерних объектов» XDTO. При этом копируем исходную структуру и преобразуем ее: лишние строки удаляем, в ссылку записываем идентификаторы строк(!), делаем нужную нам нумерацию документов. На данном этапе нам доступны как данные XDTO, так и данные самого объекта Производство без заказа.
Функция БПро_СпецОбработка(ДанныеXDTO, Объект, ИмяПКО)
МассивДанныеXDTO = Новый Массив;
Если ИмяПКО = "Документ_ПроизводствоБезЗаказа_Отправка" Тогда
МассивДанныеXDTO = БПро_СпецОбработка_Документ_ПроизводствоБезЗаказа_Отправка(ДанныеXDTO, Объект, ИмяПКО);
ИначеЕсли ИмяПКО = "БПро_ПКО_Документ_ПроизводствоБезЗаказаВТребованиеНакладная_Отправка" Тогда
МассивДанныеXDTO = БПро_СпецОбработка_Документ_ПроизводствоБезЗаказаВТребованиеНакладная_Отправка(ДанныеXDTO, Объект, ИмяПКО);
ИначеЕсли ИмяПКО = "Документ_ПересортицаВСборку" Тогда
МассивДанныеXDTO = БПро_СпецОбработка_Документ_ПересортицаВСборку(ДанныеXDTO, Объект, ИмяПКО);
КонецЕсли;
Возврат МассивДанныеXDTO;
КонецФункции
Функция БПро_СпецОбработка_Документ_ПроизводствоБезЗаказа_Отправка(ДанныеXDTO, Объект, ИмяПКО)
ГруппыЗатрат = Новый Соответствие;
МассивДанныеXDTO = Новый Массив;
ЕстьПродукция = ДанныеXDTO.Свойство("Продукция");
ЕстьМатериалы = ДанныеXDTO.Свойство("Материалы");
Если ЕстьПродукция Тогда
Счетчик = 0;
Для каждого СтрокаПродукция Из ДанныеXDTO.Продукция Цикл
Счетчик = Счетчик + 1;
НовыеДанныеXDTO = ГруппыЗатрат.Получить(СтрокаПродукция.НомерСтрокиДокумента);
НомерСтрокиДокумента = СтрокаПродукция.НомерСтрокиДокумента;
Если НовыеДанныеXDTO = Неопределено Тогда
НовыеДанныеXDTO = ОбщегоНазначения.СкопироватьРекурсивно(ДанныеXDTO);
НовыеДанныеXDTO.AdditionalInfo.ТоварыДопИнф = Новый Массив;
НовыеДанныеXDTO.AdditionalInfo.Материалы = Новый Массив;
Если ЕстьПродукция Тогда
НовыеДанныеXDTO.Продукция.Очистить();
КонецЕсли;
Если ЕстьМатериалы Тогда
НовыеДанныеXDTO.Материалы.Очистить();
КонецЕсли;
НовыеДанныеXDTO.КлючевыеСвойства.Ссылка = XMLЗначение(Тип("ДокументСсылка.ПроизводствоБезЗаказа"), СтрокаПродукция.ИдентификаторСтроки);
НовыеДанныеXDTO.КлючевыеСвойства.Дата = ДатаПроизводствоБезЗаказа(ДанныеXDTO.КлючевыеСвойства.Дата, Ложь);
НовыеДанныеXDTO.КлючевыеСвойства.Номер = СтрШаблон("00%1.%2", Сред(НовыеДанныеXDTO.КлючевыеСвойства.Номер, 6),
Прав("00000000" + Формат(Счетчик,"ЧГ=0"), 2));
КонецЕсли;
НоваяСтрока = НовыеДанныеXDTO.Продукция.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаПродукция);
Для каждого ЭлМасс Из ДанныеXDTO.AdditionalInfo.ТоварыДопИнф Цикл
Если ЭлМасс.НомерГруппыЗатрат = НомерСтрокиДокумента Тогда
НовыеДанныеXDTO.AdditionalInfo.ТоварыДопИнф.Добавить(ОбщегоНазначения.СкопироватьРекурсивно(ЭлМасс));
Прервать;
КонецЕсли;
КонецЦикла;
ГруппыЗатрат.Вставить(НомерСтрокиДокумента, НовыеДанныеXDTO);
КонецЦикла;
КонецЕсли;
Для каждого КиЗ Из ГруппыЗатрат Цикл
МассивДанныеXDTO.Вставить(0, КиЗ.Значение);
КонецЦикла;
Возврат МассивДанныеXDTO;
КонецФункции
Функция БПро_СпецОбработка_Документ_ПроизводствоБезЗаказаВТребованиеНакладная_Отправка(ДанныеXDTO, Объект, ИмяПКО)
ГруппыЗатрат = Новый Соответствие;
МассивДанныеXDTO = Новый Массив;
ЕстьТовары = ДанныеXDTO.Свойство("Товары");
Если ЕстьТовары Тогда
Счетчик = 0;
Для каждого СтрокаТовары Из ДанныеXDTO.Товары Цикл
НомерСтрокиДокумента = СтрокаТовары.НомерСтрокиДокумента;
НовыеДанныеXDTO = ГруппыЗатрат.Получить(НомерСтрокиДокумента);
Если НовыеДанныеXDTO = Неопределено Тогда
Счетчик = Счетчик + 1;
НовыеДанныеXDTO = ОбщегоНазначения.СкопироватьРекурсивно(ДанныеXDTO);
НовыеДанныеXDTO.AdditionalInfo.ТоварыДопИнф = Новый Массив;
НовыеДанныеXDTO.AdditionalInfo.Материалы = Новый Массив;
НовыеДанныеXDTO.Товары.Очистить();
Для каждого ЭлМасс Из ДанныеXDTO.AdditionalInfo.ТоварыДопИнф Цикл
Если ЭлМасс.НомерГруппыЗатрат = НомерСтрокиДокумента Тогда
НовыеДанныеXDTO.КлючевыеСвойства.Ссылка = XMLЗначение(Тип("ДокументСсылка.ПроизводствоБезЗаказа"), ЭлМасс.ИдентификаторСтроки);
НовыеДанныеXDTO.КлючевыеСвойства.Дата = ДатаПроизводствоБезЗаказа(ДанныеXDTO.КлючевыеСвойства.Дата, Истина);
НовыеДанныеXDTO.КлючевыеСвойства.Номер = СтрШаблон("00%1.%2", Сред(НовыеДанныеXDTO.КлючевыеСвойства.Номер, 6),
Прав("00000000" + Формат(Счетчик,"ЧГ=0"), 2));
НовыеДанныеXDTO.AdditionalInfo.Вставить("ПроизводствоБезЗаказа",
Новый Структура("Ссылка, НомерГруппыЗатрат, Номенклатура, СчетаГФУ",
ЭлМасс.ИдентификаторСтроки,
НомерСтрокиДокумента,
ЭлМасс.Номенклатура,
ЭлМасс.СчетаГФУ));
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Для каждого ЭлМасс Из ДанныеXDTO.AdditionalInfo.Материалы Цикл
Если ЭлМасс.НомерГруппыЗатрат = НомерСтрокиДокумента Тогда
НовыеДанныеXDTO.AdditionalInfo.ТоварыДопИнф.Добавить(ОбщегоНазначения.СкопироватьРекурсивно(ЭлМасс));
КонецЕсли;
КонецЦикла;
НоваяСтрока = НовыеДанныеXDTO.Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТовары);
ГруппыЗатрат.Вставить(НомерСтрокиДокумента, НовыеДанныеXDTO);
КонецЦикла;
КонецЕсли;
Для каждого КиЗ Из ГруппыЗатрат Цикл
МассивДанныеXDTO.Вставить(0, КиЗ.Значение);
КонецЦикла;
Возврат МассивДанныеXDTO;
КонецФункции
-
Далее система работает типовым образом: в пакет уходит массив объектов Производство без заказа, и массив объектов Требование-накладная.
- Единственный момент - пришлось добавить еще один дополнительный метод БПро_ВыгрузкаДопОбъектаВыборки(КомпонентыОбмена, ПравилоКонвертации, ПравилоОбработки, ДанныеXDTO, Объект, ПрерватьОбработку, ВзвестиФлагОшибки), аналогичный методу ВыгрузкаОбъектаВыборки, который не позволял выгружать массив элементов ДанныеXDTO, а строго преобразовывал один объект. Это пришлось добавить.
Процедура БПро_ВыгрузкаДопОбъектаВыборки(КомпонентыОбмена, ПравилоКонвертации, ПравилоОбработки, ДанныеXDTO, Объект, ПрерватьОбработку, ВзвестиФлагОшибки) ВзвестиФлагОшибки = Ложь; Если ПрерватьОбработку Тогда ВзвестиФлагОшибки = Истина; КонецЕсли; Если Не ПрерватьОбработку Тогда // Отработка ПКО Если Не ОбъектФорматаПроходитПоФильтруXDTO(КомпонентыОбмена, ПравилоКонвертации.ОбъектФормата) Тогда Возврат; КонецЕсли; ПропуститьОбработку = Ложь; Попытка // 2. Конвертируем Данные в Структуру по правилам конвертации. ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер(); Событие = "ДанныеXDTOИзДанныхИБ." + ПравилоКонвертации.ИмяПКО; ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер( ВремяНачала, Событие, Объект, КомпонентыОбмена, ОбменДаннымиОценкаПроизводительности.ТипСобытияБиблиотека()); Если ДанныеXDTO = Неопределено Тогда Возврат; КонецЕсли; // 3. Конвертируем Структуру в ОбъектXDTO. ВремяНачала = ОбменДаннымиОценкаПроизводительности.НачатьЗамер(); СсылкиИзОбъекта = Новый Массив; ОбъектXDTO = ОбъектXDTOИзДанныхXDTO(КомпонентыОбмена, ДанныеXDTO, ПравилоКонвертации.ТипXDTO, СсылкиИзОбъекта, , ПравилоКонвертации.Расширения); Событие = "ОбъектXDTOИзДанныхXDTO." + ПравилоКонвертации.ИмяПКО; ОбменДаннымиОценкаПроизводительности.ЗавершитьЗамер( ВремяНачала, Событие, Объект, КомпонентыОбмена, ОбменДаннымиОценкаПроизводительности.ТипСобытияБиблиотека()); Исключение ПропуститьОбработку = Истина; ВзвестиФлагОшибки = Истина; ОписаниеОшибки = ОписаниеОшибкиПКО( КомпонентыОбмена.НаправлениеОбмена, ПравилоОбработки.Имя, ПравилоКонвертации.ИмяПКО, ПредставлениеОбъектаДляПротокола(Объект, ПравилоКонвертации.ОбъектДанных), ИнформацияОбОшибке()); ЗафиксироватьПроблемуПриОбработкеОбъекта(КомпонентыОбмена, Объект, Перечисления.ТипыПроблемОбменаДанными.ОшибкаВыполненияКодаОбработчиковПриОтправкеДанных, ОписаниеОшибки.ПодробноеПредставление, ОписаниеОшибки.КраткоеПредставление); КонецПопытки; Если Не ПропуститьОбработку Тогда ОшибкаПроверкиПоСхеме = Ложь; ОписаниеОшибкиПроверкиПоСхеме = Неопределено; Контекст = Новый Структура; Контекст.Вставить("НаправлениеОбмена", КомпонентыОбмена.НаправлениеОбмена); Контекст.Вставить("ИмяПОД", ПравилоОбработки.Имя); Контекст.Вставить("ИмяПКО", ПравилоКонвертации.ИмяПКО); Контекст.Вставить("ПредставлениеОбъекта", ПредставлениеОбъектаДляПротокола(Объект, ПравилоКонвертации.ОбъектДанных)); ПроверитьОбъектXDTOПоСхеме(ОбъектXDTO, ПравилоКонвертации.ТипXDTO, Контекст, ОшибкаПроверкиПоСхеме, ОписаниеОшибкиПроверкиПоСхеме); Если ОшибкаПроверкиПоСхеме Тогда ПропуститьОбработку = Истина; ЗафиксироватьПроблемуПриОбработкеОбъекта(КомпонентыОбмена, Объект, Перечисления.ТипыПроблемОбменаДанными.ОшибкаПроверкиСконвертированногоОбъекта, ОписаниеОшибкиПроверкиПоСхеме.ПодробноеПредставление, ОписаниеОшибкиПроверкиПоСхеме.КраткоеПредставление); КонецЕсли; КонецЕсли; Если ПропуститьОбработку Тогда ПрерватьОбработку = Истина; Возврат; КонецЕсли; ВыгрузитьОбъектыПоСсылке(КомпонентыОбмена, СсылкиИзОбъекта); // 4. Записываем ОбъектXDTO в XML-файл. ФабрикаXDTO.ЗаписатьXML(КомпонентыОбмена.ФайлОбмена, ОбъектXDTO); КонецЕсли; Если ПрерватьОбработку Тогда КомпонентыОбмена.НеВыгруженныеОбъекты.Добавить(Объект.Ссылка); КонецЕсли; Если ВзвестиФлагОшибки Тогда КомпонентыОбмена.ФлагОшибки = Истина; КомпонентыОбмена.СостояниеОбменаДанными.РезультатВыполненияОбмена = Перечисления.РезультатыВыполненияОбмена.Ошибка; КонецЕсли; КонецПроцедуры
Обеспечение ссылочной целостности.
Обеспечение ссылочной связанности объектов в БП выполняется целиком на стороне БП: при получении всех документов:
-
Записываем документы. Если объект пришел с признаком «Корневой»= да, то его не проводим, но записываем в доп свойства этот признак. Также идентификатор самого корневого документа записываем в свойство документа (далее объясню зачем).
Процедура ОтложеннаяОбработка_ВыпускПродукции(Объект, ПараметрыКонвертации, ОбъектМодифицирован)
БПро_ОбновитьРеквизитыОбщиеТребования(Объект);
УстановитьДопСвойствоИзAdditionalInfo(Объект, "НомерERP");
УстановитьДопСвойствоИзAdditionalInfo(Объект, "ЭтоКорневойДокумент");
УстановитьДопСвойствоИзAdditionalInfo(Объект, "КорневойДокумент");
*********
&ИзменениеИКонтроль("ОтложеннаяОбработка_ТребованиеНакладная")
Процедура БПро_ОтложеннаяОбработка_ТребованиеНакладная(Объект, ПараметрыКонвертации, ОбъектМодифицирован)
******
#Вставка
БПро_ОбновитьРеквизитыОбщиеТребования(Объект);
УстановитьДопСвойствоИзAdditionalInfo(Объект, "НомерERP");
УстановитьДопСвойствоИзAdditionalInfo(Объект, "ЭтоКорневойДокумент");
УстановитьДопСвойствоИзAdditionalInfo(Объект, "КорневойДокумент");
#КонецВставки
КонецПроцедуры
-
Если на стороне ЕРП документ сняли с проведения (или удалили) в БП придет объект «УдалениеОбъекта» со ссылкой на удаляемый объект. В этом случае при получении мы получаем идентификатор удаляемого корневого документа и запросом получаем весь массив дочерних документов по признаку «Корневой документ»
Функция СписокОбъектовПоКорневойСсылке(КорневойДокумент, ФильтрПоВидуДокумента = Неопределено) Экспорт
Запрос = Новый Запрос("ВЫБРАТЬ
| ДополнительныеСведения.Объект КАК Ссылка
|ИЗ
| РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
|ГДЕ
| ДополнительныеСведения.Значение = &КорневойДокумент
| И (&НетФильтраПоВидуДокумента
| ИЛИ ДополнительныеСведения.Объект ССЫЛКА Документ.РеализацияТоваровУслуг)
| И ДополнительныеСведения.Свойство.ИдентификаторДляФормул = &ИдентификаторДляФормул");
Если ЗначениеЗаполнено(ФильтрПоВидуДокумента) Тогда
Запрос.Текст = СтрЗаменить(Запрос.Текст, "Документ.РеализацияТоваровУслуг", "Документ."+ФильтрПоВидуДокумента);
КонецЕсли;
Запрос.УстановитьПараметр("НетФильтраПоВидуДокумента", не ЗначениеЗаполнено(ФильтрПоВидуДокумента));
Запрос.УстановитьПараметр("КорневойДокумент", КорневойДокумент);
Запрос.УстановитьПараметр("ИдентификаторДляФормул", "КорневойДокумент");
ТабРез = Запрос.Выполнить().Выгрузить();
Возврат ТабРез.ВыгрузитьКолонку("Ссылка");
КонецФункции // ()
&После("ДополнитьСписокОбъектовКУдалению")
Процедура БПро_ДополнитьСписокОбъектовКУдалению(КомпонентыОбмена, ТипДанных, УникальныйИдентификатор, МассивОбъектовКУдалению)
Если ТипДанных = Тип("ДокументСсылка.ТребованиеНакладная") Тогда
МассивДопОбъектовКУдалению = СписокОбъектовПоКорневойСсылке(УникальныйИдентификатор, "ТребованиеНакладная");
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(МассивОбъектовКУдалению,МассивДопОбъектовКУдалению, Истина);
ИначеЕсли ТипДанных = Тип("ДокументСсылка.ОтчетПроизводстваЗаСмену") Тогда
МассивДопОбъектовКУдалению = СписокОбъектовПоКорневойСсылке(УникальныйИдентификатор, "ОтчетПроизводстваЗаСмену");
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(МассивОбъектовКУдалению,МассивДопОбъектовКУдалению, Истина);
КонецЕсли;
КонецПроцедуры
&После("ПрочитатьСообщениеОбмена")
Процедура БПро_ПрочитатьСообщениеОбмена(КомпонентыОбмена, Результаты, ТаблицыДляЗагрузки, РежимАнализа)
// Вставить содержимое метода.
Если Не РежимАнализа Тогда
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(Результаты.МассивОбъектовКУдалению,КомпонентыОбмена.ПомеченныеНаУдалениеОбъекты, Истина);
КонецЕсли;
КонецПроцедуры
-
Если на стороне ЕРП документ изменили (например, изменили табличную часть), то в БП нам придет новый набор объектов. При этом нам надо все уже существующие «дочерние» объекты» надо пометить на удаление, а затем их заново загрузить. Для этого достаточно один раз вызвать соответствующий метод при загрузке именно «корневого» объекта.
Процедура ПКО_Документ_ВыпускПродукции_Получение_ПередЗаписьюПолученныхДанных(ПолученныеДанные, ДанныеИБ, КонвертацияСвойств, КомпонентыОбмена)
**************
Если AdditionalInfo<>Неопределено Тогда
УстановитьДопИнф_ТЧ(ПолученныеДанные.Продукция, AdditionalInfo, Истина, "ОтчетПроизводстваЗаСмену", Неопределено);
ЭтоКорневойДокумент = AdditionalInfo.Свойство("ЭтоКорневойДокумент") и AdditionalInfo.ЭтоКорневойДокумент;
Если ЭтоКорневойДокумент Тогда
ОбработатьКорневойДокумент(ПолученныеДанные, AdditionalInfo, КомпонентыОбмена, "ОтчетПроизводстваЗаСмену");
КонецЕсли;
Если ПолученныеДанные.Продукция.Количество()>0 Тогда
ГруппаАналитическогоУчета = НоменклатурнаяГруппаПоНаименованиюНоменклатуры(ПолученныеДанные.Продукция[0].Номенклатура);
ПолученныеДанные.НоменклатурнаяГруппа = ГруппаАналитическогоУчета;
КонецЕсли;
КонецЕсли;
***************
КонецПроцедуры
&ИзменениеИКонтроль("ПКО_Документ_ТребованиеНакладная_Получение_ПередЗаписьюПолученныхДанных")
Процедура БПро_ПКО_Документ_ТребованиеНакладная_Получение_ПередЗаписьюПолученныхДанных(ПолученныеДанные, ДанныеИБ, КонвертацияСвойств, КомпонентыОбмена)
*****
#Вставка
ПолученныеДанные.УчитыватьКПН = Истина;
ПолученныеДанные.ВидУчетаНУ = Справочники.ВидыУчетаНУ.НУ;
AdditionalInfo = Неопределено; ПроизводствоБезЗаказа = Неопределено; ГруппаАналитическогоУчета = Неопределено;
Если ПолученныеДанные.ДополнительныеСвойства.Свойство("AdditionalInfo", AdditionalInfo) Тогда
ЕстьПроизводствоБезЗаказа = AdditionalInfo.Свойство("ПроизводствоБезЗаказа", ПроизводствоБезЗаказа);
ЭтоКорневойДокумент = AdditionalInfo.Свойство("ЭтоКорневойДокумент") и AdditionalInfo.ЭтоКорневойДокумент;
Если ЭтоКорневойДокумент Тогда
ОбработатьКорневойДокумент(ПолученныеДанные, AdditionalInfo, КомпонентыОбмена, "ТребованиеНакладная");
КонецЕсли;
******
#КонецВставки
********
КонецПроцедуры
Таким образом задачу мы решили: алгоритм преобразования происходит на источнике, ссылочная целостность обеспечена не типовым, но надежным способом.
Разработка велась на Платформе 1С:Предприятие 8.3 (8.3.24.1691), ERP(2.5.17.140) Формат ED - http://v8.1c.ru/edi/edi_stnd/EnterpriseData/1.8
Если полезно - плюсуйте)