Как программно заполнить дополнительные реквизиты номенклатуры в 1С:УНФ при загрузке из Excel

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

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

Архитектура хранения дополнительных реквизитов

Прежде чем переходить к написанию кода, проанализируем, где именно хранятся эти данные. В справочнике Номенклатура (как и во многих других объектах) существует табличная часть с именем ДополнительныеРеквизиты. Она состоит из двух ключевых колонок:

  1. Свойство: Ссылка на план видов характеристик ДополнительныеРеквизитыИСведения.
  2. Значение: Само значение реквизита, которое может быть числом, строкой, датой, булево или ссылкой на специальный справочник ЗначенияСвойствОбъектов.

Важно понимать, что дополнительные реквизиты часто привязаны к Категории номенклатуры. Это означает, что набор доступных свойств для товара «Насос» будет отличаться от набора для товара «Кабель».

Способ 1: Прямое заполнение табличной части объекта

Это наиболее простой и быстрый способ, если вы создаете новый объект или загружаете данные в уже существующий. Разберем алгоритм по шагам.

Предположим, у нас есть считанное из Excel значение «Мощность» и нам нужно записать его в карточку номенклатуры. Рассмотрим пример кода:


// Получаем объект номенклатуры для редактирования
НовыйОбъект = Справочники.Номенклатура.СоздатьЭлемент();
НовыйОбъект.Наименование = "Насос центробежный";
НовыйОбъект.КатегорияНоменклатуры = Справочники.КатегорииНоменклатуры.НайтиПоНаименованию("Насосы");

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

// Поиск свойства. Важно: наименование должно точно совпадать!
// В УНФ часто используется формат "ИмяСвойства (ИмяКатегории)"
СвойствоСсылка = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Мощность (Насосы)");

Если НЕ СвойствоСсылка.Пустая() Тогда
    НоваяСтрока.Свойство = СвойствоСсылка;
    // Значение должно соответствовать типу, заданному в ПВХ
    НоваяСтрока.Значение = Число(ЗначениеИзЭксел); 
КонецЕсли;

НовыйОбъект.Записать();

Важный нюанс: Как выяснилось в ходе обсуждения на форуме, при поиске свойства по наименованию нужно быть предельно внимательным. Если реквизит является общим, он может называться просто «Высота». Если же он индивидуален для категории, система может хранить его как «Высота (Насосы)». Если метод НайтиПоНаименованию вернет пустую ссылку, вы получите ошибку при записи объекта, так как поле Свойство в табличной части не может быть пустым.

Способ 2: Использование универсальных механизмов БСП

Если конфигурация использует Библиотеку стандартных подсистем, правильнее использовать программный интерфейс общего модуля УправлениеСвойствами. Это позволит избежать проблем с индексами и проверками, которые могут быть настроены в системе.

Рассмотрим более сложный пример, в котором учитывается поиск существующих значений и проверка типов:


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

// Ищем наше свойство в ПВХ
СвойствоНоменклатуры = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Цвет");

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

    // Определяем тип свойства для корректного поиска значения
    ТипСвойства = СвойствоНоменклатуры.ТипЗначения.Типы()[0];

    Если ТипСвойства = Тип("СправочникСсылка.ЗначенияСвойствОбъектов") Тогда
        // Если это доп. значение, ищем его в справочнике по владельцу
        ЗначениеРеквизита = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию(СтрокаИзExcel, Истина, , СвойствоНоменклатуры);
        СтрокаТЗ.Значение = ЗначениеРеквизита;
    Иначе
        // Приводим к нужному примитивному типу
        СтрокаТЗ.Значение = Число(СтрокаИзExcel);
    КонецЕсли;
    
    // Записываем обновленный набор свойств для объекта
    УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(СсылкаНаНоменклатуру, ТЗЗначенияСвойств);
КонецЕсли;

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

Разбор типичной ошибки «Запись не верна! Значение поля Свойство не может быть пустым»

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

Как избежать ошибки:

Работа со ссылочными дополнительными значениями

Если тип дополнительного реквизита — «Дополнительное значение» (ссылка на ЗначенияСвойствОбъектов), вы не сможете просто записать туда текст «Красный». Программа ожидает ссылку. В этом случае нам необходимо:

  1. Найти значение в справочнике ЗначенияСвойствОбъектов, где Владельцем является само свойство (реквизит).
  2. Если значения не существует, его необходимо создать программно, чтобы пользователь мог увидеть его в выпадающем списке.

Посмотрим на пример создания нового значения свойства:


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

Рекомендации по оптимизации загрузки

Рассмотрим ситуацию, когда в Excel-файле тысячи строк. Поиск свойства по наименованию в каждой итерации цикла будет существенно замедлять работу. Проанализируем, как ускорить процесс:

Использование соответствий (Кэширование): Перед началом цикла загрузки один раз прочитайте все нужные свойства в объект Соответствие или Структура. Ключом будет имя колонки из Excel, а значением — ссылка на элемент ПВХ ДополнительныеРеквизитыИСведения.

Это позволит обращаться к памяти вместо постоянных запросов к базе данных, что сократит время выполнения обработки в несколько раз.

Таким образом, для успешного заполнения доп. реквизитов в 1С:УНФ важно правильно идентифицировать свойство, привести тип данных к требуемому и не забывать о специфике справочника дополнительных значений.

← На главную