Как программно записать и обновить дополнительные реквизиты номенклатуры в 1С 8.3?

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

При интеграции 1С с интернет-магазинами, маркетплейсами или внешними CRM-системами разработчики часто сталкиваются с необходимостью программной записи дополнительных реквизитов номенклатуры. На первый взгляд задача кажется тривиальной: получить объект номенклатуры, обратиться к табличной части дополнительных реквизитов и записать туда нужные значения. Однако на практике разработчики часто сталкиваются с ситуацией, когда код выполняется без ошибок, но данные в интерфейсе 1С не сохраняются или не обновляются.

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

Понимание архитектуры: как устроены дополнительные реквизиты и сведения

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

  1. Дополнительные реквизиты — это данные, которые хранятся непосредственно «внутри» самого объекта. Физически в СУБД они представляют собой строки подчиненной таблицы (табличной части ДополнительныеРеквизиты), жестко связанной с основной таблицей справочника (например, Справочник.Номенклатура) по уникальному идентификатору (GUID) родительского элемента. Запись дополнительного реквизита всегда требует получения объекта для редактирования (вызова метода ПолучитьОбъект()) и накладывает блокировку на всю карточку товара.
  2. Дополнительные сведения — это данные, которые хранятся «снаружи» объекта. Физически они располагаются в независимом регистре сведений РегистрСведений.ДополнительныеСведения. Измерениями регистра выступают ссылка на Объект (номенклатуру) и ссылка на Свойство (из Плана видов характеристик), а ресурсом — непосредственно Значение. Сведения можно изменять и записывать напрямую через менеджер записи регистра без блокировки и перезаписи самого элемента номенклатуры.

Часто у разработчиков возникает резонный вопрос: «Я открываю новую карточку товара в 1С, перехожу на вкладку дополнительных реквизитов и уже вижу там пустые поля для заполнения. Означает ли это, что строки в базе данных уже созданы?»

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

Разбор типичных ошибок разработчиков

Проанализируем классические ошибки, которые приводят к тому, что код выполняется без ошибок, но реквизиты не сохраняются:

Способ 1. Программное заполнение через прямую работу с табличной частью

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

Для поиска свойств в ПВХ рекомендуется использовать поиск по реквизиту Имя (это уникальное имя свойства для разработчиков, которое не меняется пользователями из интерфейса), либо осуществлять точный поиск по наименованию с учетом владельца свойства.

Ниже представлен готовый к использованию код процедуры:


