Как передать данные, отсутствующие в стандартном формате EnterpriseData, и расширить перечисления при обмене в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Мы часто сталкиваемся с задачей передачи данных между базами 1С с использованием формата EnterpriseData (ED) — для этого подойдёт настройка двусторонней синхронизации 1С через расширения. Особенностью формата является его стандартизация, что иногда создает сложности, когда нам необходимо передать свойства, не предусмотренные типовым ED-пакетом, или добавить новые значения в стандартные перечисления. В этом руководстве мы подробно разберем, как эффективно решать эти задачи, применяя различные подходы в зависимости от сложности и характера передаваемых данных.

Передача данных, отсутствующих в объекте формата-приемника

Мы рассмотрим несколько подходов к передаче данных, для которых нет прямого соответствия в объекте формата-приемника. Важно понимать, что каждый из них имеет свои области применения и преимущества.

Метод 1: Использование свойства AdditionalInfo для простых типов

Это один из наиболее распространенных и гибких способов, когда требуется передать нетиповые данные. В то время как для старых методологий часто используется универсальный обмен данными XML 8.2 и 8.3 (дополненный) (поможет универсальный перенос и обмен данными между базами 1С), в ED свойство AdditionalInfo позволяет нам включить в передаваемый объект произвольные данные, которые затем могут быть обработаны на стороне приемника.

  1. На стороне источника: Передача идентификатора или простого значения

Предположим, нам нужно передать ссылку на объект, например, на организацию (Справочник.Организации), но в объекте формата-приемника отсутствует свойство Владелец. В таком случае мы можем передать уникальный идентификатор этой организации через AdditionalInfo. Это может быть как уникальный идентификатор 1С (ГУИД), так и любой другой ключ, позволяющий однозначно найти объект.

Например, в алгоритме выгрузки или в обработчике события, мы можем добавить идентификатор организации следующим образом. Мы получаем уникальный идентификатор владельца из исходного объекта и помещаем его в свойство AdditionalInfo передаваемого XDTO-объекта.


// Предположим, у нас есть ссылка на объект-источник ДокументИсточник
// и мы хотим передать Владельца этого документа, которого нет в XDTO-формате приемника.

// 1. Получаем уникальный идентификатор Владельца из объекта-источника.
// УникальныйИдентификатор() возвращает УникальныйИдентификатор, который удобно перевести в строку для передачи.
ИдентификаторВладельца = ДокументИсточник.Владелец.УникальныйИдентификатор; 

// 2. Инициализируем AdditionalInfo, если оно еще не создано.
// AdditionalInfo представляет собой структуру, в которую мы можем добавлять произвольные данные.
Если ДанныеXDTO.AdditionalInfo = Неопределено Тогда
    ДанныеXDTO.AdditionalInfo = Новый Структура;
КонецЕсли;

// 3. Добавляем идентификатор в AdditionalInfo с ключом "ИдентификаторОрганизацииВладельца".
// Важно использовать понятные ключи для легкой идентификации данных на приемнике.
ДанныеXDTO.AdditionalInfo.Вставить("ИдентификаторОрганизацииВладельца", Строка(ИдентификаторВладельца));

Здесь мы создаем структуру в AdditionalInfo и помещаем туда строковое представление уникального идентификатора. Важно отметить, что AdditionalInfo может содержать произвольные структуры, массивы или простые типы данных.

После получения данных на стороне приемника, мы можем прочитать переданный идентификатор и использовать его для поиска нужного объекта в нашей информационной базе. Это обычно происходит в обработчиках событий правил конвертации объектов (ПКО), таких как ПриКонвертацииДанныхXDTO или ПередЗаписьюПолученныхДанных, которые позволяют выполнять дополнительную логику после получения данных, но перед их записью в базу.

Пример кода для стороны приемника. Мы извлекаем строковый идентификатор из AdditionalInfo, преобразуем его в объект УникальныйИдентификатор и затем используем метод ПолучитьСсылку() для поиска соответствующего объекта в справочнике "Организации".


