При разработке интеграций и программном переносе данных в конфигурациях на базе Библиотеки стандартных подсистем (БСП), таких как «1С:Управление торговлей 11», «1С:ERP» или «1С:Комплексная автоматизация», разработчики часто сталкиваются со следующей проблемой. При программном добавлении строки в табличную часть КонтактнаяИнформация контрагента или партнера данные успешно записываются в базу данных, однако при открытии карточки в интерфейсе поля КИ оказываются пустыми. Более того, при первом же интерактивном сохранении (нажатии кнопки «Записать и закрыть») программно добавленные данные бесследно исчезают.
В этой статье мы подробно разберем внутренние механизмы работы подсистемы КИ в БСП, выясним причины очистки табличной части и рассмотрим правильные, архитектурно верные способы программного заполнения контактной информации.
Попытка заполнить табличную часть простым добавлением строк напрямую, как показано в примере ниже, является главной ошибкой:
// Ошибочный подход прямого заполнения табличной части
НоваяСтрока = СоздатьНовогоКонтрагента.КонтактнаяИнформация.Добавить();
НоваяСтрока.Тип = Перечисления.ТипыКонтактнойИнформации.АдресЭлектроннойПочты;
НоваяСтрока.Вид = Справочники.ВидыКонтактнойИнформации.EmailКонтрагента;
НоваяСтрока.Представление = "test@email.ru";
СоздатьНовогоКонтрагента.Записать();
Чтобы понять, почему этот код не работает в долгосрочной перспективе, проанализируем архитектуру хранения КИ в БСП:
ЗначенияПолей. БСП не считывает напрямую колонку Представление или АдресЭП для отображения данных на управляемой форме. Вместо этого используется служебная колонка ЗначенияПолей, где подробный состав контактной информации (индексы, города, улицы, коды стран и телефонов) хранится в сериализованном XML- или JSON-формате. Если это поле остается пустым, управляемая форма считает, что контактная информация не заполнена вовсе.ЗначенияПолей. Поскольку при прямом заполнении ТЧ это поле было пустым, поля ввода на форме остаются незаполненными.ПередЗаписьюНаСервере. Система сопоставляет данные на форме с данными в объекте. Так как на форме визуальные поля ввода КИ пусты, платформа считает их актуальными и затирает существующие строки в табличной части, перезаписывая их пустыми значениями.СкрываемыеВиды. В коде формы существует проверка видимости видов КИ. Если массив скрываемых видов пуст, срабатывает типовой алгоритм очистки: Объект.КонтактнаяИнформация.Очистить(), после чего табличная часть заполняется заново на основании того, что было введено на форме.Для корректного сохранения данных нам необходимо использовать специализированный программный интерфейс (API) Библиотеки стандартных подсистем.
Самый простой и надежный способ программного добавления контактной информации для нового или существующего объекта — использование метода публичного модуля УправлениеКонтактнойИнформацией. Этот метод берет на себя всю рутину по формированию правильной XML/JSON-структуры для поля ЗначенияПолей.
Рассмотрим пример создания контрагента и заполнения его Email-адреса:
// 1. Создаем объект контрагента
НовыйКонтрагент = Справочники.Контрагенты.СоздатьЭлемент();
НовыйКонтрагент.Наименование = "ООО Ромашка";
НовыйКонтрагент.НаименованиеПолное = "Общество с ограниченной ответственностью 'Ромашка'";
// Для новых (еще не записанных) объектов крайне важно предварительно получить и установить ссылку,
// так как контактная информация должна ссылаться на владельца.
НоваяСсылка = Справочники.Контрагенты.ПолучитьСсылку();
НовыйКонтрагент.УстановитьСсылкуНового(НоваяСсылка);
// 2. Определяем параметры контактной информации
EmailАдрес = "romashka@example.com";
ВидКИ = Справочники.ВидыКонтактнойИнформации.EmailКонтрагента;
// 3. Используем штатный метод БСП для добавления информации в объект
УправлениеКонтактнойИнформацией.ДобавитьКонтактнуюИнформацию(
НовыйКонтрагент,
EmailАдрес,
ВидКИ,
ТекущаяДатаСеанса(),
Ложь // Признак того, что запись производится в объект (в ТЧ), а не напрямую в регистр сведений
);
// 4. Записываем сам объект контрагента
НовыйКонтрагент.Записать();
Важное примечание: Обратите внимание на выбор вида контактной информации. Для контрагента необходимо указывать строго Справочники.ВидыКонтактнойИнформации.EmailКонтрагента, а для партнера — Справочники.ВидыКонтактнойИнформации.EmailПартнера. Ошибка в выборе предопределенного вида КИ приведет к тому, что информация будет записана в базу, но не отобразится в карточке соответствующего справочника.
Если объект уже существует в базе данных и у вас есть его ссылка, вам не обязательно получать объект, изменять его табличную часть и перезаписывать весь элемент целиком. БСП предоставляет возможность внести КИ напрямую через транзакционную запись.
Давайте разберем, как обновить адрес электронной почты существующего контрагента:
СсылкаНаКонтрагента = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", "7701020304");
Если Не СсылкаНаКонтрагента.Пустая() Тогда
EmailАдрес = "info@romashka.ru";
ВидКИ = Справочники.ВидыКонтактнойИнформации.EmailКонтрагента;
ТипКИ = Перечисления.ТипыКонтактнойИнформации.АдресЭлектроннойПочты;
// Формируем XML-представление структуры полей КИ
ОбъектXDTO = УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияXDTOПоПредставлению(EmailАдрес, ТипКИ);
ЗначенияПолейXML = УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияXDTOВXML(ОбъектXDTO);
// Выполняем запись КИ без перезаписи самого контрагента
УправлениеКонтактнойИнформацией.ЗаписатьКонтактнуюИнформацию(
СсылкаНаКонтрагента,
ЗначенияПолейXML,
ВидКИ,
ТипКИ
);
КонецЕсли;
Использование этого метода существенно повышает производительность системы при массовой загрузке КИ (например, при первоначальном переносе данных из других систем), так как минимизирует количество блокировок и транзакций по записи тяжелых справочников.
В случаях, когда необходимо программно заполнить сразу множество различных видов контактной информации (например, телефон, юридический адрес, фактический адрес и веб-сайт), удобно подготовить таблицу значений КИ и применить ее к объекту одним методом.
Проанализируем пример комплексного заполнения КИ для нового партнера:
НовыйПартнер = Справочники.Партнеры.СоздатьЭлемент();
НовыйПартнер.Наименование = "Торговый Дом Вектор";
НовыйПартнер.Клиент = Истина;
СсылкаПартнера = Справочники.Партнеры.ПолучитьСсылку();
НовыйПартнер.УстановитьСсылкуНового(СсылкаПартнера);
// Получаем пустую таблицу структуры КИ, соответствующую структуре объекта
ТаблицаКИ = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъекта(НовыйПартнер, , ТекущаяДатаСеанса());
// Заполняем Телефон
СтрокаТелефон = ТаблицаКИ.Добавить();
СтрокаТелефон.Объект = СсылкаПартнера;
СтрокаТелефон.Вид = Справочники.ВидыКонтактнойИнформации.ТелефонПартнера;
СтрокаТелефон.Тип = Перечисления.ТипыКонтактнойИнформации.Телефон;
СтрокаТелефон.Представление = "+7 (999) 111-22-33";
// Создаем XML структуру для телефона
ОбъектXDTOТелефон = УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияXDTOПоПредставлению(СтрокаТелефон.Представление, СтрокаТелефон.Тип);
СтрокаТелефон.ЗначенияПолей = УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияXDTOВXML(ОбъектXDTOТелефон);
// Заполняем Email
СтрокаEmail = ТаблицаКИ.Добавить();
СтрокаEmail.Объект = СсылкаПартнера;
СтрокаEmail.Вид = Справочники.ВидыКонтактнойИнформации.EmailПартнера;
СтрокаEmail.Тип = Перечисления.ТипыКонтактнойИнформации.АдресЭлектроннойПочты;
СтрокаEmail.Представление = "sales@vector.ru";
СтрокаEmail.АдресЭП = "sales@vector.ru";
// Создаем XML структуру для почты
ОбъектXDTOEmail = УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияXDTOПоПредставлению(СтрокаEmail.Представление, СтрокаEmail.Тип);
СтрокаEmail.ЗначенияПолей = УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияXDTOВXML(ОбъектXDTOEmail);
// Переносим заполненную таблицу обратно в объект партнера
УправлениеКонтактнойИнформацией.УстановитьКонтактнуюИнформациюОбъекта(НовыйПартнер, ТаблицаКИ, Истина);
// Сохраняем партнера
НовыйПартнер.Записать();
Помните о разделении сущностей Партнеры (управленческий учет) и Контрагенты (регламентированный учет, юридические лица). Если вы создаете полноценного контрагента, в системе УТ 11 обязательно должен быть создан связанный с ним партнер.
Для корректного сопоставления КИ между партнером и контрагентом рекомендуется использовать встроенный метод:
ПартнерыИКонтрагенты.ЗаполнитьКонтактнуюИнформациюКонтрагентаПартнера()
Это позволит синхронизировать данные КИ и избежать расхождений в реквизитах при работе менеджеров в интерфейсе программы.