&НаСервере
Процедура ЗаписатьДопРеквизитыНоменклатурыВручную(Идентификатор1С, ИдентификаторИМ, НаименованиеИМ)
    
    // 1. Находим ссылки на свойства в Плане видов характеристик
    СвойствоID = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("ИдентификаторИМ (Товар для ИМ)", Истина);
    СвойствоName = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("НаименованиеИМ (Товар для ИМ)", Истина);
    
    Если СвойствоID.Пустая() Или СвойствоName.Пустая() Тогда
        ВызватьИсключение "В системе не настроены необходимые дополнительные реквизиты для товаров ИМ!";
    КонецЕсли;
    
    // 2. Получаем ссылку на номенклатуру по UUID
    СсылкаНаНоменклатуру = Справочники.Номенклатура.ПолучитьСсылка(Новый УникальныйИдентификатор(Идентификатор1С));
    
    // Надежная проверка существования элемента в базе данных
    Если ОбщегоНазначения.СсылкаСуществует(СсылкаНаНоменклатуру) Тогда
        
        // Получаем объект для редактирования
        НоменклатураОбъект = СсылкаНаНоменклатуру.ПолучитьОбъект();
        
        // Переменные-флаги для отслеживания необходимости добавления новых строк
        НужноДобавитьID = Истина;
        НужноДобавитьName = Истина;
        
        // 3. Обходим существующую табличную часть дополнительных реквизитов
        Для Каждого СтрокаРеквизита Из НоменклатураОбъект.ДополнительныеРеквизиты Цикл
            
            Если СтрокаРеквизита.Свойство = СвойствоID Тогда
                СтрокаРеквизита.Значение = ИдентификаторИМ;
                НужноДобавитьID = Ложь;
            ИначеЕсли СтрокаРеквизита.Свойство = СвойствоName Тогда
                СтрокаРеквизита.Значение = НаименованиеИМ;
                НужноДобавитьName = Ложь;
            КонецЕсли;
            
        КонецЦикла;
        
        // 4. Если свойства не были найдены в табличной части, добавляем новые строки
        Если НужноДобавитьID Тогда
            НоваяСтрока = НоменклатураОбъект.ДополнительныеРеквизиты.Добавить();
            НоваяСтрока.Свойство = СвойствоID;
            НоваяСтрока.Значение = ИдентификаторИМ;
        КонецЕсли;
        
        Если НужноДобавитьName Тогда
            НоваяСтрока = НоменклатураОбъект.ДополнительныеРеквизиты.Добавить();
            НоваяСтрока.Свойство = СвойствоName;
            НоваяСтрока.Значение = НаименованиеИМ;
        КонецЕсли;
        
        // 5. Записываем измененный объект номенклатуры один раз
        Попытка
            НоменклатураОбъект.Записать();
            Сообщить("Дополнительные реквизиты для номенклатуры успешно сохранены.");
        Исключение
            ЗаписьЖурналаРегистрации("СинхронизацияСИМ", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
            ВызватьИсключение "Не удалось записать объект номенклатуры: " + ОписаниеОшибки();
        КонецПопытки;
        
    Иначе
        Сообщить("Номенклатура с указанным уникальным идентификатором не найдена в базе данных!");
    КонецЕсли;
    
КонецПроцедуры

Способ 2. Использование стандартного API БСП (Рекомендуемый метод)

Прямая модификация табличных частей объектов — рабочий метод, но он заставляет разработчика самостоятельно писать громоздкий код проверок, поиска дублей свойств, блокировок данных и обработки исключений. В современных конфигурациях 1С (УТ 11, ERP, Комплексная автоматизация, УНФ), построенных на базе БСП, реализован специализированный программный интерфейс, который делает эту работу за вас.

Для записи свойств используется общий модуль УправлениеСвойствами и его ключевой метод ЗаписатьСвойстваУОбъекта(). Этот метод берет на себя всю «рутину»:

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


&НаСервере
Процедура ЗаписатьДопРеквизитыЧерезБСП(СсылкаНаНоменклатуру, ИдентификаторИМ, НаименованиеИМ)
    
    // 1. Находим нужные свойства в Плане видов характеристик.
    // Рекомендуется искать свойства по реквизиту "Имя" (имя для разработчиков).
    СвойствоID = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Имя", "ИдентификаторИМ");
    СвойствоName = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Имя", "НаименованиеИМ");
    
    // Если по коду/имени не нашли, пробуем точный поиск по наименованию
    Если СвойствоID.Пустая() Тогда
        СвойствоID = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("ИдентификаторИМ (Товар для ИМ)", Истина);
    КонецЕсли;
    
    Если СвойствоName.Пустая() Тогда
        СвойствоName = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("НаименованиеИМ (Товар для ИМ)", Истина);
    КонецЕсли;
    
    // Если свойства отсутствуют в системе - прерываем выполнение
    Если СвойствоID.Пустая() Или СвойствоName.Пустая() Тогда
        ЗаписьЖурналаРегистрации("СвойстваНоменклатуры", УровеньЖурналаРегистрации.Предупреждение, , , "Не найдены метаданные дополнительных реквизитов.");
        Возврат;
    КонецЕсли;
    
    // 2. Формируем таблицу значений со свойствами и их новыми значениями
    ТаблицаСвойств = Новый ТаблицаЗначений;
    ТаблицаСвойств.Колонки.Добавить("Свойство", Новый ОписаниеТипов("ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения"));
    ТаблицаСвойств.Колонки.Добавить("Значение"); // Тип произвольный, зависит от настроек реквизита
    
    // Заполняем таблицу парами Свойство-Значение
    НоваяСтрока = ТаблицаСвойств.Добавить();
    НоваяСтрока.Свойство = СвойствоID;
    НоваяСтрока.Значение = ИдентификаторИМ;
    
    НоваяСтрока = ТаблицаСвойств.Добавить();
    НоваяСтрока.Свойство = СвойствоName;
    НоваяСтрока.Значение = НаименованиеИМ;
    
    // 3. Вызываем стандартный метод БСП для записи свойств у владельца.
    // Параметры: Ссылка на объект (Владелец) и подготовленная ТаблицаЗначений.
    Попытка
        УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(СсылкаНаНоменклатуру, ТаблицаСвойств);
        Сообщить("Свойства успешно записаны средствами БСП.");
    Исключение
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка сохранения дополнительных реквизитов: " + ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры

Как быстро прочитать дополнительные реквизиты объекта?

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

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

Посмотрим на пример использования этих функций:


// Пример получения значения одного конкретного свойства номенклатуры
ЗначениеИдентификатора = УправлениеСвойствами.ЗначениеСвойства(СсылкаНаНоменклатуру, СвойствоID);

Если ЗначениеЗаполнено(ЗначениеИдентификатора) Тогда
    Сообщить("У товара уже установлен ID интернет-магазина: " + ЗначениеИдентификатора);
КонецЕсли;

Выводы и рекомендации

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

← На главную