// ПолученныеДанные - это объект 1С, который мы собираемся записать в базу-приемник.
// ДанныеXDTO - это полученный XDTO-объект, содержащий данные из источника.

// 1. Проверяем наличие AdditionalInfo и нужного свойства в нем.
Если ДанныеXDTO.AdditionalInfo <> Неопределено И ДанныеXDTO.AdditionalInfo.Свойство("ИдентификаторОрганизацииВладельца") Тогда
    СтрокаИдентификатора = ДанныеXDTO.AdditionalInfo.ИдентификаторОрганизацииВладельца;
        
    // 2. Преобразуем строковый идентификатор в объект УникальныйИдентификатор.
    УИД_Организации = Новый УникальныйИдентификатор(СтрокаИдентификатора);
        
    // 3. Получаем ссылку на элемент справочника "Организации" по УИД.
    // Метод ПолучитьСсылку() возвращает ссылку на существующий объект, если он найден по УИД.
    СсылкаОрганизация = Справочники.Организации.ПолучитьСсылку(УИД_Организации);
        
    // 4. Если ссылка найдена, устанавливаем ее в свойство приемника.
    Если ЗначениеЗаполнено(СсылкаОрганизация) Тогда
        ПолученныеДанные.Владелец = СсылкаОрганизация;
    Иначе
        // 5. Обрабатываем случай, когда организация не найдена.
        // В зависимости от логики обмена, можно создать новую организацию,
        // вывести сообщение об ошибке или пропустить присвоение.
        Сообщить("Организация с УИД " + СтрокаИдентификатора + " не найдена на стороне приемника. " + 
                 "Требуется ручная сверка или дополнительная логика создания.", СтатусСообщения.Важное);
    КонецЕсли;
КонецЕсли;

Как мы видим, этот подход позволяет гибко обрабатывать данные, даже если они не представлены напрямую в XDTO-формате. Он хорошо подходит для передачи идентификаторов, кодов или наименований, по которым можно однозначно найти или сопоставить объект.

Метод 2: Передача сложных объектов через AdditionalInfo с использованием правил получения

Что если нам нужно передать не просто идентификатор, а целый сложный объект, например, реализовать XDTO выгрузку и загрузку справочника с иерархией, если ее нет в базе-приемнике, и мы хотим ее создать? — для этого подойдёт инструмент реализации обмена данными КД3 через EnterpriseData. Передавать все свойства организации по отдельности через AdditionalInfo может быть громоздко. В таких случаях мы можем передать структурированные данные (например, набор ключевых свойств) через AdditionalInfo, а затем использовать правила получения на стороне приемника для поиска или создания соответствующего объекта.

  1. На стороне источника: Передача структуры свойств в AdditionalInfo

Мы можем сформировать структуру, содержащую ключевые свойства сложного объекта (например, код, наименование, ИНН организации) или данные, которые требуются для создания или сопоставления. Хотя AdditionalInfo может содержать произвольные данные, передача полноценного XDTO-объекта через него для конвертации обычно не рекомендуется, так как для этого существуют ПКО. Но для отдельных вспомогательных сложных полей это может быть полезно.

Предположим, мы хотим передать "ВидНоменклатуры" и "СтавкуНДС", которые являются справочниками или перечислениями, и в целевом объекте XDTO для них не предусмотрены полноценные правила конвертации. Мы можем создать структуру и передать ее:


// На стороне источника, перед формированием XDTO-объекта.
// Предположим, ИсточникДанных - это объект, из которого мы берем информацию.
Если ДанныеXDTO.AdditionalInfo = Неопределено Тогда
    ДанныеXDTO.AdditionalInfo = Новый Структура;
КонецЕсли;

// Передаем ключевые данные для ВидаНоменклатуры (УИД и Наименование)
// Эти данные позволят нам однозначно найти или создать вид номенклатуры на приемнике.
ДанныеXDTO.AdditionalInfo.ВидНоменклатурыНаименование = ИсточникДанных.ВидНоменклатуры.Наименование;
ДанныеXDTO.AdditionalInfo.ВидНоменклатурыУИД = Строка(ИсточникДанных.ВидНоменклатуры.УникальныйИдентификатор);
    
