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