В процессе разработки или доработки конфигураций 1С часто возникает необходимость программно управлять дополнительными реквизитами объектов — для этого есть обработка для выгрузки, загрузки и массового изменения дополнительных реквизитов в 1С. Это могут быть различные справочники (номенклатура, контрагенты) или документы (поступление товаров, заказы). Особые сложности могут возникнуть, когда дополнительный реквизит имеет тип значения "Дополнительное значение". В этом случае требуется не просто присвоить строку или число, а указать ссылку на соответствующий элемент из специального справочника. В этом руководстве мы подробно разберем, как эффективно решать эту задачу, используя как стандартные механизмы Библиотеки стандартных подсистем (БСП), так и прямой доступ к данным объекта.
Дополнительные реквизиты и сведения в 1С:Предприятии 8.3 представляют собой мощный механизм для расширения функциональности типовых объектов без изменения их структуры. Они позволяют добавлять произвольные свойства объектам, таким как справочники, документы, планы видов характеристик и т.д. Определение самих дополнительных реквизитов хранится в плане видов характеристик ДополнительныеРеквизитыИСведения. Типы значений таких реквизитов могут быть самыми разнообразными: число, строка, дата, булево, ссылки на справочники, документы и, что наиболее важно для нашей задачи, тип "Дополнительное значение".
Когда дополнительный реквизит имеет тип "Дополнительное значение", это означает, что его возможные значения предопределены и хранятся в специальном справочнике ЗначенияСвойствОбъектов. Для корректной программной записи такого реквизита необходимо оперировать не строковым представлением значения, а именно ссылкой на соответствующий элемент этого справочника.
УправлениеСвойствами.ЗаписатьСвойстваУОбъекта()Наиболее рекомендуемым и универсальным способом работы с дополнительными реквизитами в типовых конфигурациях, использующих Библиотеку стандартных подсистем (БСП), является обращение к процедуре УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(). Этот подход обеспечивает корректную запись данных, соблюдение транзакционности и обрабатывает многие нюансы, связанные с хранением свойств.
Прежде всего, нам нужна ссылка на объект, которому мы хотим присвоить дополнительный реквизит. Это может быть элемент справочника (например, Справочники.Номенклатура.НайтиПоКоду("00001")) или документ (например, Документы.ПоступлениеТоваровУслуг.НайтиПоНомеру("0000-000001")).
Каждый дополнительный реквизит является элементом плана видов характеристик ДополнительныеРеквизитыИСведения. Мы можем найти его по наименованию. Обычно наименование включает в себя название реквизита и (в скобках) название объекта-владельца, для которого он предназначен. Использование параметра Истина во втором аргументе метода НайтиПоНаименованию() позволяет искать по полному наименованию, включая скобки.
ОпределениеДопРеквизита = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("СтатусОбработки (Поступление товаров и услуг)", Истина);
Если ОпределениеДопРеквизита = Неопределено Тогда
Сообщить("Дополнительный реквизит 'СтатусОбработки' не найден!");
Возврат;
КонецЕсли;
Иногда реквизит можно найти по другим полям, например, по реквизиту Заголовок, как показано в одном из примеров:
ДопРеквизитВес = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Заголовок", "Вес(кг)");
Если наш дополнительный реквизит имеет тип "Дополнительное значение", то его фактические значения хранятся в справочнике ЗначенияСвойствОбъектов. Для присвоения такого реквизита нам нужна именно ссылка на элемент этого справочника, а не его строковое представление. Используем метод НайтиПоНаименованию() для справочника ЗначенияСвойствОбъектов.
ЗначениеДопРеквизита = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию("Обработан");
Если ЗначениеДопРеквизита = Неопределено Тогда
Сообщить("Значение 'Обработан' для дополнительного реквизита не найдено!");
Возврат;
КонецЕсли;
Важно: Если дополнительный реквизит имеет другой тип (например, "Число" или "Строка"), то в качестве значения следует передавать соответствующее число или строку. Критически важно, чтобы тип передаваемого значения совпадал с типом, указанным в определении дополнительного реквизита.
Процедура ЗаписатьСвойстваУОбъекта() ожидает в качестве второго параметра ТаблицуЗначений. Эта таблица должна содержать две колонки: "Свойство" и "Значение".
ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения и содержать ссылку на определение нашего дополнительного реквизита.
ТаблицаДопРеквизитов = Новый ТаблицаЗначений;
ТаблицаДопРеквизитов.Колонки.Добавить("Свойство", Новый ОписаниеТипов("ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения"));
ТаблицаДопРеквизитов.Колонки.Добавить("Значение");
// Добавляем строку для нашего реквизита
НоваяСтрока = ТаблицаДопРеквизитов.Добавить();
НоваяСтрока.Свойство = ОпределениеДопРеквизита;
НоваяСтрока.Значение = ЗначениеДопРеквизита; // Если тип "Дополнительное значение", то здесь ссылка на Справочник.ЗначенияСвойствОбъектов
// Пример добавления другого реквизита, например, числового
ОпределениеДопРеквизитаВес = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Вес(кг) (Номенклатура)", Истина);
Если ОпределениеДопРеквизитаВес <> Неопределено Тогда
НоваяСтрокаВес = ТаблицаДопРеквизитов.Добавить();
НоваяСтрокаВес.Свойство = ОпределениеДопРеквизитаВес;
НоваяСтрокаВес.Значение = 15.5; // Числовое значение
КонецЕсли;
После подготовки всех данных мы можем вызвать процедуру УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(), передав ей ссылку на объект-владелец и сформированную таблицу значений.
// Предположим, ДокументПоступления - это ссылка на объект, которому присваиваем реквизиты
УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(ДокументПоступления, ТаблицаДопРеквизитов);
Полный пример с использованием БСП для записи реквизита типа "Дополнительное значение":
// 1. Получаем ссылку на объект, которому будем записывать доп. реквизит
// Например, если это документ "Поступление товаров и услуг"
ДокументПоступления = Документы.ПоступлениеТоваровУслуг.НайтиПоНомеру("0000-000001");
Если ДокументПоступления = Неопределено Тогда
Сообщить("Документ не найден!");
Возврат;
КонецЕсли;
// 2. Находим определение дополнительного реквизита
// Предположим, имя доп. реквизита "СтатусОбработки"
// и он относится к "Поступление товаров и услуг"
ОпределениеДопРеквизита = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("СтатусОбработки (Поступление товаров и услуг)", Истина);
Если ОпределениеДопРеквизита = Неопределено Тогда
Сообщить("Дополнительный реквизит 'СтатусОбработки' не найден!");
Возврат;
КонецЕсли;
// 3. Находим нужное значение в справочнике "ЗначенияСвойствОбъектов"
// Предположим, мы хотим установить значение "Обработан"
ЗначениеДопРеквизита = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию("Обработан");
Если ЗначениеДопРеквизита = Неопределено Тогда
Сообщить("Значение 'Обработан' для дополнительного реквизита не найдено!");
Возврат;
КонецЕсли;
// 4. Формируем ТаблицуЗначений для записи
ТаблицаДопРеквизитов = Новый ТаблицаЗначений;
ТаблицаДопРеквизитов.Колонки.Добавить("Свойство", Новый ОписаниеТипов("ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения"));
ТаблицаДопРеквизитов.Колонки.Добавить("Значение");
НоваяСтрока = ТаблицаДопРеквизитов.Добавить();
НоваяСтрока.Свойство = ОпределениеДопРеквизита;
НоваяСтрока.Значение = ЗначениеДопРеквизита; // Здесь передается именно ссылка на элемент справочника!
// Пример с числовым реквизитом "Вес"
ОпределениеДопРеквизитаВес = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Вес(кг) (Поступление товаров и услуг)", Истина);
Если ОпределениеДопРеквизитаВес <> Неопределено Тогда
НоваяСтрокаВес = ТаблицаДопРеквизитов.Добавить();
НоваяСтрокаВес.Свойство = ОпределениеДопРеквизитаВес;
НоваяСтрокаВес.Значение = 25.75; // Числовое значение
КонецЕсли;
// 5. Записываем дополнительные реквизиты
УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(ДокументПоступления, ТаблицаДопРеквизитов);
Сообщить("Дополнительные реквизиты успешно записаны для документа: " + ДокументПоступления);
Если возможностей доп. реквизитов недостаточно, рассмотрите универсальный механизм добавления табличных частей с помощью расширения конфигураций на основе 1С:БСП.
В некоторых случаях, если БСП по какой-либо причине недоступна или вы предпочитаете более прямой контроль, можно работать непосредственно с табличной частью ДополнительныеРеквизиты объекта. Этот метод требует получения самого объекта, а не только его ссылки.
Для прямого доступа к свойствам объекта нам потребуется не ссылка, а сам объект. Это делается с помощью метода ПолучитьОбъект().
ОбъектНоменклатура = Справочники.Номенклатура.НайтиПоКоду("00001").ПолучитьОбъект();
Если ОбъектНоменклатура = Неопределено Тогда
Сообщить("Элемент номенклатуры не найден!");
Возврат;
КонецЕсли;
Как и в случае с БСП, сначала нам нужно найти элемент плана видов характеристик, который определяет наш дополнительный реквизит.
ДопРеквизитСвойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Вид деятельности (Номенклатура)", Истина);
Если ДопРеквизитСвойство = Неопределено Тогда
Сообщить("Дополнительный реквизит 'Вид деятельности' не найден!");
Возврат;
КонецЕсли;
Если реквизит имеет тип "Дополнительное значение", то мы ищем его в справочнике ЗначенияСвойствОбъектов.
ЗначениеДеятельности = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию("Прочая деятельность");
Если ЗначениеДеятельности = Неопределено Тогда
Сообщить("Значение 'Прочая деятельность' для дополнительного реквизита не найдено.");
Возврат;
КонецЕсли;
Если реквизит другого типа (например, "Строка"), то мы используем соответствующее значение:
ЗначениеКомментария = "Важный комментарий к элементу";
ДополнительныеРеквизиты:
У каждого объекта, поддерживающего дополнительные реквизиты, есть табличная часть с именем ДополнительныеРеквизиты. Нам нужно найти в ней строку, соответствующую нашему реквизиту. Если такая строка уже существует, мы изменяем ее значение. Если нет — добавляем новую строку.
// Проверяем, существует ли уже такой реквизит у объекта
НайденнаяСтрока = ОбъектНоменклатура.ДополнительныеРеквизиты.Найти(ДопРеквизитСвойство, "Свойство");
Если НайденнаяСтрока = Неопределено Тогда
// Если нет, добавляем новую строку
ДопРеквизит = ОбъектНоменклатура.ДополнительныеРеквизиты.Добавить();
ДопРеквизит.Свойство = ДопРеквизитСвойство;
Иначе
// Если есть, используем существующую строку
ДопРеквизит = НайденаяСтрока;
КонецЕсли;
// Присваиваем значение
ДопРеквизит.Значение = ЗначениеДеятельности; // Здесь передаем ссылку на Справочник.ЗначенияСвойствОбъектов
После всех изменений необходимо записать сам объект, чтобы изменения в табличной части сохранились.
Попытка
ОбъектНоменклатура.Записать();
Сообщить("Дополнительный реквизит успешно записан для номенклатуры: " + ОбъектНоменклатура.Наименование);
Исключение Е
Сообщить("Ошибка при записи объекта: " + Е.Описание);
КонецПопытки;
Полный пример прямой записи дополнительного реквизита типа "Дополнительное значение":
// 1. Получаем объект, которому присваиваем доп. реквизит
ОбъектНоменклатура = Справочники.Номенклатура.НайтиПоКоду("00001").ПолучитьОбъект();
Если ОбъектНоменклатура = Неопределено Тогда
Сообщить("Элемент номенклатуры с кодом '00001' не найден.");
Возврат;
КонецЕсли;
// 2. Находим определение дополнительного реквизита "Вид деятельности"
ДопРеквизитСвойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Вид деятельности (Номенклатура)", Истина);
Если ДопРеквизитСвойство = Неопределено Тогда
Сообщить("Дополнительный реквизит 'Вид деятельности' не найден.");
Возврат;
Ко конецЕсли;
// 3. Находим нужное значение "Прочая деятельность" в справочнике ЗначенияСвойствОбъектов
ЗначениеДеятельности = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию("Прочая деятельность");
Если ЗначениеДеятельности = Неопределено Тогда
Сообщить("Значение 'Прочая деятельность' для дополнительного реквизита не найдено.");
Возврат;
КонецЕсли;
// 4. Работаем с табличной частью ДополнительныеРеквизиты объекта
ДопРеквизитСтрока = ОбъектНоменклатура.ДополнительныеРеквизиты.Найти(ДопРеквизитСвойство, "Свойство");
Если ДопРеквизитСтрока = Неопределено Тогда
// Если реквизита еще нет, добавляем новую строку
ДопРеквизитСтрока = ОбъектНоменклатура.ДополнительныеРеквизиты.Добавить();
ДопРеквизитСтрока.Свойство = ДопРеквизитСвойство;
КонецЕсли;
ДопРеквизитСтрока.Значение = ЗначениеДеятельности; // Присваиваем ссылку на элемент справочника
// Пример с другим реквизитом, например, строковым "Комментарий"
ДопРеквизитКомментарийСвойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Комментарий (Номенклатура)", Истина);
Если ДопРеквизитКомментарийСвойство <> Неопределено Тогда
ДопРеквизитСтрокаКомментарий = ОбъектНоменклатура.ДополнительныеРеквизиты.Найти(ДопРеквизитКомментарийСвойство, "Свойство");
Если ДопРеквизитСтрокаКомментарий = Неопределено Тогда
ДопРеквизитСтрокаКомментарий = ОбъектНоменклатура.ДополнительныеРеквизиты.Добавить();
ДопРеквизитСтрокаКомментарий.Свойство = ДопРеквизитКомментарийСвойство;
КонецЕсли;
ДопРеквизитСтрокаКомментарий.Значение = "Это важный комментарий, добавленный программно."; // Строковое значение
КонецЕсли;
// 5. Записываем объект
Попытка
ОбъектНоменклатура.Записать();
Сообщить("Дополнительные реквизиты для номенклатуры '" + ОбъектНоменклатура.Наименование + "' успешно обновлены.");
Исключение Е
Сообщить("Ошибка при записи объекта: " + Е.Описание);
КонецПопытки;
Неопределено: Всегда проверяйте, что результаты поиска (как определений реквизитов, так и их значений) не являются Неопределено. Это поможет избежать ошибок "Метод объекта не обнаружен" или "Объект не найден".ЗначенияСвойствОбъектов, нельзя передавать произвольную строку, даже если она совпадает с наименованием элемента справочника.ЗначенияСвойствОбъектов и изменение объектов-владельцев.УправлениеСвойствами.ЗаписатьСвойстваУОбъекта() обеспечивает транзакционность изменений. Это означает, что либо все изменения запишутся успешно, либо ни одно. При прямой работе с объектом вам придется самостоятельно заботиться о транзакциях, если это необходимо.Мы рассмотрели два основных способа программной записи дополнительных реквизитов в 1С, включая наиболее сложный случай с типом "Дополнительное значение". Всегда отдавайте предпочтение стандартным механизмам БСП, так как они более надежны и поддерживаются разработчиками платформы, но знайте и о возможности прямого доступа к данным объекта. Помните о важности соответствия типов значений и тщательной проверке на существование всех необходимых элементов.