При работе с типовыми конфигурациями на базе Библиотеки стандартных подсистем (БСП) разработчики часто сталкиваются с механизмом дополнительных реквизитов. Особенность этого механизма заключается в том, что реквизиты не существуют в объекте изначально, а добавляются на форму динамически. В этой статье мы подробно разберем, как правильно найти такой реквизит программно и установить его значение при изменении других данных на форме, например, при выборе склада.
Для начала проанализируем, как БСП отображает дополнительные реквизиты. Когда открывается форма объекта (документа или справочника), система считывает настройки из планов видов характеристик и динамически создает программные реквизиты формы. Эти реквизиты обычно имеют сложные технические имена вида ДополнительныйРеквизит_Гв123.... Напрямую обращаться к ним по таким именам нельзя, так как идентификаторы могут меняться.
Вся информация о соответствии реальных свойств и динамических имен на форме хранится в служебной таблице (коллекции), которая обычно называется Свойства_ОписаниеДополнительныхРеквизитов. Наша задача — найти в этой таблице нужную строку и обратиться к реквизиту по его внутреннему имени.
Рассмотрим стандартный подход, когда нам известно наименование дополнительного реквизита. Этот метод прост в реализации, но имеет существенный минус: если пользователь изменит название реквизита в пользовательском режиме, код перестанет работать.
Разберем пример кода для установки значения реквизита "Направление продаж":
// 1. Находим ссылку на само свойство (ПВХ)
Свойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Направление продаж");
// 2. Ищем описание этого свойства в коллекции формы
СтруктураПоиска = Новый Структура("Свойство", Свойство);
МассивСтрок = ЭтотОбъект.Свойства_ОписаниеДополнительныхРеквизитов.НайтиСтроки(СтруктураПоиска);
Если МассивСтрок.Количество() > 0 Тогда
ОписаниеСвойства = МассивСтрок[0];
// 3. Получаем динамическое имя реквизита на форме
ИмяСвойстваНаФорме = ОписаниеСвойства.ИмяРеквизитаЗначение;
// 4. Устанавливаем значение (например, ссылку на справочник ЗначенияСвойствОбъектов)
ЭтотОбъект[ИмяСвойстваНаФорме] = Справочники.ЗначенияСвойствОбъектов.НайтиПоНаименованию("Коммерческие продажи", , , Свойство);
КонецЕсли;
Выясним причину, по которой первый способ считается ненадежным. Наименование — это строковое поле, которое видит пользователь. Более правильным подходом является использование реквизита «Имя» (так называемое имя для разработчиков). Оно задается в карточке дополнительного реквизита на вкладке «Главное» (в подразделе «Для разработчиков»).
Проанализируем улучшенный вариант кода:
// Поиск свойства по уникальному коду/имени для разработчика более надежен
Свойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Имя", "НаправлениеПродаж_Спец");
СтруктураПоиска = Новый Структура("Свойство", Свойство);
МассивСтрок = ЭтотОбъект.Свойства_ОписаниеДополнительныхРеквизитов.НайтиСтроки(СтруктураПоиска);
Если МассивСтрок.Количество() > 0 Тогда
ИмяРеквизита = МассивСтрок[0].ИмяРеквизитаЗначение;
ЭтотОбъект[ИмяРеквизита] = НужноеЗначение;
КонецЕсли;
Просто присвоить значение в ЭтотОбъект[ИмяРеквизита] иногда недостаточно. В БСП дополнительные реквизиты могут зависеть друг от друга (например, один реквизит становится видимым только при заполнении другого). Чтобы система «увидела» программное изменение, необходимо вызвать специальные процедуры БСП.
После изменения значения на клиенте рекомендуется вызвать метод:
УправлениеСвойствамиКлиент.ПослеИзмененияДополнительногоРеквизита(ЭтотОбъект, Элемент);
Где Элемент — это элемент формы, связанный с данным реквизитом. Это инициирует пересчет правил видимости, доступности и обязательности заполнения.
Посмотрим на ситуацию с точки зрения чистоты кода. Если в вашей конфигурации часто требуется заполнять дополнительные реквизиты, логично вынести этот функционал в общий модуль. Рассмотрим пример такой процедуры:
// Процедура в общем модуле (сервер)
Процедура УстановитьЗначениеДопРеквизита(Форма, ИмяСвойстваБСП, Значение) Экспорт
СвойствоСсылка = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Имя", ИмяСвойстваБСП);
Если СвойствоСсылка.Пустая() Тогда
Возврат;
КонецЕсли;
ПараметрыПоиска = Новый Структура("Свойство", СвойствоСсылка);
СтрокиОписание = Форма.Свойства_ОписаниеДополнительныхРеквизитов.НайтиСтроки(ПараметрыПоиска);
Если СтрокиОписание.Количество() > 0 Тогда
ИмяРеквизитаНаФорме = СтрокиОписание[0].ИмяРеквизитаЗначение;
Форма[ИмяРеквизитаНаФорме] = Значение;
КонецЕсли;
КонецПроцедуры
Существует еще один способ решения задачи. Вместо того чтобы искать программные реквизиты на форме, мы можем изменить данные непосредственно в объекте, а затем дать команду форме перечитать эти данные.
Объект.ДополнительныеРеквизиты.УправлениеСвойствами.ЗаполнитьДополнительныеРеквизитыВФорме(ЭтотОбъект, Объект);.Этот метод считается наиболее «чистым» с точки зрения архитектуры БСП, так как он задействует стандартные механизмы синхронизации данных между объектом и его визуальным представлением на форме.
Важный момент: если вы решите полностью отказаться от механизма дополнительных реквизитов и добавить обычный реквизит в конфигураторе, это упростит написание кода (обращение будет идти через точку: Объект.МойРеквизит), но вы потеряете гибкость настройки системы пользователями без участия программиста. Выбор за вами, но использование методов БСП позволяет сохранить баланс между удобством разработки и возможностями системы.