Как программно записать значения дополнительных реквизитов в 1С, включая тип 'Дополнительное значение'?

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

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

Особенности дополнительных реквизитов в 1С

Дополнительные реквизиты и сведения в 1С:Предприятии 8.3 представляют собой мощный механизм для расширения функциональности типовых объектов без изменения их структуры. Они позволяют добавлять произвольные свойства объектам, таким как справочники, документы, планы видов характеристик и т.д. Определение самих дополнительных реквизитов хранится в плане видов характеристик ДополнительныеРеквизитыИСведения. Типы значений таких реквизитов могут быть самыми разнообразными: число, строка, дата, булево, ссылки на справочники, документы и, что наиболее важно для нашей задачи, тип "Дополнительное значение".

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

Решение 1: Использование стандартных механизмов БСП через процедуру УправлениеСвойствами.ЗаписатьСвойстваУОбъекта()

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

  1. Получаем ссылку на объект-владелец свойств:

    Прежде всего, нам нужна ссылка на объект, которому мы хотим присвоить дополнительный реквизит. Это может быть элемент справочника (например, Справочники.Номенклатура.НайтиПоКоду("00001")) или документ (например, Документы.ПоступлениеТоваровУслуг.НайтиПоНомеру("0000-000001")).

  2. Находим определение дополнительного реквизита:

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

    
    ОпределениеДопРеквизита = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("СтатусОбработки (Поступление товаров и услуг)", Истина);
    Если ОпределениеДопРеквизита = Неопределено Тогда
        Сообщить("Дополнительный реквизит 'СтатусОбработки' не найден!");
        Возврат;
    КонецЕсли;
    

    Иногда реквизит можно найти по другим полям, например, по реквизиту Заголовок, как показано в одном из примеров:

    
    ДопРеквизитВес = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Заголовок", "Вес(кг)");
    
  3. Находим необходимое значение для реквизитов типа "Дополнительное значение":

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

    
    ЗначениеДопРеквизита = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию("Обработан");
    Если ЗначениеДопРеквизита = Неопределено Тогда
        Сообщить("Значение 'Обработан' для дополнительного реквизита не найдено!");
        Возврат;
    КонецЕсли;
    

    Важно: Если дополнительный реквизит имеет другой тип (например, "Число" или "Строка"), то в качестве значения следует передавать соответствующее число или строку. Критически важно, чтобы тип передаваемого значения совпадал с типом, указанным в определении дополнительного реквизита.

  4. Формируем таблицу значений для записи:

    Процедура ЗаписатьСвойстваУОбъекта() ожидает в качестве второго параметра ТаблицуЗначений. Эта таблица должна содержать две колонки: "Свойство" и "Значение".

    1. Колонка "Свойство" должна иметь тип ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения и содержать ссылку на определение нашего дополнительного реквизита.
    2. Колонка "Значение" должна содержать само значение, тип которого должен соответствовать типу реквизита.
    
    ТаблицаДопРеквизитов = Новый ТаблицаЗначений;
    ТаблицаДопРеквизитов.Колонки.Добавить("Свойство", Новый ОписаниеТипов("ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения"));
    ТаблицаДопРеквизитов.Колонки.Добавить("Значение");
    
    // Добавляем строку для нашего реквизита
    НоваяСтрока = ТаблицаДопРеквизитов.Добавить();
    НоваяСтрока.Свойство = ОпределениеДопРеквизита;
    НоваяСтрока.Значение = ЗначениеДопРеквизита; // Если тип "Дополнительное значение", то здесь ссылка на Справочник.ЗначенияСвойствОбъектов
    
    // Пример добавления другого реквизита, например, числового
    ОпределениеДопРеквизитаВес = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Вес(кг) (Номенклатура)", Истина);
    Если ОпределениеДопРеквизитаВес <> Неопределено Тогда
        НоваяСтрокаВес = ТаблицаДопРеквизитов.Добавить();
        НоваяСтрокаВес.Свойство = ОпределениеДопРеквизитаВес;
        НоваяСтрокаВес.Значение = 15.5; // Числовое значение
    КонецЕсли;
    
  5. Вызываем процедуру записи:

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

    
    // Предположим, ДокументПоступления - это ссылка на объект, которому присваиваем реквизиты
    УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(ДокументПоступления, ТаблицаДопРеквизитов);
    

Полный пример с использованием БСП для записи реквизита типа "Дополнительное значение":


// 1. Получаем ссылку на объект, которому будем записывать доп. реквизит
// Например, если это документ "Поступление товаров и услуг"
ДокументПоступления = Документы.ПоступлениеТоваровУслуг.НайтиПоНомеру("0000-000001");
Если ДокументПоступления = Неопределено Тогда
    Сообщить("Документ не найден!");
    Возврат;
КонецЕсли;

// 2. Находим определение дополнительного реквизита
// Предположим, имя доп. реквизита "СтатусОбработки"
// и он относится к "Поступление товаров и услуг"
ОпределениеДопРеквизита = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("СтатусОбработки (Поступление товаров и услуг)", Истина);
Если ОпределениеДопРеквизита = Неопределено Тогда
    Сообщить("Дополнительный реквизит 'СтатусОбработки' не найден!");
    Возврат;
КонецЕсли;

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

// 4. Формируем ТаблицуЗначений для записи
ТаблицаДопРеквизитов = Новый ТаблицаЗначений;
ТаблицаДопРеквизитов.Колонки.Добавить("Свойство", Новый ОписаниеТипов("ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения"));
ТаблицаДопРеквизитов.Колонки.Добавить("Значение");

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

