При переносе данных между управляющими и учетными системами 1С (например, между «1С:Управление торговлей», редакция 11, «1С:Комплексная автоматизация», редакция 2, или «1С:ERP Управление предприятием» и «1С:Бухгалтерия предприятия», редакция 3.0) пользователи часто сталкиваются со сбоями синхронизации. Одной из наиболее критичных и труднодиагностируемых проблем является ошибка валидации схемы XDTO (EnterpriseData). Обмен данными внезапно прекращает работу, а в журнале регистрации фиксируется системное сообщение о несоответствии структуры объекта XDTO-типу.
В этой статье мы подробно разберем, почему возникает ошибка проверки данных XDTO при выгрузке документов Сборка товаров (сбой проверки свойства ЕдиницаИзмерения и отсутствие свойства ДанныеНоменклатуры) и документов Отчет о розничных продажах (ошибка типа ТипКоличество). Мы разработаем и внедрим корректное решение этой проблемы с помощью механизма расширений конфигурации, не снимая систему с поддержки.
---
Давайте проанализируем техническую суть сбоя на примере документа Сборка товаров. Текст ошибки указывает на общий модуль ОбменДаннымиXDTOСервер и метод контекста Проверить(). Причина кроется в том, что валидатор XDTO ожидает увидеть заполненную единицу измерения для выгружаемых строк табличной части, но свойство ДанныеНоменклатуры в схеме обмена оказывается не установлено.
Многие пользователи сразу начинают проверять справочники номенклатуры и единиц измерения в базах УТ и БП, однако там все заполнено корректно и идентично. На самом деле проблема носит сугубо программный характер и связана с обновлением конфигураций УТ 11.4.5 / КА 2.4.5.
В этих релизах разработчики 1С провели оптимизацию учета номеров ГТД, перенеся их данные из табличной части документов непосредственно в регистры и таблицу «Виды запасов». В связи с этим был изменен пакет запросов в процедуре ПКО_Документ_СборкаТоваров_ПриОтправкеДанных общего модуля МенеджерОбменаЧерезУниверсальныйФормат.
Разработчиками была допущена программная неточность: при выгрузке товаров использовалось жесткое смещение для получения таблицы результатов пакета запросов:
РезультатЗапроса[РезультатЗапроса.Количество() - 2].Выгрузить()
Однако логика проведения и структура запросов документа Сборка (разборка) товаров напрямую зависят от вида хозяйственной операции:
В итоге реквизит ЕдиницаИзмерения не заполняется, и валидатор схемы EnterpriseData аварийно прерывает весь сеанс синхронизации, из-за чего в бухгалтерию не уходят никакие другие документы.
---
Мы настоятельно не рекомендуем редактировать типовую конфигурацию напрямую, так как это усложнит процедуру последующих обновлений системы. Самым правильным и безопасным способом является использование механизма расширений.
Разберем по шагам процесс создания расширения и переопределения проблемной процедуры:
ИсправлениеОбменаXDTO.МенеджерОбменаЧерезУниверсальныйФормат.ПКО_Документ_СборкаТоваров_ПриОтправкеДанных с помощью аннотации &Вместо.Просто заменить индекс в запросе на РезультатЗапроса.Количество() - 1 нельзя — в этом случае исправится выгрузка «Сборки», но сломается выгрузка «Разборки». Нам необходимо написать универсальный код, который будет динамически определять правильный индекс таблицы товаров в зависимости от хозяйственной операции документа.
Рассмотрим пример программного кода, который необходимо поместить в модуль нашего расширения:
&Вместо("ПКО_Документ_СборкаТоваров_ПриОтправкеДанных")
Процедура Испр_ПКО_Документ_СборкаТоваров_ПриОтправкеДанных(ДанныеИБ, ДанныеXDTO, КомпонентыОбмена, СтекВыгрузки)
СкладДляВыгрузки = СкладДляВыгрузки(ДанныеИБ.Склад, КомпонентыОбмена.ПараметрыКонвертации);
ДанныеXDTO.Вставить("Склад", СкладДляВыгрузки);
ВыгрузитьПодразделениеИзРеквизитаДокумента(КомпонентыОбмена, ДанныеИБ, ДанныеXDTO, "Склад");
ВыгрузитьДополнительныеРеквизитыИСведения(КомпонентыОбмена, ДанныеИБ, ДанныеXDTO);
ТекстЗапроса = "ВЫБРАТЬ
| Номенклатура.ЕдиницаИзмерения КАК ЕдиницаИзмерения
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка = &НоменклатураСсылка";
Если ДанныеИБ.ХозяйственнаяОперация = Перечисления.ХозяйственныеОперации.СборкаТоваров Тогда
ДанныеXDTO.Вставить("ВидОперации", "Сборка");
ДанныеXDTO.Вставить("ТипЗапасов", "СобственныеТовары");
ТекстЗапроса = ТекстЗапроса + ОбщегоНазначения.РазделительПакетаЗапросов() +
"ВЫБРАТЬ
| ЕСТЬNULL(КлючиАналитикиУчетаНоменклатуры.Номенклатура, ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)) КАК Номенклатура,
| ЕСТЬNULL(КлючиАналитикиУчетаНоменклатуры.Характеристика, ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка)) КАК Характеристика,
| ЕСТЬNULL(СпрНоменклатура.ЕдиницаИзмерения, ЗНАЧЕНИЕ(Справочник.УпаковкиЕдиницыИзмерения.ПустаяСсылка)) КАК ЕдиницаИзмерения,
| ВидыЗапасов.Количество КАК Количество,
| ЕСТЬNULL(НомераГТД.Код, """") КАК НомерГТД,
| ЕСТЬNULL(НомераГТД.СтранаПроисхождения, ЗНАЧЕНИЕ(Справочник.СтраныМира.ПустаяСсылка)) КАК СтранаПроисхождения,
| ВЫРАЗИТЬ(СборкаТоваровТовары.ДоляСтоимости * ВидыЗапасов.Количество / СборкаТоваровТовары.Количество КАК ЧИСЛО(10, 0)) КАК ДоляСтоимости,
| ВЫБОР
| КОГДА ВидыЗапасов.ВидЗапасов.ТипЗапасов = ЗНАЧЕНИЕ(Перечисление.ТипыЗапасов.КомиссионныйТовар)
| ТОГДА ВЫРАЗИТЬ(""КомиссионныеТовары"" КАК СТРОКА(18))
| ИНАЧЕ ВЫРАЗИТЬ(""СобственныеТовары"" КАК СТРОКА(18))
| КОНЕЦ КАК ТипЗапасов
|ИЗ
| Документ.СборкаТоваров.Товары КАК СборкаТоваровТовары
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.СборкаТоваров.ВидыЗапасовСписание КАК ВидыЗапасов
| ПО СборкаТоваровТовары.АналитикаУчетаНоменклатуры = ВидыЗапасов.АналитикаУчетаНоменклатуры
| И СборкаТоваровТовары.Ссылка = ВидыЗапасов.Ссылка
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.НомераГТД КАК НомераГТД
| ПО (ВидыЗапасов.НомерГТД = НомераГТД.Ссылка)
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиАналитикиУчетаНоменклатуры КАК КлючиАналитикиУчетаНоменклатуры
| ПО СборкаТоваровТовары.АналитикаУчетаНоменклатуры = КлючиАналитикиУчетаНоменклатуры.Ссылка
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СпрНоменклатура
| ПО (КлючиАналитикиУчетаНоменклатуры.Номенклатура = СпрНоменклатура.Ссылка)
|ГДЕ
| СборкаТоваровТовары.Ссылка = &Ссылка";
Иначе
ДанныеXDTO.Вставить("ВидОперации", "Разборка");
ТекстЗапроса = ТекстЗапроса + ОбщегоНазначения.РазделительПакетаЗапросов() +
"ВЫБРАТЬ
| Товары.Номенклатура КАК Номенклатура,
| Товары.Характеристика КАК Характеристика,
| СУММА(Товары.Количество) КАК Количество,
| СУММА(Товары.ДоляСтоимости) КАК ДоляСтоимости,
| Товары.Серия КАК Серия,
| Товары.АналитикаУчетаНоменклатуры КАК АналитикаУчетаНоменклатуры
|ПОМЕСТИТЬ втТовары
|ИЗ
| Документ.СборкаТоваров.Товары КАК Товары
|ГДЕ
| Товары.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
| Товары.Серия,
| Товары.Номенклатура,
| Товары.АналитикаУчетаНоменклатуры,
| Товары.Характеристика
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ЕСТЬNULL(КлючиАналитикиУчетаНоменклатуры.Номенклатура, ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)) КАК Номенклатура,
| ЕСТЬNULL(КлючиАналитикиУчетаНоменклатуры.Характеристика, ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка)) КАК Характеристика,
| ЕСТЬNULL(СпрНоменклатура.ЕдиницаИзмерения, ЗНАЧЕНИЕ(Справочник.УпаковкиЕдиницыИзмерения.ПустаяСсылка)) КАК ЕдиницаИзмерения,
| ВидыЗапасов.Количество КАК Количество,
| ЕСТЬNULL(НомераГТД.Код, """") КАК НомерГТД,
| ЕСТЬNULL(НомераГТД.СтранаПроисхождения, ЗНАЧЕНИЕ(Справочник.СтраныМира.ПустаяСсылка)) КАК СтранаПроисхождения,
| ВЫРАЗИТЬ(втТовары.ДоляСтоимости * ВидыЗапасов.Количество / втТовары.Количество КАК ЧИСЛО(10, 0)) КАК ДоляСтоимости,
| ВЫБОР
| КОГДА ВидыЗапасов.ВидЗапасов.ТипЗапасов = ЗНАЧЕНИЕ(Перечисление.ТипыЗапасов.КомиссионныйТовар)
| ТОГДА ВЫРАЗИТЬ(""КомиссионныеТовары"" КАК СТРОКА(18))
| ИНАЧЕ ВЫРАЗИТЬ(""СобственныеТовары"" КАК СТРОКА(18))
| КОНЕЦ КАК ТипЗапасов
|ИЗ
| втТовары КАК втТовары
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.СборкаТоваров.ВидыЗапасовОприходование КАК ВидыЗапасов
| ПО втТовары.АналитикаУчетаНоменклатуры = ВидыЗапасов.АналитикаУчетаНоменклатуры
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.НомераГТД КАК НомераГТД
| ПО (ВидыЗапасов.НомерГТД = НомераГТД.Ссылка)
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КлючиАналитикиУчетаНоменклатуры КАК КлючиАналитикиУчетаНоменклатуры
| ПО втТовары.АналитикаУчетаНоменклатуры = КлючиАналитикиУчетаНоменклатуры.Ссылка
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СпрНоменклатура
| ПО (КлючиАналитикиУчетаНоменклатуры.Номенклатура = СпрНоменклатура.Ссылка)
|ГДЕ
| ВидыЗапасов.Ссылка = &Ссылка
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ ПЕРВЫЕ 1
| ВЫБОР
| КОГДА ВидыЗапасовСписание.ВидЗапасов.ТипЗапасов = ЗНАЧЕНИЕ(Перечисление.ТипыЗапасов.КомиссионныйТовар)
| ТОГДА ВЫРАЗИТЬ(""КомиссионныеТовары"" КАК СТРОКА(18))
| ИНАЧЕ ВЫРАЗИТЬ(""СобственныеТовары"" КАК СТРОКА(18))
| КОНЕЦ КАК ТипЗапасов
|ИЗ
| Документ.СборкаТоваров.ВидыЗапасовСписание КАК ВидыЗапасовСписание
|ГДЕ
| ВидыЗапасовСписание.Ссылка = &Ссылка";
КонецЕсли;
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Ссылка", ДанныеИБ.Ссылка);
Запрос.УстановитьПараметр("НоменклатураСсылка", ДанныеИБ.Номенклатура);
Запрос.Текст = ТекстЗапроса;
РезультатЗапроса = Запрос.ВыполнитьПакет();
ДанныеНоменклатуры = РезультатЗапроса[0].Выбрать();
Если ДанныеНоменклатуры.Следующий() Тогда
ДанныеXDTO.Вставить("ЕдиницаИзмерения", ДанныеНоменклатуры.ЕдиницаИзмерения);
Иначе
ДанныеXDTO.Вставить("ЕдиницаИзмерения", Справочники.УпаковкиЕдиницыИзмерения.ПустаяСсылка());
КонецЕсли;
Если ДанныеИБ.ХозяйственнаяОперация = Перечисления.ХозяйственныеОперации.РазборкаТоваров Тогда
ДанныеВидовЗапасов = РезультатЗапроса[РезультатЗапроса.Количество() - 1].Выбрать();
Если ДанныеВидовЗапасов.Следующий() Тогда
ДанныеXDTO.Вставить("ТипЗапасов", ДанныеВидовЗапасов.ТипЗапасов);
Иначе
ДанныеXDTO.Вставить("ТипЗапасов", "СобственныеТовары");
КонецЕсли;
КонецЕсли;
// Внедряем динамическое определение индекса таблицы товаров
Если ДанныеИБ.ХозяйственнаяОперация = Перечисления.ХозяйственныеОперации.СборкаТоваров Тогда
НомерТаблТовары = 1;
Иначе
НомерТаблТовары = 2;
КонецЕсли;
ДанныеXDTO.Вставить("Товары", РезультатЗапроса[НомерТаблТовары].Выгрузить());
КонецПроцедуры
Проанализируем ключевое изменение в коде. Мы ввели переменную НомерТаблТовары. Если документ отражает сборку, то результирующая таблица товаров находится в первом индексе пакета запроса (индекс 1). Если выполняется разборка — во втором (индекс 2). Теперь выгрузка обоих видов документов будет проходить корректно и без ошибок.
---
Иногда при синхронизации возникает аналогичная ошибка проверки XDTO для документов Отчет о розничных продажах. Система сообщает, что для свойства Количество (тип ТипКоличество) не установлено значение обязательного свойства ЕдиницаИзмерения. Рассмотрим детальнее три основные причины этой проблемы и способы их устранения:
В розничных продажах часто фигурируют не только физические товары, но и сопутствующие услуги (например, «Доставка», «Сборка мебели» или «Подарочный пакет»). Если для такой номенклатуры с типом Услуга в информационной базе не заполнена базовая единица измерения, то при выгрузке количества для данной строки XDTO-валидатор выдаст ошибку. Формат обмена EnterpriseData требует заполнения единицы измерения для любой строки документа, где количество не равно нулю. Чтобы исправить это, необходимо зайти в карточки всех услуг, продаваемых через розницу, и заполнить там базовую единицу измерения (например, «шт» или «услуга»).
Если в настройках программы включено использование упаковок номенклатуры, правила обмена при выгрузке розничных отчетов обращаются к связанным справочникам. Если у какого-либо товара была создана карточка упаковки, но внутри нее не заполнена единица измерения (или она ссылается на битый/удаленный элемент), валидатор XDTO выдаст ошибку структуры КлючевыеСвойстваУпаковка. Для решения этой проблемы рекомендуется проверить справочники упаковок у товаров, проданных в проблемный день.
В XSD-схеме формата обмена EnterpriseData для свойства Количество заложен строгий тип данных с ограничением точности до 3 знаков после запятой (формат 15,3). Если в вашей управляющей системе (УТ, КА или ERP) была программно или стандартно увеличена точность весового товара (например, до 4 или 5 знаков после запятой для ювелирных изделий, химикатов или нефтепродуктов), то при попытке выгрузить количество вида 0.1005 валидатор XDTO отклонит пакет.
В таких случаях в расширении обмена на этапе выгрузки свойств розничных продаж необходимо принудительно округлять значение выгружаемого количества с помощью функции:
Окр(ЗначениеСвойства, 3)
---
Для предотвращения подобных ошибок в будущем рекомендуем придерживаться следующих правил:
EF_*). Включите автоматическую загрузку исправительных патчей в разделе Администрирование — Интернет-поддержка и услуги. Описанная ошибка «Сборки товаров» была официально исправлена разработчиками в более поздних релизах конфигураций, и установка актуальных патчей позволяет решить проблему автоматически.МенеджерОбменаЧерезУниверсальныйФормат и исправили ошибку в самом релизе, ваше расширение можно будет безболезненно отключить или удалить.