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