Как программно загружать свойства номенклатуры из XML без зачеркнутых реквизитов и зависания формы в 1С:УНФ

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

При интеграции 1С с внешними системами (загрузка из XML, импорт по API из маркетплейсов или сайтов поставщиков) разработчики часто сталкиваются с задачей загрузки характеристик и свойств товаров. В современных конфигурациях 1С, таких как 1С:Управление нашей фирмой (УНФ) или 1С:Управление торговлей (УТ), этот механизм реализован на базе подсистемы «Свойства» из Библиотеки стандартных подсистем (БСП).

В процессе реализации загрузки нередко возникают две серьезные проблемы:

  1. Созданные программно свойства отображаются в карточке номенклатуры зачеркнутым шрифтом и не выгружаются обратно (например, в CommerceML).
  2. Если у товаров много уникальных свойств (сотни и тысячи), карточка номенклатуры превращается в «свалку» незаполненных полей, а сама форма элемента начинает критически зависать при открытии.

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

 

Архитектура хранения свойств в БСП: почему свойства зачеркиваются?

Для начала проанализируем ситуацию с зачеркнутыми свойствами. В интерфейсе БСП зачеркнутый шрифт — это защитная реакция платформы. Он указывает на нарушение логической связи между объектами метаданных. 1С видит, что в табличной части ДополнительныеРеквизиты конкретного товара записано значение свойства, но в правилах самой категории (вида номенклатуры) это свойство не объявлено.

Чтобы свойства отображались корректно, необходимо строго соблюдать цепочку взаимосвязей БСП:

Категория номенклатуры (Вид) → Набор свойств → Дополнительный реквизит (ПВХ) → Табличная часть Номенклатуры.

Разберем назначение каждого элемента в этой цепочке:

Если мы просто программно добавим строку в табличную часть номенклатуры ДополнительныеРеквизиты, но забудем включить это свойство в табличную часть ДополнительныеРеквизиты соответствующего Набора свойств, система выведет реквизит зачеркнутым.

 

Шаг 1. Алгоритм правильного программного создания и связывания свойств

Рассмотрим по шагам, как правильно связать все объекты программно, чтобы избежать эффекта зачеркивания.

Во-первых, при загрузке свойства нам нужно проверить, существует ли оно уже в базе. Выполнять запрос в цикле — плохая практика (именно эта ошибка была в исходном коде автора темы). Правильнее будет использовать кэширование или один раз получить нужный набор данных. Но для понимания логики разберем точечный алгоритм создания свойства:


// 1. Получаем или создаем Набор свойств для нашей категории номенклатуры
// Предположим, у нас есть КатегорияСсылка (СправочникСсылка.КатегорииНоменклатуры)
НаборСвойствСсылка = КатегорияСсылка.НаборСвойств;

Если Не ЗначениеЗаполнено(НаборСвойствСсылка) Тогда
    // Если у категории нет набора, создаем его программно
    НаборОбъект = Справочники.НаборыДополнительныхРеквизитовИСведений.СоздатьЭлемент();
    НаборОбъект.Наименование = "Свойства категории: " + КатегорияСсылка.Наименование;
    НаборОбъект.Записать();
    НаборСвойствСсылка = НаборОбъект.Ссылка;
    
    // Привязываем созданный набор к категории
    КатегорияОбъект = КатегорияСсылка.ПолучитьОбъект();
    КатегорияОбъект.НаборСвойств = НаборСвойствСсылка;
    КатегорияОбъект.Записать();
КонецЕсли;

Во-вторых, создаем непосредственно свойство в Плане видов характеристик ДополнительныеРеквизитыИСведения:


// Ищем свойство по наименованию внутри конкретного набора
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ДополнительныеРеквизитыИСведения.Ссылка КАК Ссылка
    |ИЗ
    |	ПланВидовХарактеристик.ДополнительныеРеквизитыИСведения КАК ДополнительныеРеквизитыИСведения
    |ГДЕ
    |	ДополнительныеРеквизитыИСведения.Наименование = &Наименование
    |	И ДополнительныеРеквизитыИСведения.НаборСвойств = &НаборСвойств";
    
Запрос.УстановитьПараметр("Наименование", ИмяСвойстваИзXML);
Запрос.УстановитьПараметр("НаборСвойств", НаборСвойствСсылка);
РезультатЗапроса = Запрос.Выполнить();

Если РезультатЗапроса.Пустой() Тогда
    // Создаем новое свойство
    НовоеСвойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.СоздатьЭлемент();
    НовоеСвойство.Наименование = ИмяСвойстваИзXML;
    НовоеСвойство.Заголовок = ИмяСвойстваИзXML;
    НовоеСвойство.НаборСвойств = НаборСвойствСсылка;
    НовоеСвойство.Виден = Истина;
    НовоеСвойство.Доступен = Истина;
    
    // Задаем тип значения реквизита (например, Строка или Дополнительное значение)
    НовоеСвойство.ТипЗначения = ОбщегоНазначения.ОписаниеТипаСтрока(1024);
    НовоеСвойство.Записать();
    СсылкаНаСвойство = НовоеСвойство.Ссылка;
    
    // КРИТИЧЕСКИЙ ШАГ: Добавляем свойство в табличную часть Набора свойств!
    НаборОбъект = НаборСвойствСсылка.ПолучитьОбъект();
    НоваяСтрокаНабора = НаборОбъект.ДополнительныеРеквизиты.Добавить();
    НоваяСтрокаНабора.Свойство = СсылкаНаСвойство;
    НоваяСтрокаНабора.СвойствоОтсканировано = Истина; // Служебный реквизит БСП
    НаборОбъект.Записать();
    
    Сообщить("Создано и привязано к набору новое свойство: " + ИмяСвойстваИзXML);
