Как программно заполнить дополнительные свойства номенклатуры в УТ 10.3: решаем проблему исчезающих значений

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

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

Разбор архитектуры свойств в УТ 10.3

Прежде чем переходить к коду, давайте проанализируем, как устроена система хранения свойств. В старых конфигурациях на обычных формах (таких как УТ 10.3, УПП 1.3, КА 1.1) механизм дополнительных свойств реализован через три ключевых объекта:

  1. План видов характеристик (ПВХ) "Свойства объектов" — здесь хранятся сами названия свойств (например, "Цвет", "Размер", "Количество в упаковке").
  2. Справочник "Значения свойств объектов" — этот справочник является подчиненным вышеуказанному ПВХ. В нем хранятся конкретные значения, которые может принимать свойство (например, "Красный", "42", "10 шт").
  3. Регистр сведений "Значения свойств объектов" — именно здесь хранится связь конкретного товара (объекта) с его конкретным значением свойства.

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

Анализ ошибки: почему данные пропадают

Рассмотрим ситуацию, описанную в теме. Автор создала дополнительное свойство и попыталась записать значение следующим кодом:


НовЗапись = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьМенеджерЗаписи();
НовЗапись.Объект   = Источник;
НовЗапись.Свойство = СамоСвойство; 
НовЗапись.Значение = Строка(ВыборкаЕдИзм.ШтукВУпаковке); // Ошибка здесь!
НовЗапись.Записать();

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

Правильный алгоритм заполнения свойств

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


// 1. Ищем или создаем значение в подчиненном справочнике
ИмяЗначения = Строка(ВыборкаЕдИзм.ШтукВУпаковке);
НайденоеЗначение = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию(ИмяЗначения, Истина, , СамоСвойство);

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

// 2. Записываем данные в регистр сведений
МенеджерЗаписи = РегистрыСведений.ЗначенияСвойствОбъектов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Объект   = Источник;
МенеджерЗаписи.Свойство = СамоСвойство;
МенеджерЗаписи.Прочитать(); // Читаем, чтобы не создать дубль, если запись уже есть

МенеджерЗаписи.Объект   = Источник;
МенеджерЗаписи.Свойство = СамоСвойство;
МенеджерЗаписи.Значение = СсылкаНаЗначение; // Записываем ССЫЛКУ, а не строку!
МенеджерЗаписи.Записать();

Оптимизация для массовой обработки

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

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

Рассмотрим пример оптимизированного кода:


// Создаем структуру для кэширования значений, чтобы не искать их в БД постоянно
КэшЗначений = Новый Соответствие;

// Начинаем транзакцию для ускорения записи
НачатьТранзакцию();

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

ЗафиксироватьТранзакцию();

Использование типовых средств конфигурации

Проанализируем еще один вариант, который часто забывают. В 1С:УТ 10.3 есть мощная встроенная обработка — "Групповая обработка справочников и документов". Она находится в меню "Сервис".

Для решения задачи без написания кода:

  1. Выберите тип объекта "Справочники" и добавьте "Номенклатура".
  2. Настройте отбор по нужным позициям.
  3. Нажмите кнопку "Выбрать".
  4. В нижней части формы выберите действие "Установить свойства".
  5. В появившемся окне выберите нужное свойство и укажите значение.

Этот метод гарантирует, что все типы данных будут соблюдены, а ссылки корректно прописаны в регистрах, так как обработка использует стандартные механизмы конфигурации.

Важное замечание про типы в ПВХ

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

  1. Зайти в План видов характеристик "Свойства объектов".
  2. Найти свое свойство.
  3. В поле "Тип значения" выбрать только "Строка" (убрав галочку со справочника).

В этом случае ваш первоначальный код с НовЗапись.Значение = "Ваша Строка" будет работать абсолютно корректно и значения перестанут исчезать.

Подведем итог: Основная сложность при работе со свойствами в УТ 10.3 — это строгое соблюдение типов данных. Всегда проверяйте, какой тип ожидает ПВХ, и если это ссылка на справочник — создавайте элемент справочника перед записью в регистр.

← На главную