Материала по расширению XDTO-пакетов в свободном доступе действительно мало, и он в основном про Конвертацию данных 3.x. Здесь — два рабочих подхода на реальном примере, с кодом расширений, граблями платформы и результатами проверки. Один из подходов (AdditionalInfo) доведён до рабочего решения; второй (расширение формата XDTO) разобран подробно, чтобы было понятно, когда он оправдан и во что обходится.
Отдельно разобран нюанс, который в публичных примерах обычно не проговаривают: доработка через AdditionalInfo не привязана к версии формата — при выходе новых версий EnterpriseData её не нужно пересобирать и синхронизировать в двух базах (см. §5).
1. Постановка
В УТ у строки расхода авансового отчёта есть реквизит Документ.АвансовыйОтчет.ПрочиеРасходы.БланкСтрогойОтчетности (Булево). В БП аналог — Документ.АвансовыйОтчет.Прочее.БланкСтрогойОтчетности, на форме колонка подписана «БСО» и работает как «принять к вычету по БСО (или иному документу)».
При типовой синхронизации признак не переносится. Пример документа: строк1 с признаком Истина — после обмена в БП все строки приходят с БСО = Ложь.
УТ:
БП:
Отрывок файла обмена:
2. Что есть в типовом обмене, а чего в нём нет
Универсальный формат — это несколько слоёв, и важно понимать, какой из них чем расширяется.
| Слой | Где лежит | Расширяется |
|---|---|---|
| Схема формата | пакеты ПакетXDTO.EnterpriseData_1_* + конверт ExchangeMessage |
объектом «Расширение формата XDTO» в расширении конфигурации |
| Правила конвертации (ПОД/ПКО/ПКС) | общий модуль менеджера обмена: в УТ МенеджерОбменаЧерезУниверсальныйФормат, в БП МенеджерОбменаЧерезУниверсальныйФормат13 |
расширением: &После, &Вместо, &ИзменитьИКонтроль |
| Произвольные данные | AdditionalInfo конверта сообщения |
кодом менеджера, без правки схемы |
| Движок | ОбменДаннымиXDTOСервер, точки расширения — ОбменДаннымиПереопределяемый |
расширением |
Три проверки, которые стоит сделать прежде чем писать код (они экономят дни):
- Есть ли реквизит в модуле менеджера обмена. Выгружаем конфигурацию в файлы и ищем имя реквизита по обоим модулям. В нашем случае слова
БланкСтрогойОтчетностив менеджере обмена УТ нет вообще — то есть типовой код этот признак никуда не кладёт, и «включить галочку в настройках обмена» не получится. - Есть ли свойство в схеме формата. Проверяется на ходу:
Т = ФабрикаXDTO.Тип("http://v8.1c.ru/edi/edi_stnd/EnterpriseData/1.20", "Документ.АвансовыйОтчет_ПрочиеРасходы.Строка"); Для Каждого С Из Т.Свойства Цикл Сообщить(С.Имя); КонецЦикла;
-
Имена типов в EnterpriseData — с точками, URI вида
http://v8.1c.ru/edi/edi_stnd/EnterpriseData/<версия>. У типа строки расходов естьПредъявленСФ, но признака БСО нет ни в одной из версий формата.
3. По какому ПКО реально выгружается объект. Это не всегда «очевидный» ПКО. В нашем случае авансовый отчёт выгружался через Документ_АвансовыйОтчетИзСтруктуры_Отправка, а не через обычный Документ_АвансовыйОтчет_Отправка — видно по составу свойств в файле выгрузки (свойство ЗакупкаПодДеятельность объявлено только в правилах «Из структуры»).
3.Вариант 1: расширение формата XDTO
Механизм существует и официально описан (ИТС, «Расширение формата обмена EnterpriseData»). Суть: в расширении конфигурации создаётся свой ПакетXDTO с тем же targetNamespace, что у пакета конфигурации, и в нём объявляются дополнительные свойства типов. Дальше — регистрация расширения в правилах конвертации и в настройках обмена.
Опорные точки механизма, которые видно в конфигурациях:
ОбменДаннымиXDTOСервер.ДополнитьСвойстваПакетаИзРасширений()— дополняет список свойств типа свойствами из расширенного пакета;ОбменДаннымиXDTOСервер.ИнициализироватьРасширениеПравилаКонвертацииОбъекта(ПравилоКонвертации, ПространствоИмен);- регистрация версии формата: в УТ —
ОбменДаннымиУТ.ДоступныеВерсииУниверсальногоФормата(в ERP/БП имя отличается, ориентируйтесь на код своей конфигурации); - в настройках узла есть поле
РасширениеФормата(РегистрСведений.НастройкиОбменаДаннымиXDTO, ресурсРасширениеФормата), то есть расширение формата — это часть контракта обмена, и оно должно стоять в обеих базах. -
Как это выглядит в реальности: внутри одного из примеров, скачанного с infostart лежали
EnterpriseData_1_5_20,EnterpriseData_1_5_1_20иExchangeMessage— то есть полная копия схемы формата (около 800 КБ XML).
Цена варианта: держать копию схемы EnterpriseData и пересобирать её при каждом обновлении формата; согласовывать расширение в обеих базах. Оправдано, когда реквизитов много, нужна строгая типизация и схему действительно хочется видеть в формате. Для «передать один флаг» это заметно дороже, чем нужно.
4. Вариант 2: AdditionalInfo — выбранный путь
В формате есть штатный «карман» для произвольных данных: свойство AdditionalInfo объявлено не в EnterpriseData, а в конверте сообщения — http://www.1c.ru/SSL/Exchange/Message, базовый (абстрактный) тип Object, тип свойства xs:anyType. Все объекты обмена наследуются от этого типа, поэтому дополнительные данные едут без правки схемы.
Типовой код этим пользуется: например, в УТ есть ДанныеXDTO.Вставить("AdditionalInfo", …) для реализаций и возвратов, а на приёме — разбор ДанныеXDTO.AdditionalInfo.Свойство(...).
Вот так это выглядит в файле выгрузки (наш случай — таблица «ИдентификаторСтроки → БСО»):
<Документ.АвансовыйОтчет>
<msg:AdditionalInfo xmlns:d4p1="http://v8.1c.ru/8.1/data/core" xsi:type="d4p1:Structure">
<d4p1:Property name="БСО_ПрочиеРасходы">
<d4p1:Value xsi:type="d4p1:ValueTable">
<d4p1:column><d4p1:Name>ИдентификаторСтроки</d4p1:Name>…</d4p1:column>
<d4p1:column><d4p1:Name>БланкСтрогойОтчетности</d4p1:Name>…</d4p1:column>
<d4p1:row><d4p1:Value xsi:type="xs:string">24b13221-…</d4p1:Value>
<d4p1:Value xsi:type="xs:boolean">true</d4p1:Value></d4p1:row>
…
</d4p1:Value>
</d4p1:Property>
</msg:AdditionalInfo>
<КлючевыеСвойства>…</КлючевыеСвойства>
На что обратить внимание:
AdditionalInfoидёт перед собственными свойствами документа. Это нормально: свойство принадлежит базовому типу, а в XML Schema содержимое базового типа всегда идёт первым. Приёмник разбирает элементы по именам, порядок ни на что не влияет — не пытайтесь это «починить».СериализаторXDTO.ЗаписатьXDTOподдерживаетСтруктура,ТаблицаЗначений,Массив,Соответствие— таблица значений приезжает на приёмник какТаблицаЗначений(проверяется вызовомНайтиСтроки(...)).- Никаких изменений схемы, версий формата и
РасширениеФорматане требуется.
5. Почему решение не привязано к версии формата
Этот нюанс стоит вынести отдельно: от выбранного подхода зависит, придётся ли переделывать доработку при выходе очередной версии формата.
Расширение XDTO-пакета версию чувствует. Пакет — это копия схемы, и её имя содержит версию (EnterpriseData_1_11_5, EnterpriseData_1_20_2). Базы при обмене договариваются, какую версию использовать; если согласована другая версия, ваша копия схемы в обмене просто не участвует. Поэтому в таких примерах обязательны схема нужной версии в расширении, регистрация своей версии формата и заполнение РасширениеФормата в настройках узла — то есть обмен фактически «пришпиливается» к вашей расширенной схеме, а при выходе новой версии копию приходится собирать заново. Отсюда и несколько версий пакетов в одном расширении (в разобранном выше примере скачанного расширения лежали сразу EnterpriseData_1_5_20, EnterpriseData_1_5_1_20 и ExchangeMessage).
AdditionalInfo версию не чувствует. Этот «карман» объявлен в конверте сообщения (ExchangeMessage), а конверт один для всех версий EnterpriseData: версионируются пакеты с описанием объектов, а не конверт. Какая бы версия формата ни была согласована — 1.20, 1.21, 1.25 — табличка данных просто едет рядом с объектом.
| Элемент решения | Привязан к версии формата? | Почему |
|---|---|---|
Передача данных через AdditionalInfo |
нет | конверт ExchangeMessage общий для всех версий |
Обработчики &После в менеджере обмена |
нет | привязка по имени процедуры, а не по версии формата |
| Запрос признака по ссылке документа | нет | это метаданные конфигурации |
Регистрация версии формата, РасширениеФормата в узле |
не требуется вовсе | мы не участвуем в согласовании версий |
Практический эффект: при выходе новой версии EnterpriseData доработку не нужно ни пересобирать, ни синхронизировать в двух базах — она продолжает работать как есть.
Что от релизов всё-таки зависит (и что стоит перепроверять при обновлении):
- имена обработчиков (
ПКО_…,ОтложеннаяОбработка_…). Если 1С их переименует, расширение перестанет привязываться — но это видно сразу, ошибкой применения расширения, а не тихой поломкой в обмене; - правила приёмника. Мы опираемся на текущую формулу БП «БСО = СФ И Билет». Если её изменят, доработка не сломается, но проставлять
ПредъявленСФи вид документа может стать не нужно; - появление признака в самом формате. Если 1С однажды добавит БСО в схему и в правила конвертации, типовой обмен начнёт возить его сам — и расширение можно будет просто снять.
Чек-лист после обновления конфигураций:
- применить расширения к БД — ошибки привязки обработчиков видны сразу;
- прогнать тестовый обмен на копии и посмотреть журнал регистрации по событию «…БСО авансового отчета»: дошла ли таблица и сколько строк применено;
- поискать признак в
XDTOPackages/EnterpriseData_*— не появился ли он в самой схеме; - заглянуть в модуль объекта БП: не изменилась ли формула вокруг
БланкСтрогойОтчетности.
6. Расширение для УТ: заполняем AdditionalInfo
Общий модуль МенеджерОбменаЧерезУниверсальныйФормат заимствуется в расширение, обработчики — &После (менеджер остаётся на поддержке).
&После("ПКО_Документ_АвансовыйОтчет_Отправка_ПриОтправкеДанных")
Процедура Расш1_ПКО_Документ_АвансовыйОтчет_Отправка_ПриОтправкеДанных(
ДанныеИБ, ДанныеXDTO, КомпонентыОбмена, СтекВыгрузки)
ТаблицаБСО = ТаблицаБСОПоСтрокам(ДанныеИБ.ПрочиеРасходы);
Если ТаблицаБСО = Неопределено И ЗначениеЗаполнено(ДанныеИБ.Ссылка) Тогда
ТаблицаБСО = ТаблицаБСОПоСсылке(ДанныеИБ.Ссылка);
КонецЕсли;
ДобавитьБСО(ДанныеXDTO, ТаблицаБСО);
КонецПроцедуры
&После("ПКО_Документ_АвансовыйОтчетИзСтруктуры_Отправка_ПриОтправкеДанных")
Процедура Расш1_ПКО_Документ_АвансовыйОтчетИзСтруктуры_Отправка_ПриОтправкеДанных(
ДанныеИБ, ДанныеXDTO, КомпонентыОбмена, СтекВыгрузки)
ТаблицаБСО = Неопределено;
Если ДанныеИБ.Свойство("ПрочиеРасходы") Тогда
ТаблицаБСО = ТаблицаБСОПоСтрокам(ДанныеИБ.ПрочиеРасходы);
КонецЕсли;
Если ТаблицаБСО = Неопределено
И ДанныеИБ.Свойство("Ссылка") И ЗначениеЗаполнено(ДанныеИБ.Ссылка) Тогда
ТаблицаБСО = ТаблицаБСОПоСсылке(ДанныеИБ.Ссылка);
КонецЕсли;
ДобавитьБСО(ДанныеXDTO, ТаблицаБСО);
КонецПроцедуры
// Признак берём запросом по ссылке: в ПКО «Из структуры» таблица расходов собрана
// типовым запросом без колонки БланкСтрогойОтчетности.
Функция ТаблицаБСОПоСсылке(Ссылка)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПрочиеРасходы.ИдентификаторСтроки КАК ИдентификаторСтроки,
| ПрочиеРасходы.БланкСтрогойОтчетности КАК БланкСтрогойОтчетности
|ИЗ Документ.АвансовыйОтчет.ПрочиеРасходы КАК ПрочиеРасходы
|ГДЕ ПрочиеРасходы.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Ссылка);
ТаблицаБСО = НоваяТаблицаБСО();
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
НоваяСтрока = ТаблицаБСО.Добавить();
НоваяСтрока.ИдентификаторСтроки = Выборка.ИдентификаторСтроки;
НоваяСтрока.БланкСтрогойОтчетности = Выборка.БланкСтрогойОтчетности;
КонецЦикла;
Возврат ?(ТаблицаБСО.Количество() = 0, Неопределено, ТаблицаБСО);
КонецФункции
Процедура ДобавитьБСО(ДанныеXDTO, ТаблицаБСО)
Если ТаблицаБСО = Неопределено Тогда Возврат; КонецЕсли;
Если ДанныеXDTO.Свойство("AdditionalInfo")
И ТипЗнч(ДанныеXDTO.AdditionalInfo) = Тип("Структура") Тогда
ДополнительныеДанные = ДанныеXDTO.AdditionalInfo;
Иначе
ДополнительныеДанные = Новый Структура;
КонецЕсли;
Если ДополнительныеДанные.Свойство("БСО_ПрочиеРасходы") Тогда
ДополнительныеДанные.Удалить("БСО_ПрочиеРасходы");
КонецЕсли;
ДополнительныеДанные.Вставить("БСО_ПрочиеРасходы", ТаблицаБСО);
ДанныеXDTO.Вставить("AdditionalInfo", ДополнительныеДанные);
КонецПроцедуры
Два принципиальных момента:
- передаём все строки, и Истина, и Ложь. Иначе в приёмнике нельзя снять признак: «нет данных» и «признак снят» — разные вещи;
- обработчики стоят на обоих ПКО объекта, потому что заранее не всегда понятно, какой из них сработает в конкретной базе.
7. Расширение для БП: три места приёма, из которых главное — третье
Приём оказался самой интересной частью. Кандидатов на установку «чужого» реквизита три, и работают они в разных ситуациях:
| Обработчик | Когда срабатывает | Годится ли для нового документа |
|---|---|---|
ПКО_…_Получение_ПриКонвертацииДанныхXDTO |
всегда | нет: значения из строк формата попадут в документ только по свойствам, объявленным в правилах конвертации |
ПКО_…_Получение_ПередЗаписьюПолученныхДанных |
только при обновлении существующего документа: типовая процедура начинается с Если ДанныеИБ = Неопределено Тогда Возврат |
нет |
ОтложеннаяОбработка_<Объект> (ПослеЗагрузкиВсехДанных) |
всегда, документ уже создан и табличные части заполнены | да |
Тонкость: у нового документа табличную часть заполняет сам БСП из ДополнительныеСвойства["Прочее"], причём по индексу строки (ДополнительныеСвойства[ИмяТЧ][НомерСтроки - 1]) — но только для объявленных свойств. Поэтому ПредъявленСФ, НомерСФ, ДатаСФ «доезжают», а БланкСтрогойОтчетности, не объявленный в правилах, теряется.
Чтобы поставить признак в отложенной обработке, нужно передать туда список признаков. Ключ — ссылка создаваемого объекта, канал — КомпонентыОбмена.ПараметрыКонвертации (в отложенный обработчик приходит ровно эта же структура, см. диспетчер менеджера обмена)
Порядок строк сохраняется: БСП заполняет ТЧ по индексу, поэтому соответствие «строка формата ↔ строка ТЧ ↔ элемент массива признаков» не рвётся.
Почему в БП пришлось ставить ещё и СФ, и вид документа
Признак БСО в БП связан с «СФ предъявлен»:
- в форме галка БСО недоступна, пока не установлена галка СФ (при снятии СФ обработчик формы
ПрочееПредъявленСФПриИзменениигасит БСО); - в модуле объекта (
ПередЗаписью→ЗаполнитьНередактируемыеРеквизитыДляКомандировки) признак пересчитывается какБСО = ПредъявленСФ И ВидДокументаРасхода = Билет.
Поэтому строкам с БСО дополнительно проставляем ПредъявленСФ = Истина, ВидДокументаРасхода = Билет и НомерСФ/ДатаСФ из входящего документа — ровно то, что БП делает для билетов сам. И это не подгонка: в УТ признак ставится строкам из электронных билетов с НДС (СоставОперации.СуммаНДС <> 0 КАК БланкСтрогойОтчетности в модуле объекта УТ), то есть «Билет» — корректное соответствие.
Процедура ПрименитьПризнакБСОСтрокеТЧ(СтрокаТЧ, ПризнакБСО)
СтрокаТЧ.БланкСтрогойОтчетности = ПризнакБСО;
Если НЕ ПризнакБСО Тогда Возврат; КонецЕсли;
СтрокаТЧ.ПредъявленСФ = Истина;
СтрокаТЧ.ВидДокументаРасхода = Перечисления.ВидыДокументовПодтверждающихКомандировочныеРасходы.Билет;
СтрокаТЧ.НомерСФ = СтрокаТЧ.НомерВходящегоДокумента;
СтрокаТЧ.ДатаСФ = СтрокаТЧ.ДатаВходящегоДокумента;
КонецПроцедуры
8. Грабли, которые стоит знать заранее
- Признака может не быть в модуле обмена вообще — тогда его нужно брать запросом по ссылке документа, а не из переданной таблицы.
- Выгружается не тот ПКО, который кажется очевидным. Определяйте по составу свойств в файле выгрузки, а не по названию объекта.
- Необъявленные в правилах реквизиты теряются при загрузке нового документа.
ПередЗаписьюПолученныхДанныхдля нового документа не работает: типовая процедура выходит приДанныеИБ = Неопределено.- Приёмник может пересчитывать ваш реквизит сам — проверяйте
ПередЗаписью,ПриЗаписии модуль формы документа-приёмника. - Файловый обмен двухсторонний. Ошибка
ТранспортСообщенийОбменаFILE«не был обнаружен файл сообщения с данными» с шаблономMessage*_<корреспондент>_<свой узел>.*— это ожидание ответного файла, а не поломка расширения. Сначала запустите обмен на стороне корреспондента. (Если настройка подключения через локальный или сетевой каталог-типовое поведение системы)
9. Проверка: сценарии и результат
Проверяли обмен с файловым транспортом через COM (встроенный типовой инструмент) на разных сценариях — все прошли штатно, в боевом режиме сейчас запущен в серверном варианте через com-соединение:
| Сценарий | Результат |
|---|---|
| Выгрузка нового авансового отчёта с признаком БСО | в БП документ создан, строки 3, 7, 8 — СФ + БСО + вид документа «Билет» |
| Выгрузка документа, который уже есть и в УТ, и в БП | значения обновляются корректно (работает обработчик ПередЗаписью) |
| Снятие признака БСО только в источнике | в БП признак снимается, счёт-фактура отвязывается и помечается на удаление — типовое поведение БП |
| Снятие признака только в приёмнике | обмен не «возвращает» признак сам по себе |
| Снятие и последующий возврат признака в источнике | в БП счёт-фактура возвращается и становится проведённой |
Поведение со счетами-фактурами — это логика самой БП (галка СФ и связанный с ней документ), и она нас устраивает: цель была передать признак, а не переопределить учёт.
10. Ограничения и что осталось
- Передаётся булево. Если понадобится набор полей — тем же способом едет таблица значений с любым набором колонок.
- При снятии признака БСО в УТ сопутствующие
ПредъявленСФ/ВидДокументаРасходав БП остаются (галка БСО снимается). Если нужно откатывать и их — достаточно дополнитьПрименитьПризнакБСОСтрокеТЧветкой дляЛожь. - Диагностические записи в журнал регистрации (
Обмен с УТ.БСО авансового отчета/Обмен с БП.БСО авансового отчета) в коде помечены как временные — после приёмки их можно убрать. - Проверено на конкретных версиях УТ 11.5.27.81 БП 3.0.206.19 . При обновлении конфигураций имеет смысл повторно убедиться, что имена обработчиков и состав свойств не изменились — расширения на
&Послепереживают обновления лучше, чем копии типовых процедур.
Файлы
К статье приложены собранные расширения в zip архиве:
БСО_АвансовыеОтчеты.cfe— расширение для УТ (заимствованныйМенеджерОбменаЧерезУниверсальныйФормат);БСО_АвансовыеОтчеты_BP.cfe— расширение для БП (заимствованныйМенеджерОбменаЧерезУниверсальныйФормат13);
Если будете повторять на своих конфигурациях: проверьте имена ПКО и реквизитов (шаг 2 §2) — в соседних релизах они могут отличаться, а сам механизм AdditionalInfo остаётся тем же.
И, конечно, обязательно тестировать!
Проверено на следующих конфигурациях и релизах:
- Управление торговлей, редакция 11, релизы 11.5.27.81
Вступайте в нашу телеграмм-группу Инфостарт