При разработке интеграций, загрузок данных из внешних источников или фоновых заданий программисты часто сталкиваются с ситуацией, когда необходимо программно создать или обновить элемент справочника (например, контрагента или физическое лицо) и заполнить его контактную информацию (адреса, телефоны, email). Однако при попытке просто записать объект разработчики замечают, что некоторые служебные или скрытые реквизиты остаются пустыми. В интерактивном режиме эти реквизиты заполняются автоматически в процедуре ПередЗаписьюНаСервере модуля формы. Попытка получить форму на сервере через функцию ПолучитьФорму приводит к критической ошибке компиляции.
В этой статье мы подробно разберем, почему возникает эта ошибка, как устроена подсистема «Контактная информация» в Библиотеке стандартных подсистем (БСП) и как правильно, с точки зрения архитектуры 1С, решать задачу заполнения данных полностью на сервере без привлечения клиентского контекста.
Давайте проанализируем ошибку, с которой столкнулся автор темы. В коде внешней обработки на сервере выполняется следующая конструкция:
ФормаСправочника = ПолучитьФорму("Справочник.Контрагенты.ФормаОбъекта", новый Структура("Ключ", КонтрагентОбъект.Ссылка));
Система возвращает ошибку: «Процедура или функция с указанным именем не определена (ПолучитьФорму)». Это происходит потому, что метод ПолучитьФорму предназначен для создания интерфейсных объектов и доступен исключительно на клиенте (в тонком, толстом или веб-клиенте). На сервере (в серверном модуле обработки, общем модуле или модуле менеджера) физически не существует контекста отображения. Попытка обойти это ограничение через клиентский цикл (как показано в Сообщении 2 темы) является крайне неэффективной, замедляет работу системы и абсолютно неприменима в фоновых заданиях или API-сервисах.
Кроме того, логика, заложенная в обработчиках формы (таких как ПередЗаписьюНаСервере), оперирует элементами управления, экранными данными и структурой ДанныеФормыСтруктура, а не чистым объектом базы данных СправочникОбъект. Пытаться искусственно воссоздать эту форму на сервере — тупиковый путь, увеличивающий технический долг.
Чтобы понять, как решить задачу правильно, проанализируем, что именно делает форма при записи контактной информации (КИ). В конфигурациях на базе БСП (например, «Бухгалтерия предприятия 3.0», «ERP Управление предприятием», «Управление торговлей») контактная информация хранится в табличной части справочника (например, табличная часть КонтактнаяИнформация). Она состоит из нескольких ключевых полей:
Если мы программно заполним только поле Представление и запишем объект, то при открытии карточки контрагента пользователь увидит пустые поля в формах ввода адреса. БСП просто не сможет распарсить плоскую строку без XML/JSON-структуры. Именно эти структуры и генерируются «под капотом» при интерактивной работе. Наша задача — научиться формировать их программно на сервере.
Для работы с контактной информацией без использования форм в БСП предусмотрен специальный программный интерфейс (API), сосредоточенный в общем модуле УправлениеКонтактнойИнформацией. Рассмотрим наиболее эффективные методы.
Если у нас есть только строка адреса (например, полученная из файла импорта), нам необходимо преобразовать её в валидную XML/JSON структуру БСП, а затем записать в объект. Разберем этот процесс по шагам.
Шаг 1. Создадим функцию преобразования плоской строки представления в формат XML/JSON:
Функция ПолучитьЗначениеКонтактнойИнформации(Знач Представление, Знач ТипКИ) Экспорт
// Получаем объект XDTO на основе текстового представления адреса или телефона
ОбъектXDTO = УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияXDTOПоПредставлению(Представление, ТипКИ);
// Сериализуем XDTO в XML-строку для поля "ЗначенияПолей"
ЗначенияПолейXML = УправлениеКонтактнойИнформациейСлужебный.ContactнаяИнформацияXDTOВXML(ОбъектXDTO);
// Конвертируем полученный XML в JSON-формат для поля "Значение"
Возврат УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВJSON(ЗначенияПолейXML);
КонецФункции
Шаг 2. Применим полученную функцию при записи объекта контрагента:
Процедура ЗаполнитьИЗаписатьКонтрагента()
// Предположим, у нас уже есть ссылка на контрагента или мы создаем нового
КонтрагентОбъект = Справочники.Контрагенты.СоздатьЭлемент();
КонтрагентОбъект.Наименование = "ООО Новые Технологии";
// Получаем нужный вид контактной информации (например, Юридический адрес)
ВидКИ = Справочники.ВидыКонтактнойИнформации.ЮридическийАдресКонтрагента;
ТипКИ = Перечисления.ТипыКонтактнойИнформации.Адрес;
СтрокаАдреса = "101000, г. Москва, ул. Мясницкая, д. 10";
// Формируем валидное XML/JSON представление для БСП
ЗначениеJSON = ПолучитьЗначениеКонтактнойИнформации(СтрокаАдреса, ТипКИ);
// Используем штатный метод БСП для добавления информации в объект
УправлениеКонтактнойИнформацией.ДобавитьКонтактнуюИнформацию(
КонтрагентОбъект,
ЗначениеJSON,
ВидКИ,
ТекущаяДатаСеанса(),
Истина // Флаг "Замещать" — перезапишет существующий адрес этого вида
);
// Теперь объект содержит все необходимые технические поля и его можно безопасно записывать!
КонтрагентОбъект.Записать();
КонецПроцедуры
Если в вашей внешней обработке адрес уже разделен по колонкам (индекс, город, улица, дом), не нужно пытаться склеивать строку самостоятельно. БСП позволяет передать готовую структуру данных для генерации системных полей.
Рассмотрим пример детального заполнения адреса:
Процедура ЗаполнитьАдресИзСтруктуры(КонтрагентОбъект)
ВидКИ = Справочники.ВидыКонтактнойИнформации.ФактическийАдресКонтрагента;
ТипКИ = Перечисления.ТипыКонтактнойИнформации.Адрес;
// Создаем структуру описания адреса в формате БСП
АдресСтруктура = УправлениеКонтактнойИнформацией.ОписаниеНовойКонтактнойИнформации(ТипКИ);
АдресСтруктура.ZIPcode = "190000";
АдресСтруктура.country = "Россия";
АдресСтруктура.city = "г. Санкт-Петербург";
АдресСтруктура.street = "Невский пр-кт";
АдресСтруктура.houseNumber = "28";
// Преобразуем структуру в XML, а затем в JSON
АдресXML = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВXML(АдресСтруктура, , ТипКИ);
АдресJSON = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВJSON(АдресXML);
// Записываем подготовленные структурированные данные в объект контрагента
УправлениеКонтактнойИнформацией.ДобавитьКонтактнуюИнформацию(
КонтрагентОбъект,
АдресJSON,
ВидКИ,
ТекущаяДатаСеанса(),
Истина
);
КонтрагентОбъект.Записать();
КонецПроцедуры
Иногда разработчики сталкиваются с ситуацией, когда в процедуре формы ПередЗаписьюНаСервере прописан специфический программный код, добавленный другими программистами в рамках кастомизации конфигурации (не относящийся к стандартной БСП). Если этот код критически важен, правильным решением будет его рефакторинг:
ПередЗаписью модуля самого объекта (справочника или документа).ВызовСервера. В этом случае вы сможете вызывать процедуру как из формы, так и из своей внешней обработки, передавая туда в качестве параметра непосредственно КонтрагентОбъект.Пытаться получить или эмулировать форму на сервере для обхода ограничений записи — грубая архитектурная ошибка. Для корректной программной работы с контактной информацией в любых современных конфигурациях 1С всегда используйте штатные методы общего модуля УправлениеКонтактнойИнформацией. Это гарантирует целостность данных в базе, корректность разбора адресов по ФИАС и избавит вас от ошибок совместимости при будущих обновлениях системы.