При работе с технологией Конвертации данных 3.0 (КД 3.0) и обменом через универсальный формат EnterpriseData разработчики часто сталкиваются с жестким ограничением: формат обмена содержит только типовой набор реквизитов и табличных частей. Но что делать, если в вашей конфигурации-источнике есть уникальная табличная часть (например, номера КиЗ, специфическая маркировка, дополнительная аналитика), которую жизненно важно перенести в конфигурацию-приемник, а в стандартном XDTO-пакете формата ее просто нет?
В этой статье мы подробно разберем, как обойти это ограничение. Мы научимся использовать встроенный «багажник» формата в виде свойства AdditionalInfo, разберем двухэтапный процесс загрузки данных в БСП (Библиотеке Стандартных Подсистем) и рассмотрим изящный лайфхак автоматического заполнения табличных частей.
В Конвертации данных 2.1 мы привыкли к тому, что в процессе загрузки у нас есть прямой доступ к создаваемому объекту базы данных, и мы можем делать с ним все что угодно. В КД 3.0 архитектура принципиально иная. Процесс импорта разделен на два изолированных этапа:
ПриКонвертацииДанныхXDTO у нас есть доступ к входящему XDTO-пакету, но физического объекта в базе данных (документа или справочника) еще не существует. Мы можем оперировать только структурой ПолученныеДанные.ПередЗаписьюПолученныхДанных, где уже создается объект информационной базы, но прямого доступа к исходному XML/XDTO у нас здесь уже нет.Поэтому наша главная задача — красиво передать неформатные данные с первого этапа на второй.
---
Для передачи нетиповых данных мы задействуем стандартный реквизит формата AdditionalInfo (Дополнительная информация), который присутствует практически у каждого объекта EnterpriseData. Это свойство представляет собой произвольную структуру, куда можно упаковать любые данные.
Рассмотрим ситуацию на примере переноса номеров КиЗ (контрольно-идентификационных знаков) для документа поступления. Перейдем в ПКО (Правило конвертации объектов) нашего документа и в обработчике ПриОтправкеДанных напишем следующий код:
// Создаем массив структур, в который поместим строки нашей нетиповой ТЧ
МассивСтрокТЧ = Новый Массив;
Для Каждого СтрокаТЧ Из ДанныеИБ.НомераКиЗ Цикл
СтруктураСтроки = Новый Структура;
СтруктураСтроки.Вставить("НомерКиЗ", СтрокаТЧ.НомерКиЗ);
СтруктураСтроки.Вставить("НоменклатураКод", СтрокаТЧ.Номенклатура.Код);
МассивСтрокТЧ.Добавить(СтруктураСтроки);
КонецЦикла;
// Инициализируем структуру AdditionalInfo в объекте формата
ДополнительнаяИнформация = Новый Структура;
ДополнительнаяИнформация.Вставить("ТаблицаКиЗ", МассивСтрокТЧ);
// Помещаем структуру в XDTO-данные для отправки
ДанныеXDTO.Вставить("AdditionalInfo", ДополнительнаяИнформация);
Важное примечание: Передавать ссылки напрямую через AdditionalInfo не рекомендуется, так как в базе-приемнике ссылки источника превратятся в «битые». Передавайте уникальные идентификаторы (UID), коды или ИНН/КПП для последующего поиска в приемнике.
---
При загрузке в базу-приемник первым делом отрабатывает обработчик ПриКонвертацииДанныхXDTO. Физического документа в базе еще нет, но нам нужно перехватить переданный массив и положить его во временный «карман» объекта.
Этим карманом выступает свойство ПолученныеДанные.ДополнительныеСвойства. Пропишем там следующий алгоритм:
// Проверяем наличие заполненного AdditionalInfo во входящих данных
Если ДанныеXDTO.Свойство("AdditionalInfo") И ТипЗнч(ДанныеXDTO.AdditionalInfo) = Тип("Структура") Тогда
// Проверяем, пришла ли наша кастомная таблица
Если ДанныеXDTO.AdditionalInfo.Свойство("ТаблицаКиЗ") Тогда
// Перекладываем данные в ДополнительныеСвойства объекта-контейнера
ПолученныеДанные.ДополнительныеСвойства.Вставить("ВременнаяТаблицаКиЗ", ДанныеXDTO.AdditionalInfo.ТаблицаКиЗ);
КонецЕсли;
// Если нужно передать другие реквизиты шапки, которых нет в формате:
Если ДанныеXDTO.AdditionalInfo.Свойство("НетиповойРеквизитШапки") Тогда
ПолученныеДанные.ДополнительныеСвойства.Вставить("НетиповойРеквизитШапки", ДанныеXDTO.AdditionalInfo.НетиповойРеквизитШапки);
КонецЕсли;
КонецЕсли;
---
Теперь переходим к финальному этапу. Объект сопоставлен или создан заново, все его стандартные реквизиты заполнены механизмами БСП. Нам остается лишь перенести наши данные из временного хранилища ДополнительныеСвойства непосредственно в табличную часть документа.
Сделать это нужно в обработчике ПКО ПередЗаписьюПолученныхДанных. Проанализируем пример кода:
// 1. Пытаемся извлечь наши данные из "багажника"
ДанныеТаблицы = Неопределено;
Если НЕ ПолученныеДанные.ДополнительныеСвойства.Свойство("ВременнаяТаблицаКиЗ", ДанныеТаблицы) Тогда
Возврат; // Если данных нет, ничего не делаем
КонецЕсли;
// 2. Определяем объект для заполнения.
// Если документ уже был в ИБ, БСП передает его в параметре ДанныеИБ.
// Но безопаснее и правильнее заполнять ТЧ именно у ПолученныеДанные,
// так как БСП сама синхронизирует эти свойства перед непосредственной записью.
ДокументОбъект = ПолученныеДанные;
// Очищаем существующую табличную часть в приемнике перед перезаполнением
ДокументОбъект.НомераКиЗ.Очистить();
// 3. Заполняем табличную часть данными
Для Каждого СтрокаДанных Из ДанныеТаблицы Цикл
// Ищем номенклатуру по коду, который мы передали
СсылкаНаНоменклатуру = Справочники.Номенклатура.НайтиПоКоду(СтрокаДанных.НоменклатураКод);
Если СсылкаНаНоменклатуру.Пустая() Тогда
// Обработка ситуации, если номенклатура не найдена (например, пишем лог или пропускаем)
Продолжить;
КонецЕсли;
// Добавляем новую строку в табличную часть документа-приемника
НоваяСтрока = ДокументОбъект.НомераКиЗ.Добавить();
НоваяСтрока.НомерКиЗ = СтрокаДанных.НомерКиЗ;
НоваяСтрока.Номенклатура = СсылкаНаНоменклатуру;
КонецЦикла;
---
Существует малоизвестный встроенный механизм в БСП, который позволяет значительно сократить объем кода на стороне приемника. Если структура колонок табличной части в источнике совпадает со структурой колонок ТЧ в приемнике, вам не обязательно вручную обходить строки в обработчике ПередЗаписьюПолученныхДанных.
Достаточно в обработчике ПриКонвертацииДанныхXDTO поместить массив структур в ПолученныеДанные.ДополнительныеСвойства под ключом, имя которого в точности совпадает с именем табличной части объекта конфигурации-приемника.
Посмотрим на пример упрощенного кода в ПриКонвертацииДанныхXDTO:
// Имя ключа "НомераКиЗ" в точности соответствует имени табличной части документа в приемнике
Если ДанныеXDTO.AdditionalInfo.Свойство("ТаблицаКиЗ") Тогда
ПолученныеДанные.ДополнительныеСвойства.Вставить("НомераКиЗ", ДанныеXDTO.AdditionalInfo.ТаблицаКиЗ);
КонецЕсли;
При сборке объекта система сама обнаружит совпадение имени ключа в ДополнительныеСвойства с именем табличной части объекта конфигурации и автоматически заполнит табличную часть строками из переданного массива. Важно лишь, чтобы ключи структур внутри массива соответствовали именам реквизитов этой табличной части.
---
Иногда разработчики сталкиваются со следующей проблемой: при переносе справочника «Контрагенты» напрямую, заполненное AdditionalInfo отрабатывает отлично. Но если переносится документ, содержащий реквизит «Контрагент», то в процедуре ПриКонвертацииДанныхXDTO для этого контрагента поле AdditionalInfo оказывается пустым.
Выясним причину этого поведения. Согласно концепции EnterpriseData, при выгрузке документа все его ссылочные реквизиты (справочники) выгружаются не как полноценные объекты, а как ключевые свойства (например: УИД, Код, Наименование, ИНН) для быстрой идентификации. Ссылочный объект в составе документа не выгружается целиком, поэтому и его AdditionalInfo игнорируется.
Решение этой проблемы:
AdditionalInfo самого документа, а при загрузке документа находите контрагента в базе и дозаполняйте его реквизиты.---
Мы подробно разобрали универсальную методику обхода ограничений формата EnterpriseData в Конвертации данных 3.0. Использование связки AdditionalInfo на стороне источника и ДополнительныеСвойства на стороне приемника позволяет реализовать интеграцию любой сложности без необходимости постоянного изменения XDTO-пакетов обмена. Используйте эти приемы в своих проектах, чтобы сделать обмен данными гибким и надежным!