Как программно заполнить контактную информацию контрагента во внешней обработке БП 3.0?

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

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

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

Анализ ошибки при копировании типового кода из формы

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


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

При выполнении этого кода во внешней обработке система выдаст ошибку о том, что поле КонтактнаяИнформацияОписаниеДополнительныхРеквизитов не найдено. Разберем, почему это происходит.

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

В модуле внешней обработки переменная ЭтотОбъект ссылается на саму обработку (объект метаданных ВнешняяОбработка), у которой, естественно, нет такой коллекции атрибутов. При фоновой или серверной загрузке записывать данные нужно напрямую в объект справочника (или его табличную часть), а не пытаться манипулировать элементами формы.

Ошибочный "костыльный" метод: почему прямое добавление строк опасно

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


Об = СпрКонтрагент.ПолучитьОбъект();
Адрес = Об.КонтактнаяИнформация.Добавить();
Адрес.Тип = Перечисления.ТипыКонтактнойИнформации.Адрес;
Адрес.Вид = Справочники.ВидыКонтактнойИнформации.ЮрАдресКонтрагента; 
Адрес.Представление = РеквизитыКонтрагента.ЮридическийАдрес.Представление;
Об.Записать();

Важно: в современных конфигурациях 1С, использующих подсистему "Контактная информация" из БСП, такой подход является грубейшей ошибкой!

В этом коде разработчик заполняет только текстовое поле Представление. В карточке контрагента этот адрес действительно появится в виде текста, и визуально все будет казаться нормальным. Однако для алгоритмов системы 1С реальные данные адреса хранятся не в строке представления, а в скрытых реквизитах Значение или ЗначенияПолей. В этих реквизитах адрес хранится в виде строго структурированного сериализованного JSON- или XML-пакета (XDTO).

Если записать адрес "напрямую", заполнив лишь текст, система воспримет такую контактную информацию как некорректную или неполную. Проанализируем последствия, к которым это неизбежно приведет:

  1. Ошибки при автоматическом формировании и выгрузке регламентированной отчетности в ФНС, ПФР и другие фонды (система не сможет извлечь индекс, код региона, улицу).
  2. Проблемы при передаче документов через системы электронного документооборота (1С-ЭДО), так как формат формализованных документов требует строгой разбивки адреса по КЛАДР/ФИАС.
  3. Ошибки при пробитии чеков через онлайн-кассы.
  4. Пустоты или некорректные данные при формировании регламентированных печатных форм (ТОРГ-12, УПД, Счета-фактуры).

Правильные способы заполнения контактной информации в БСП

Вся работа с контактной информацией при программной генерации объектов должна вестись исключительно через программный интерфейс общего модуля УправлениеКонтактнойИнформацией. В зависимости от того, в каком виде к вам пришли данные из ФНС или другой внешней системы, выберем один из двух подходов — для интеграции подойдёт REST API модуль для создания карточек контрагентов.

Способ 1: Если адресные данные получены в виде структуры (по полям)

Рассмотрим алгоритм действий, если внешняя система вернула нам адрес в разобранном виде: мы отдельно знаем индекс, регион, город, улицу и номер дома — для этого подойдёт заполнение карточек контрагентов данными из госреестров.

Сначала нам нужно получить пустую структуру (шаблон) для заполнения адреса. Для этого вызовем функцию УправлениеКонтактнойИнформацией.ОписаниеНовойКонтактнойИнформации() с указанием нужного типа КИ (Адрес). Затем мы заполним ключи полученной структуры нашими данными.

Посмотрим на пример реализации:


// 1. Получаем пустую структуру для адреса
ПараметрыАдреса = УправлениеКонтактнойИнформацией.ОписаниеНовойКонтактнойИнформации(Перечисления.ТипыКонтактнойИнформации.Адрес);

// 2. Заполняем известные нам поля
ПараметрыАдреса.Вставить("Индекс", "119049");
ПараметрыАдреса.Вставить("КодРегиона", "77"); // Код субъекта РФ
ПараметрыАдреса.Вставить("Город", "Москва");
ПараметрыАдреса.Вставить("Улица", "Крымский Вал");
ПараметрыАдреса.Вставить("Дом", "9");

// Также можно передавать данные в английских ключах структуры (ZIPcode, area, city, street, houseNumber),
// если это предусмотрено версией БСП.

// 3. Получаем объект контрагента
ОбъектКонтрагент = СсылкаНаКонтрагента.ПолучитьОбъект();

// 4. Записываем КИ через типовой метод
ВидКИ = Справочники.ВидыКонтактнойИнформации.ЮрАдресКонтрагента;
УправлениеКонтактнойИнформацией.ЗаписатьКонтактнуюИнформацию(ОбъектКонтрагент, ПараметрыАдреса, ВидКИ, Перечисления.ТипыКонтактнойИнформации.Адрес);

// 5. Сохраняем справочник
ОбъектКонтрагент.Записать();

Процедура ЗаписатьКонтактнуюИнформацию самостоятельно сформирует правильный JSON/XML пакет, корректно сгенерирует текстовое представление и вставит нужную строку в табличную часть объекта, сохранив историю изменений (если для данного вида КИ включена периодичность).

Способ 2: Если адрес получен в виде единой строки текста

Разберем ситуацию, когда от ФНС или пользователя нам пришла просто строковая переменная с адресом (например, "г. Москва, ул. Ленина, д. 1"), и мы не можем разбить ее на поля самостоятельно — поможет автоматическое извлечение адреса из текстовой строки.

В этом случае нам поможет специальный метод парсинга, который попытается разобрать строку по адресному классификатору (ФИАС/ГАР) и преобразовать ее во внутренний формат.

Рассмотрим пример кода для этой задачи:


СтрокаАдреса = "125009, г. Москва, Тверская ул, д. 1";

// 1. Пытаемся распарсить строку и получить XDTO объект адреса
// В зависимости от версии БСП методы могут немного отличаться, обычно используется общий модуль со словом "Служебный"
ОбъектXDTO = УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияXDTOПоПредставлению(СтрокаАдреса, Перечисления.ТипыКонтактнойИнформации.Адрес);

Если ОбъектXDTO <> Неопределено Тогда
    
    // 2. Сериализуем объект XDTO в строку XML/JSON (внутренний формат хранения БСП)
    ЗначениеКИ = УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияXDTOВСтроку(ОбъектXDTO);
    
    ОбъектКонтрагент = СсылкаНаКонтрагента.ПолучитьОбъект();
    ВидКИ = Справочники.ВидыКонтактнойИнформации.ФактАдресКонтрагента;
    
    // 3. Записываем подготовленные данные. 
    // Вместо структуры передаем сериализованное значение
    УправлениеКонтактнойИнформацией.ЗаписатьКонтактнуюИнформацию(ОбъектКонтрагент, ЗначениеКИ, ВидКИ, Перечисления.ТипыКонтактнойИнформации.Адрес);
    
    ОбъектКонтрагент.Записать();
    
КонецЕсли;

Подведем итоги: При программном создании элементов справочников или документов, содержащих контактную информацию, никогда не заполняйте табличные части КонтактнаяИнформация напрямую. Всегда используйте методы общего модуля УправлениеКонтактнойИнформацией — есть расширение для заполнения реквизитов по ИНН. Это гарантирует корректность данных, правильное заполнение скрытых реквизитов XDTO и избавит вас от множества проблем при дальнейшей эксплуатации базы данных (формирование отчетов, работа с кассами и ЭДО).

← На главную