// Пример с числовым реквизитом "Вес"
ОпределениеДопРеквизитаВес = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Вес(кг) (Поступление товаров и услуг)", Истина);
Если ОпределениеДопРеквизитаВес <> Неопределено Тогда
    НоваяСтрокаВес = ТаблицаДопРеквизитов.Добавить();
    НоваяСтрокаВес.Свойство = ОпределениеДопРеквизитаВес;
    НоваяСтрокаВес.Значение = 25.75; // Числовое значение
КонецЕсли;

// 5. Записываем дополнительные реквизиты
УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(ДокументПоступления, ТаблицаДопРеквизитов);
Сообщить("Дополнительные реквизиты успешно записаны для документа: " + ДокументПоступления);

Решение 2: Прямая манипуляция с табличной частью "Дополнительные реквизиты" объекта

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

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

  1. Получаем объект:

    Для прямого доступа к свойствам объекта нам потребуется не ссылка, а сам объект. Это делается с помощью метода ПолучитьОбъект().

    
    ОбъектНоменклатура = Справочники.Номенклатура.НайтиПоКоду("00001").ПолучитьОбъект();
    Если ОбъектНоменклатура = Неопределено Тогда
        Сообщить("Элемент номенклатуры не найден!");
        Возврат;
    КонецЕсли;
    
  2. Находим определение дополнительного реквизита:

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

    
    ДопРеквизитСвойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Вид деятельности (Номенклатура)", Истина);
    Если ДопРеквизитСвойство = Неопределено Тогда
        Сообщить("Дополнительный реквизит 'Вид деятельности' не найден!");
        Возврат;
    КонецЕсли;
    
  3. Находим необходимое значение для реквизитов типа "Дополнительное значение":

    Если реквизит имеет тип "Дополнительное значение", то мы ищем его в справочнике ЗначенияСвойствОбъектов.

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

    Если реквизит другого типа (например, "Строка"), то мы используем соответствующее значение:

    ЗначениеКомментария = "Важный комментарий к элементу";
  4. Работаем с табличной частью ДополнительныеРеквизиты:

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

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

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

    
    Попытка
        ОбъектНоменклатура.Записать();
        Сообщить("Дополнительный реквизит успешно записан для номенклатуры: " + ОбъектНоменклатура.Наименование);
    Исключение Е
        Сообщить("Ошибка при записи объекта: " + Е.Описание);
    КонецПопытки;
    

Полный пример прямой записи дополнительного реквизита типа "Дополнительное значение":


// 1. Получаем объект, которому присваиваем доп. реквизит
ОбъектНоменклатура = Справочники.Номенклатура.НайтиПоКоду("00001").ПолучитьОбъект();
Если ОбъектНоменклатура = Неопределено Тогда
    Сообщить("Элемент номенклатуры с кодом '00001' не найден.");
    Возврат;
КонецЕсли;

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

// 3. Находим нужное значение "Прочая деятельность" в справочнике ЗначенияСвойствОбъектов
ЗначениеДеятельности = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию("Прочая деятельность");
Если ЗначениеДеятельности = Неопределено Тогда
    Сообщить("Значение 'Прочая деятельность' для дополнительного реквизита не найдено.");
    Возврат;
КонецЕсли;

// 4. Работаем с табличной частью ДополнительныеРеквизиты объекта
ДопРеквизитСтрока = ОбъектНоменклатура.ДополнительныеРеквизиты.Найти(ДопРеквизитСвойство, "Свойство");

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

ДопРеквизитСтрока.Значение = ЗначениеДеятельности; // Присваиваем ссылку на элемент справочника

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

// 5. Записываем объект
Попытка
    ОбъектНоменклатура.Записать();
    Сообщить("Дополнительные реквизиты для номенклатуры '" + ОбъектНоменклатура.Наименование + "' успешно обновлены.");
Исключение Е
    Сообщить("Ошибка при записи объекта: " + Е.Описание);
КонецПопытки;

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

  1. Проверка на Неопределено: Всегда проверяйте, что результаты поиска (как определений реквизитов, так и их значений) не являются Неопределено. Это поможет избежать ошибок "Метод объекта не обнаружен" или "Объект не найден".
  2. Соответствие типов: Это самый частый источник ошибок. Тип значения, которое вы присваиваете, должен строго соответствовать типу, указанному в настройках дополнительного реквизита. Если реквизит ожидает число, нельзя передавать строку. Если он ожидает ссылку на ЗначенияСвойствОбъектов, нельзя передавать произвольную строку, даже если она совпадает с наименованием элемента справочника.
  3. Права доступа: Убедитесь, что у пользователя, под которым выполняется код, есть необходимые права на чтение и запись дополнительных реквизитов, а также на чтение справочника ЗначенияСвойствОбъектов и изменение объектов-владельцев.
  4. Настройки программы: Для того чтобы дополнительные реквизиты и сведения были доступны в конфигурации, необходимо включить соответствующую функциональность в общих настройках программы.
  5. Транзакционность: Использование процедуры БСП УправлениеСвойствами.ЗаписатьСвойстваУОбъекта() обеспечивает транзакционность изменений. Это означает, что либо все изменения запишутся успешно, либо ни одно. При прямой работе с объектом вам придется самостоятельно заботиться о транзакциях, если это необходимо.

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

← На главную