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