Обмен данными между учетной системой 1С и интернет-магазином по стандарту CommerceML 2 — один из наиболее распространенных способов автоматизации торговли. Однако при интеграции 1С с веб-ресурсами на сторонних CMS (например, на платформе Megagroup, CS-Cart или Webasyst) разработчики и администраторы часто сталкиваются с техническими проблемами. Одна из типичных неполадок — сбой при выгрузке структуры каталога. При выборе классификации по видам номенклатуры обмен проходит успешно, но при попытке переключить выгрузку на группы номенклатуры иерархия ломается: разделы на сайте исчезают, а товары выгружаются без привязки к категориям.
В этой статье мы подробно проанализируем причины этой проблемы в конфигурациях 1С:Управление торговлей 11 и 1С:Розница 2.2, разберем программный код обмена и предложим два варианта решения: от исправления исходного кода до настройки стандартных инструментов без программирования.
Для того чтобы понять природу ошибки, рассмотрим технические детали формирования XML-файла import.xml. За выгрузку структуры каталога отвечает классификатор. CMS интернет-магазина сначала считывает блок <Классификатор><Группы>, создавая дерево разделов на основе уникальных идентификаторов (UUID). Затем, импортируя блок <Товары>, система связывает каждый товар с его категорией через аналогичный UUID группы.
При использовании стандартных алгоритмов обмена в 1С выборка данных происходит через сложные запросы во временные таблицы. В коде обработки обмена за распределение по группам отвечает переменная ИдГруппы. Если в настройках узла обмена выбрано «Классифицировать по видам номенклатуры», система связывает товар с его видом (свойство НоменклатураВидНоменклатуры). Когда же мы переключаем настройку на «Классифицировать по группам», код пытается обратиться к свойству ДанныеНоменклатуры.НоменклатураРодитель.
Проблема заключается в том, что во временной таблице запроса поле родителя может быть не заполнено, иметь другое имя (например, просто Родитель) или возвращать неопределенное значение. В результате переменная ИдГруппы остается пустой. Сайт получает товары, у которых отсутствует привязка к группе, и распределяет их в корень каталога либо вовсе игнорирует при импорте.
Если мы заглянем в общий модуль, отвечающий за выгрузку CommerceML (типовой код конфигураций УТ 11 и Розница 2.2), мы увидим следующий фрагмент обработки параметров:
ИдГруппы = "";
ВыгружатьВид = Ложь;
Если Параметры.ПрикладныеПараметры.Свойство("КлассифицироватьПоВидамНоменклатуры") И Параметры.ПрикладныеПараметры.КлассифицироватьПоВидамНоменклатуры <> Неопределено Тогда
Попытка
ВыгружатьВид = Параметры.ПрикладныеПараметры.КлассифицироватьПоВидамНоменклатуры;
Исключение
СтрокаОшибки = ОписаниеОшибки;
КонецПопытки;
КонецЕсли;
Если ВыгружатьВид Тогда
Если ЗначениеЗаполнено(ДанныеНоменклатуры.НоменклатураВидНоменклатуры) Тогда
ИдГруппы = УникальныйИдентификаторОбъекта(ДанныеНоменклатуры.НоменклатураВидНоменклатуры);
КонецЕсли;
Иначе
Если ЗначениеЗаполнено(ДанныеНоменклатуры.НоменклатураРодитель) Тогда
ИдГруппы = УникальныйИдентификаторОбъекта(ДанныеНоменклатуры.НоменклатураРодитель);
КонецЕсли;
КонецЕсли;
Проанализируем этот код. Ветка Иначе пытается получить UUID из поля ДанныеНоменклатуры.НоменклатураРодитель. Чтобы исправить баг с незаполненным полем во временной таблице, мы можем напрямую обратиться к реквизитам объекта 1С и проверить, является ли родительский элемент группой (папкой). Для этого заменим обращение к плоскому реквизиту выборки на проверку через ссылку на справочник Номенклатура.
Ниже представлен исправленный вариант кода, который гарантирует корректное определение родительской группы:
ИдГруппы = "";
ВыгружатьВид = Ложь;
Если Параметры.ПрикладныеПараметры.Свойство("КлассифицироватьПоВидамНоменклатуры") И Параметры.ПрикладныеПараметры.КлассифицироватьПоВидамНоменклатуры <> Неопределено Тогда
Попытка
ВыгружатьВид = Параметры.ПрикладныеПараметры.КлассифицироватьПоВидамНоменклатуры;
Исключение
СтрокаОшибки = ОписаниеОшибки;
КонецПопытки;
КонецЕсли;
Если ВыгружатьВид Тогда
Если ЗначениеЗаполнено(ДанныеНоменклатуры.НоменклатураВидНоменклатуры) Тогда
ИдГруппы = УникальныйИдентификаторОбъекта(ДанныеНоменклатуры.НоменклатураВидНоменклатуры);
КонецЕсли;
Иначе
// Исправление: получаем родительскую группу напрямую из объекта номенклатуры
Если ЗначениеЗаполнено(ДанныеНоменклатуры.Номенклатура) Тогда
СсылкаНаТовар = ДанныеНоменклатуры.Номенклатура;
// Проверяем наличие родителя и что этот родитель действительно является группой
Если ЗначениеЗаполнено(СсылкаНаТовар.Родитель) И СсылкаНаТовар.Родитель.ЭтоГруппа Тогда
ИдГруппы = УникальныйИдентификаторОбъекта(СсылкаНаТовар.Родитель);
КонецЕсли;
КонецЕсли;
КонецЕсли;
Рассмотрим подробнее, почему этот код работает стабильно:
СсылкаНаТовар.Родитель. Даже если в структуре ДанныеНоменклатуры нужная колонка не была инициализирована или заполнена в запросе, обращение через точку к ссылке гарантированно вернет родителя из СУБД.ЭтоГруппа отсекает ситуации, когда в базе данных настроена иерархия элементов (когда один товар подчинен другому товару, а не папке). На сайт выгрузится только UUID реальной директории (папки каталога).Если ваша конфигурация 1С находится на поддержке и вы не хотите вносить изменения в программный код общего модуля, эту проблему можно обойти с помощью стандартного функционала планов обмена. Рассмотрим этот вариант по шагам.
В настройках узла обмена с сайтом предусмотрен инструмент создания независимой структуры каталога. Он называется Пользовательское дерево групп. Этот метод позволяет создать логическую структуру разделов сайта, которая полностью отличается от физического расположения папок внутри вашей 1С.
Для настройки выполните следующие действия:
При такой настройке 1С задействует совершенно другие алгоритмы компоновки XML-данных. Информация о принадлежности товара к категории будет браться из специального регистра сведений пользовательского дерева обмена, минуя проблемные участки кода, где происходил сбой с определением НоменклатураРодитель.
Дополнительно проанализируем настройки отборов в узле обмена. Часто папки каталога не создаются на сайте, так как сами родительские группы исключаются из выгрузки правилами фильтрации данных.
Обратите внимание на процедуру инициализации отборов:
Если Объект.ОтборГруппыКатегорииНоменклатуры = ПредопределенноеЗначение("Перечисление.ВидыОтборовНоменклатуры.ГруппыНоменклатуры") Тогда
ТипЗначений = ПолучитьТипСправочника("Номенклатура");
Элементы.ТаблицаКаталоговГруппы.ВыборГруппИЭлементов = ГруппыИЭлементы.Группы;
Иначе
ТипЗначений = ПолучитьТипСправочника("ВидыНоменклатуры");
Элементы.ТаблицаКаталоговГруппы.ВыборГруппИЭлементов = ГруппыИЭлементы.ГруппыИЭлементы;
КонецЕсли;
Убедитесь, что в настройках отбора обмена не заданы слишком жесткие ограничения. Если вы накладываете фильтр на конкретные элементы номенклатуры, но не включаете в отбор их родителей (папки), XML-файл сформируется без описания структуры каталога. Сайт Megagroup не сможет распределить импортированные товары по разделам, так как в файле обмена будут отсутствовать UUID самих категорий. Всегда настраивайте отборы так, чтобы в выгрузку попадали не только конечные товары, но и содержащие их группы номенклатуры.