Как исправить ошибку проверки данных XDTO при синхронизации 1С:УТ и 1С:БП в документах сборки и розничных продаж?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При переносе данных между управляющими и учетными системами 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 аварийно прерывает весь сеанс синхронизации, из-за чего в бухгалтерию не уходят никакие другие документы.

---

Пошаговое решение проблемы с помощью расширения конфигурации

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

Разберем по шагам процесс создания расширения и переопределения проблемной процедуры:

  1. Откроем базу «1С:Управление торговлей» (или КА / ERP) в режиме Конфигуратор.
  2. Перейдем в меню Конфигурация — Расширения конфигурации.
  3. Нажмем кнопку Добавить, укажем назначение «Адаптация», снимем флажки Безопасный режим и Защита от опасных действий (это критически важно, так как модуль обмена должен выполняться без ограничений прав доступа). Назовем расширение, например, ИсправлениеОбменаXDTO.
  4. В дереве основной конфигурации найдем общий модуль МенеджерОбменаЧерезУниверсальныйФормат.
  5. Кликнем по нему правой кнопкой мыши и выберем команду Добавить в расширение.
  6. В открывшемся модуле расширения нам нужно полностью переопределить процедуру ПКО_Документ_СборкаТоваров_ПриОтправкеДанных с помощью аннотации &Вместо.

Просто заменить индекс в запросе на РезультатЗапроса.Количество() - 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 для документов Отчет о розничных продажах. Система сообщает, что для свойства Количество (тип ТипКоличество) не установлено значение обязательного свойства ЕдиницаИзмерения. Рассмотрим детальнее три основные причины этой проблемы и способы их устранения:

1. Продажа услуг без указания единиц измерения

В розничных продажах часто фигурируют не только физические товары, но и сопутствующие услуги (например, «Доставка», «Сборка мебели» или «Подарочный пакет»). Если для такой номенклатуры с типом Услуга в информационной базе не заполнена базовая единица измерения, то при выгрузке количества для данной строки XDTO-валидатор выдаст ошибку. Формат обмена EnterpriseData требует заполнения единицы измерения для любой строки документа, где количество не равно нулю. Чтобы исправить это, необходимо зайти в карточки всех услуг, продаваемых через розницу, и заполнить там базовую единицу измерения (например, «шт» или «услуга»).

2. Поврежденные карточки в справочнике «Упаковки»

Если в настройках программы включено использование упаковок номенклатуры, правила обмена при выгрузке розничных отчетов обращаются к связанным справочникам. Если у какого-либо товара была создана карточка упаковки, но внутри нее не заполнена единица измерения (или она ссылается на битый/удаленный элемент), валидатор XDTO выдаст ошибку структуры КлючевыеСвойстваУпаковка. Для решения этой проблемы рекомендуется проверить справочники упаковок у товаров, проданных в проблемный день.

3. Несоответствие разрядности количества (ограничение EnterpriseData)

В XSD-схеме формата обмена EnterpriseData для свойства Количество заложен строгий тип данных с ограничением точности до 3 знаков после запятой (формат 15,3). Если в вашей управляющей системе (УТ, КА или ERP) была программно или стандартно увеличена точность весового товара (например, до 4 или 5 знаков после запятой для ювелирных изделий, химикатов или нефтепродуктов), то при попытке выгрузить количество вида 0.1005 валидатор XDTO отклонит пакет.

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

Окр(ЗначениеСвойства, 3)

---

Рекомендации по профилактике и диагностике ошибок обмена

Для предотвращения подобных ошибок в будущем рекомендуем придерживаться следующих правил:

← На главную