Иначе
    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующий();
    СсылкаНаСвойство = Выборка.Ссылка;
КонецЕсли;

Теперь созданное свойство жестко связано с набором свойств нашей категории. При открытии карточки товара оно больше никогда не будет отображаться зачеркнутым, а также начнет без проблем выгружаться по CommerceML.

 

Шаг 2. Как победить «тупняк» формы при загрузке сотен свойств?

Если в вашем XML-файле содержится более 500 уникальных свойств, распределенных по разным товарам, и вы загрузите их все в одну общую категорию (например, «Загружено по API»), вы столкнетесь с катастрофическим падением производительности программы. При открытии формы карточки номенклатуры БСП динамически генерирует на форме элементы управления для каждого свойства, входящего в набор категории. Отрисовка 500 полей ввода на форме вызывает критические задержки («зависание» интерфейса).

Проанализируем три эффективных пути решения этой проблемы.

Стратегия 1. Программное и логическое разделение на категории (Рекомендуется)

Сваливать все товары в один котел — это грубая архитектурная ошибка. Во внешнем XML-файле товары практически всегда имеют структуру (даже если свойства лежат одной кучей). Нам необходимо группировать товары по смысловым категориям.

Например, глупо выводить свойство «Максимальная скорость отжима» для карточки товара «Ноутбук». Свойство стиральной машины должно находиться в категории «Стиральные машины», а свойства ноутбуков — в «Ноутбуки». Разделив товары на 10-20 категорий, вы получите в каждом наборе свойств не более 15-30 реквизитов, и форма карточки товара будет открываться мгновенно.

Стратегия 2. Исключение пустых значений из табличной части товара

В процессе обхода XML-данных обязательно делайте проверку на заполненность значения свойства. Если у конкретного товара значение свойства не заполнено (пустая строка), не нужно добавлять строку этого свойства в табличную часть номенклатуры ДополнительныеРеквизиты.

Посмотрим на пример правильной загрузки значений свойств в номенклатуру:


// Очищаем старые свойства перед заполнением (или обновляем выборочно)
НоменклатураОбъект = СсылкаНаТовар.ПолучитьОбъект();
НоменклатураОбъект.ДополнительныеРеквизиты.Очистить();

Для Каждого СтрокаДанных Из ТаблицаСвойствТовара ИзXML Цикл
    
    // Проверяем, заполнено ли значение свойства в файле импорта
    Если Не ЗначениеЗаполнено(СтрокаДанных.ЗначениеСвойства) Тогда
        // Пропускаем пустые свойства, не захламляем базу данных!
        Продолжить;
    КонецЕсли;
    
    // Получаем ссылку на свойство (используем алгоритм поиска/создания из Шага 1)
    СсылкаНаСвойство = ПолучитьСвойствоПоНаименованию(СтрокаДанных.ИмяСвойства, НаборСвойствСсылка);
    
    // Заполняем реквизит в номенклатуре
    НоваяСтрока = НоменклатураОбъект.ДополнительныеРеквизиты.Добавить();
    НоваяСтрока.Свойство = СсылкаНаСвойство;
    НоваяСтрока.Значение = СтрокаДанных.ЗначениеСвойства; // Записываем только непустое значение
КонецЦикла;

НоменклатураОбъект.Записать();

Стратегия 3. Скрытие пустых свойств на форме карточки товара

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

В БСП элементы формы дополнительных реквизитов создаются динамически при открытии карточки товара. Чтобы скрыть незаполненные поля, мы можем использовать механизм расширений для формы элемента справочника Номенклатура.

Рассмотрим пример кода, который нужно поместить в обработчик события ПриСозданииНаСервере формы элемента номенклатуры (после выполнения стандартного кода заполнения свойств от БСП):


&После("ПриСозданииНаСервере")
Процедура Расш_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Обходим свойства текущего товара
    Для Каждого СтрокаРеквизита Из Объект.ДополнительныеРеквизиты Цикл
        
        // Если значение свойства у данного товара не заполнено
        Если Не ЗначениеЗаполнено(СтрокаРеквизита.Значение) Тогда
            
            // Имя элемента формы в БСП генерируется по определенному шаблону.
            // Для получения имени элемента воспользуемся служебной функцией БСП:
            ИмяЭлементаФормы = УправлениеСвойствамиСлужебный.ИмяЭлементаРеквизита(СтрокаРеквизита.Свойство);
            
            // Ищем элемент на форме и скрываем его
            ЭлементНаФорме = Элементы.Найти(ИмяЭлементаФормы);
            Если ЭлементНаФорме <> Неопределено Тогда
                ЭлементНаФорме.Видимость = Ложь;
            КонецЕсли;
            
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Важное примечание: Этот метод сделает форму аккуратной и уберет "кашу" из сотен пустых полей. Но помните, что сервер 1С все равно тратит ресурсы на первичную генерацию этих 500 элементов на форме, поэтому Стратегия 1 (разделение по категориям) остается самым производительным и правильным архитектурным решением.

 

Резюме

Мы выяснили, почему свойства номенклатуры могут отображаться зачеркнутыми (из-за отсутствия их регистрации в табличной части Набора свойств категории), и научились решать эту проблему программно. Также мы рассмотрели методику борьбы с зависанием формы при большом количестве свойств. Применяйте правильное разделение на категории товаров, не записывайте пустые строки свойств в базу данных, и ваша система интеграции с XML будет работать быстро и стабильно!

← На главную