Как программно изменить дополнительные реквизиты и свойства номенклатуры в 1С:Управление торговлей 11.4

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

В процессе разработки и кастомизации конфигураций на платформе 1С:Предприятие 8.3, особенно таких крупных решений, как «1С:Управление торговлей 11.4», «1С:ERP» или «1С:Комплексная автоматизация», разработчики часто сталкиваются с необходимостью массового изменения свойств объектов. Одним из наиболее востребованных объектов для таких манипуляций является справочник Номенклатура.

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

Разбор типичной ошибки: почему ломается справочник свойств?

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


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

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

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

Архитектура хранения свойств в УТ 11.4

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

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

Ниже мы рассмотрим правильные методы программного изменения этих данных.

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

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

Рассмотрим подробнее пример кода, который решает задачу автора темы правильным и безопасным способом:


// Шаг 1. Создаем и подготавливаем таблицу значений для новых свойств
ТаблицаСвойств = Новый ТаблицаЗначений;
ТаблицаСвойств.Колонки.Добавить("Свойство");
ТаблицаСвойств.Колонки.Добавить("Значение");

// Шаг 2. Находим целевое свойство в Плане видов характеристик
СвойствоСтикер = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Стикер");

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

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

Способ 2. Прямое изменение табличной части номенклатуры

Если вы твердо уверены, что ваше свойство настроено именно как дополнительный реквизит (то есть оно хранится внутри объекта номенклатуры), можно прибегнуть к прямому изменению табличной части объекта. Этот способ работает быстрее при пакетной обработке больших массивов данных, однако требует явного получения объекта для записи.

Посмотрим на пример реализации данного алгоритма:


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

Если ЗначениеЗаполнено(СвойствоСтикер) Тогда

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

КонецЕсли;

Важное примечание: Прямой метод требует монопольного доступа к объекту в момент записи. Если объект заблокирован другим пользователем, метод Записать() вызовет исключение, поэтому использование конструкции Попытка ... Исключение здесь строго обязательно.

Способ 3. Изменение свойств без программирования (Интерактивный метод)

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

Проанализируем пошагово, как выполнить эту операцию интерактивно:

  1. Перейдем в раздел Склады и доставка или Продажи и откроем список Номенклатура.
  2. В правой части окна списка номенклатуры воспользуемся панелью быстрых отборов. В разделе «Виды и свойства» выберем нужный вид номенклатуры и установим фильтр по интересующему нас свойству (например, отберем все товары со старым значением стикера).
  3. В получившемся списке выделим позиции, которые необходимо изменить. Для выделения всех строк используем комбинацию клавиш Ctrl + A, для выборочного выделения — зажимаем клавишу Ctrl или Shift и кликаем мышью по нужным товарам.
  4. Нажмем правой кнопкой мыши на любом выделенном элементе и в контекстном меню выберем пункт «Изменить выделенные...».
  5. В открывшейся форме группового изменения реквизитов найдем в списке наш дополнительный реквизит (например, «Стикер»). Обратите внимание, что дополнительные реквизиты находятся в общем списке доступных полей.
  6. Установим флаг напротив этого реквизита, а в колонке «Новое значение» укажем то значение, которое необходимо присвоить выбранным товарам.
  7. Нажмем кнопку «Изменить реквизиты» в правом нижнем углу формы.

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

← На главную