Как программно заполнить дополнительные реквизиты документа при выборе контрагента?

Программист 1С v8.3 (Управляемые формы) 1С:Управление нашей фирмой Управленческий учет IT и автоматизация бизнеса
← На главную

Часто при доработке конфигураций на базе Библиотеки стандартных подсистем (БСП), например, в 1С:Управление нашей фирмой (УНФ), возникает типовая задача: при выборе контрагента в документе (допустим, в документе ЗаказНаряд) необходимо автоматически заполнять дополнительные реквизиты самого документа значениями из дополнительных реквизитов выбранного контрагента. Разберем по шагам, как правильно реализовать эту логику, проанализируем частые ошибки и рассмотрим использование стандартного программного интерфейса БСП.

Анализ проблемы и частых ошибок

Посмотрим на пример кода, который часто пишут разработчики при попытке решить данную задачу «в лоб». В обработчике ПриИзменении поля контрагента выполняется запрос к табличной части дополнительных реквизитов контрагента, а затем происходит попытка записать эти данные напрямую в объект документа:


// Фрагмент ошибочного кода
ЕстьСтроки = Объект.ДополнительныеРеквизиты.НайтиСтроки(Новый Структура("Свойство", ДопРеквизитСсылка));
ДокОбъект = Объект.ПолучитьОбъект(); // Вызовет ошибку
Если ЕстьСтроки.Количество() = 0 Тогда
    СтрокаТЧ = Объект.ДополнительныеРеквизиты.Добавить();
    СтрокаТЧ.Свойство = ДопРеквизитСсылка;
Иначе
    СтрокаТЧ = ЕстьСтроки[0];
КонецЕсли;
СтрокаТЧ.Значение = ВыборкаДетальныеЗаписи.Значение;
Объект.Записать(); // Грубая архитектурная ошибка

Проанализируем ситуацию и выясним причину, почему данный код не работает на управляемых формах:

  1. Ошибка контекста формы: Программа выдаст ошибку Метод объекта не обнаружен (ПолучитьОбъект). Дело в том, что в контексте управляемой формы переменная Объект имеет тип ДанныеФормыСтруктура, а не является ссылкой или реальным объектом базы данных (ДокументОбъект). У данных формы просто нет такого метода.
  2. Запись документа «на лету»: Вызов метода записи документа непосредственно при изменении реквизита (выборе контрагента) является грубым нарушением UX (пользовательского опыта). Пользователь только выбрал контрагента и, возможно, передумает сохранять документ, но система уже записала его в базу. Заполнять необходимо только элементы на текущей форме, оставляя право на запись пользователю.
  3. Прямые запросы к ПВХ: Писать громоздкие запросы к табличным частям и планам видов характеристик для получения дополнительных свойств — это создание «велосипеда». В БСП есть готовый интерфейс для этих задач.

Как правильно работать с доп. реквизитами через API БСП

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

Рассмотрим подробнее, как организовано хранение. Чтобы связать реальный дополнительный реквизит (ссылку на ПВХ) и поле на форме, БСП создает специальные служебные таблицы значений прямо в реквизитах формы. Основная из них называется Свойства_ОписаниеДополнительныхРеквизитов. Именно в этой таблице хранится соответствие: какое свойство привязано к какому строковому имени сгенерированного реквизита формы.

Для чтения значений свойств БСП предоставляет удобные функции общего модуля УправлениеСвойствами:

Пошаговый алгоритм решения

Давайте реализуем правильный алгоритм переноса значений из контрагента в заказ-наряд.

Шаг 1. Обработка события на клиенте.
В модуле формы в обработчике события ПриИзменении поля контрагента нам необходимо вызвать серверную процедуру для выполнения расчетов.


&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
    
    Если ЗначениеЗаполнено(Объект.Контрагент) Тогда
        ЗаполнитьДопРеквизитыПоКонтрагентуНаСервере();
    КонецЕсли;
    
КонецПроцедуры

Шаг 2. Чтение и перенос свойств на сервере.
На сервере мы прочитаем свойства контрагента и обойдем служебную таблицу Свойства_ОписаниеДополнительныхРеквизитов текущей формы, чтобы найти соответствующие реквизиты заказ-наряда и заполнить их значения.


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

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

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

← На главную