// Передаем наименование СтавкиНДС. Если это перечисление, то по наименованию его можно найти.
ДанныеXDTO.AdditionalInfo.СтавкаНДСНаименование = ИсточникДанных.СтавкаНДС.Наименование;

На стороне приемника, в обработчиках событий ПКО (например, ПриКонвертацииДанныхXDTO, ПослеЗагрузкиДанных или ПередЗаписьюПолученныхДанных), мы можем написать логику для обработки этих данных. Для сложных типов нам потребуется не просто присвоение, а поиск или создание объекта в информационной базе. Здесь может пригодиться методика, описывающая десериализацию объектов в конфигурации-приемнике с отличиями в реквизитах, позволяющая гибко обрабатывать входящий поток данных.

Пример получения и обработки "ВидаНоменклатуры" и "СтавкиНДС" на приемнике:


// На стороне приемника, в обработчике "ПриКонвертацииДанныхXDTO" или "ПослеЗагрузкиДанных" для объекта.
// ПолученныеДанные - это объект 1С, который будет записан.
// ДанныеXDTO - это полученный XDTO-объект.

Если ДанныеXDTO.AdditionalInfo <> Неопределено Тогда
    // 1. Обработка ВидаНоменклатуры.
    // Сначала пытаемся найти по УИД, затем по наименованию, и если ничего не найдено - создаем.
    Если ДанныеXDTO.AdditionalInfo.Свойство("ВидНоменклатурыУИД") Тогда
        УИД_ВидаНоменклатуры = Новый УникальныйИдентификатор(ДанныеXDTO.AdditionalInfo.ВидНоменклатурыУИД);
        СсылкаВидНоменклатуры = Справочники.ВидыНоменклатуры.ПолучитьСсылку(УИД_ВидаНоменклатуры);
            
        Если Не ЗначениеЗаполнено(СсылкаВидНоменклатуры) Тогда
            // Если вид номенклатуры не найден по УИД, ищем по наименованию.
            // Это полезно, если на разных базах УИДы могут отличаться, но наименования совпадают.
            Запрос = Новый Запрос;
            Запрос.Текст = "ВЫБРАТЬ Ссылка ИЗ Справочник.ВидыНоменклатуры ГДЕ Наименование = &Наименование";
            Запрос.УстановитьПараметр("Наименование", ДанныеXDTO.AdditionalInfo.ВидНоменклатурыНаименование);
            Выборка = Запрос.Выполнить().Выбрать();
            Если Выборка.Следующий() Тогда
                СсылкаВидНоменклатуры = Выборка.Ссылка;
            Иначе
                // Если вид номенклатуры не найден ни по УИД, ни по наименованию, создаем новый.
                НовыйВидНоменклатуры = Справочники.ВидыНоменклатуры.СоздатьЭлемент();
                НовыйВидНоменклатуры.Наименование = ДанныеXDTO.AdditionalInfo.ВидНоменклатурыНаименование;
                Попытка
                    НовыйВидНоменклатуры.Записать();
                    СсылкаВидНоменклатуры = НовыйВидНоменклатуры.Ссылка;
                Исключение
                    Сообщить("Ошибка при создании вида номенклатуры: " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
                КонецПопытки;
            КонецЕсли;
        КонецЕсли;
            
        Если ЗначениеЗаполнено(СсылкаВидНоменклатуры) Тогда
            ПолученныеДанные.ВидНоменклатуры = СсылкаВидНоменклатуры;
        КонецЕсли;
    КонецЕсли;

    // 2. Обработка СтавкиНДС (если это перечисление).
    // Для перечислений часто достаточно передать их строковое наименование.
    Если ДанныеXDTO.AdditionalInfo.Свойство("СтавкаНДСНаименование") Тогда
        НаименованиеСтавкиНДС = ДанныеXDTO.AdditionalInfo.СтавкаНДСНаименование;
        Попытка
            // Обращаемся к коллекции перечислений по имени, затем к элементу по наименованию.
            ПолученныеДанные.СтавкаНДС = Перечисления.СтавкиНДС[НаименованиеСтавкиНДС];
        Исключение
            Сообщить("Ставка НДС " + НаименованиеСтавкиНДС + " не найдена в перечислении 'СтавкиНДС'. " +
                     "Проверьте актуальность перечислений в базе-приемнике.", СтатусСообщения.Важное);
        КонецПопытки;
    КонецЕсли;
КонецЕсли;

Таким образом, для простых типов данных в AdditionalInfo можно использовать прямое присвоение, как показано в примере из сообщения 4. Для более сложных типов, требующих поиска или создания объекта, мы используем программную логику с обращением к справочникам или другим объектам базы-приемника.

Метод 3: Расширение пакета XDTO EnterpriseData

Этот метод является наиболее "грамотным" и предпочтительным, если нам нужно добавить новые свойства или даже новые типы объектов в формат обмена на постоянной основе, не снимая типовой пакет с поддержки. Он позволяет интегрировать новые поля непосредственно в структуру XDTO, делая их частью формата обмена.

Суть метода:

  1. Мы создаем расширяющий XDTO-пакет в конфигурации, который наследуется от стандартного пакета EnterpriseData.
  2. В этом расширяющем пакете мы описываем новые свойства или типы данных, которые нам необходимо передавать. Если вы работаете со схемами сторонних сервисов, может быть полезна конвертация схемы XSD в модель XDTO.
  3. В правилах конвертации данных (КД 2.0 или КД 3.0) мы используем этот расширенный пакет XDTO вместо или в дополнение к типовому.

Преимущества этого подхода:

Реализация (общие шаги):

  1. Создание расширяющего пакета: Открываем конфигурацию в режиме "Конфигуратор", переходим в раздел "Общие" -> "XDTO-пакеты". Создаем новый XDTO-пакет. Критически важно указать, что этот пакет расширяет существующий типовой пакет EnterpriseData, например, http://v8.1c.ru/edi/edi_exchanges или другой специфический пакет, который мы хотим дополнить. Это гарантирует, что наш пакет будет совместим с типовым.
  2. Добавление новых типов/свойств: В расширяющем пакете мы можем добавить новые элементы (свойства) к существующим типам XDTO-объектов ED. Например, если нам нужно добавить свойство "Владелец" к некоему документу, мы находим соответствующий тип XDTO-документа (например, Document.ПоступлениеТоваровУслуг) в нашем расширяющем пакете и добавляем к нему элемент (свойство) с нужным типом (например, ссылку на Справочник.Организации, который также должен быть представлен в ED или в нашем расширяющем пакете).
  3. Настройка правил обмена: При работе в "Конвертации данных" (КД 2.0 или 3.0) мы указываем использовать наш расширенный XDTO-пакет в качестве формата обмена. Затем, при настройке правил конвертации объектов (ПКО) и правил выгрузки/загрузки свойств (ПВС/ПВЗ), мы сможем работать с новыми свойствами так же, как и с типовыми. Мы сможем напрямую сопоставлять их с реквизитами объектов 1С.

Использование этого подхода требует более глубокого понимания XDTO и механизмов "Конвертации данных", но является наиболее корректным с точки зрения архитектуры обмена и обеспечивает лучшую масштабируемость и управляемость. Для этой задачи есть расширение типового обмена EnterpriseData через механизм расширений.

Можно ли создать свойство типа ДанныеXTDO.КлСвойства.Вставить("Орг", ЧетоПисатьтут)?

Как было указано в сообщении 2, нет, так сделать нельзя. Если в XDTO-формате (схеме) не описано свойство, то попытка добавить его программно в объект XDTO-документа (например, через ДанныеXTDO.КлСвойства.Вставить() или прямое присвоение ДанныеXTDO.НовоеСвойство = Значение) не приведет к его выгрузке. XDTO-пакет строго определяет структуру XML-файла, и любое отклонение от этой схемы будет проигнорировано или вызовет ошибку при сериализации/десериализации. Для добавления новых свойств необходимо расширять сам XDTO-пакет, как описано выше в Методе 3.

Как добавить значения в перечисления, отсутствующие в EnterpriseData?

С этой проблемой мы часто сталкиваемся, когда типовые конфигурации обновляются и добавляют новые элементы в перечисления (например, новые типы штрихкодов SSCC18 и SSCC20), а формат EnterpriseData при этом не обновляется или обновляется с задержкой.

Решение: Расширение пакета XDTO

Единственно верный и "грамотный" способ добавить новые значения в перечисления в контексте EnterpriseData — это расширить существующий XDTO-пакет. Этот подход аналогичен добавлению новых свойств, но применяется к элементам перечислений.

  1. Создание расширяющего XDTO-пакета для перечислений:

Мы создаем новый XDTO-пакет в конфигурации, который расширяет тот стандартный XDTO-пакет EnterpriseData, в котором находится наше перечисление. Например, если перечисление ТипШтрихкода находится в пакете http://v8.1c.ru/edi/edi_exchanges, то наш новый пакет должен быть настроен на его расширение.

Внутри расширяющего пакета мы находим описание нужного перечисления (например, типа ТипШтрихкода) и добавляем в него новые элементы. Важно понимать, что мы добавляем новые элементы, но не можем удалять или изменять существующие элементы стандартного пакета. Это позволяет сохранить совместимость с типовым форматом.

Представим, что в типовом XDTO-пакете есть такое описание перечисления:


<xs:simpleType name="ТипШтрихкода">
    <xs:restriction base="xs:string">
        <xs:enumeration value="EAN8"/>
        <xs:enumeration value="EAN13"/>
        <xs:enumeration value="CODE128"/>
    </xs:restriction>
</xs:simpleType>

В нашем расширяющем XDTO-пакете мы добавим новые элементы к этому типу. Мы не будем менять исходное определение, а лишь дополним его:


<xs:simpleType name="ТипШтрихкода">
    <xs:restriction base="xs:string">
        <!-- Существующие элементы из базового пакета -->
        <xs:enumeration value="EAN8"/>
        <xs:enumeration value="EAN13"/>
        <xs:enumeration value="CODE128"/>
        <!-- Добавляем новые значения в наш расширяющий пакет -->
        <xs:enumeration value="SSCC18"/>
        <xs:enumeration value="SSCC20"/>
    </xs:restriction>
</xs:simpleType>

После добавления элементов в расширяющий пакет, при выгрузке/загрузке данных, содержащих эти новые значения перечислений, они будут корректно обрабатываться. Система будет знать о существовании этих значений в XDTO-формате.

Важные аспекты при работе с расширением XDTO-пакетов для перечислений:

Итоги и рекомендации

Мы подробно рассмотрели различные подходы к работе с форматом EnterpriseData, когда стандартный формат обмена не полностью покрывает наши потребности. Подведем итоги и сформулируем основные рекомендации:

  1. Для передачи простых дополнительных данных, отсутствующих в формате, но необходимых для логики на приемнике (например, идентификаторов, кодов, наименований), наиболее эффективно использовать свойство AdditionalInfo. Этот метод прост в реализации и гибок.
  2. Для передачи сложных объектов или структурированных данных, требующих поиска или создания на стороне приемника, AdditionalInfo также может быть использован для передачи ключевых идентификаторов или частичных данных. Однако, для полноценной конвертации сложных объектов, требующей детального сопоставления многих свойств, предпочтительнее использовать стандартные Правила Конвертации Объектов (ПКО) с их обработчиками событий.
  3. Наиболее "правильным" и масштабируемым решением для добавления новых свойств или типов данных в EnterpriseData, а также для расширения существующих перечислений, является расширение существующего XDTO-пакета. Этот метод обеспечивает структурную целостность данных, делает обмен более прозрачным и управляемым, а также упрощает дальнейшую поддержку.

Выбор конкретного метода всегда зависит от сложности и объема данных, которые необходимо передать, а также от долгосрочных планов по поддержке и развитию обмена. Мы всегда должны стремиться к решениям, которые минимизируют ручные доработки при обновлении типовых конфигураций и обеспечивают максимальную гибкость и надежность обмена данными.

← На главную