Как программно заполнить контактную информацию партнера в 1С?

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

При разработке и автоматизации бизнес-процессов в среде 1С:Предприятие часто возникает задача программного импорта, обновления или дополнения контактной информации клиентов, партнеров или контрагентов. В современных конфигурациях, таких как 1С:ERP Управление предприятием, 1С:Комплексная автоматизация и 1С:Управление торговлей, подсистема контактной информации реализована на базе Библиотеки стандартных подсистем (БСП). Это накладывает определенные требования к коду и архитектуре решения.

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

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

Рассмотрим ситуацию, с которой часто сталкиваются программисты при первой попытке программной работы с контактной информацией. Задача состоит в том, чтобы на основании уже заполненного строкового поля Представление автоматически заполнить служебные поля НомерТелефона и НомерТелефонаБезКодов в табличной части КонтактнаяИнформация справочника Партнеры.

Начинающие разработчики часто пытаются написать код следующим образом:


Процедура ПартнерПередЗаписьюПроверитьДополнитьКИПередЗаписью(Объект, Отказ) Экспорт
    Таблица = Объект.КонтактнаяИнформация.Добавить;
    Таблица.Колонки.Добавить("НомерТелефона");
    Таблица.Колонки.Добавить("НомерТелефонаБезКодов");
    Для каждого Строка Из Таблица Цикл
        Строка.НомерТелефона = Объект.КонтактнаяИнформация.Представление;
        Строка.НомерТелефонаБезКодов = Объект.КонтактнаяИнформация.Представление;
    КонецЦикла;
КонецПроцедуры

Давайте подробно проанализируем, почему этот код совершенно неработоспособен и вызывает ошибки выполнения:

  1. Неправильное использование метода Добавить(). Метод Объект.КонтактнаяИнформация.Добавить() предназначен для добавления новой строки в табличную часть. Он возвращает конкретный объект строки (СтрокаТабличнойЧасти), а не всю коллекцию или таблицу. Присваивать его переменной с именем Таблица — грубая логическая ошибка.
  2. Попытка динамического добавления колонок. Табличная часть прикладного объекта в 1С имеет жестко заданную структуру метаданных. Нельзя программно добавлять в нее колонки через метод Колонки.Добавить(), как это делается в объекте ТаблицаЗначений.
  3. Некорректный обход коллекции. Попытка обойти одну только что добавленную пустую строку через цикл Для каждого приводит к ошибке, так как возвращенный объект строки не является коллекцией, по которой можно итерироваться.
  4. Обращение к реквизитам табличной части через точку от объекта. Конструкция вида Объект.КонтактнаяИнформация.Представление не имеет смысла, так как КонтактнаяИнформация — это табличная часть (коллекция строк), и у самой коллекции нет свойства Представление. Обращаться к этому реквизиту можно только у конкретной строки коллекции.

Простое решение: обход существующей табличной части

Для того чтобы исправить базовую логику кода и заставить программу корректно обойти уже существующие строки контактной информации, необходимо использовать цикл по коллекции строк табличной части объекта. Вот простое решение, которое часто предлагают на форумах в качестве быстрого исправления:


Для каждого ТекСтрока Из Объект.КонтактнаяИнформация Цикл
    // Проверяем, что это строка с типом "Телефон"
    Если ТекСтрока.Тип = Перечисления.ТипыКонтактнойИнформации.Телефон Тогда
        ТекСтрока.НомерТелефона = ТекСтрока.Представление;
        ТекСтрока.НомерТелефонаБезКодов = ТекСтрока.Представление;
    КонецЕсли;
КонецЦикла;

Этот код действительно решает проблему синтаксических ошибок и корректно перезаписывает реквизиты в цикле. Мы обращаемся к каждой строке ТекСтрока внутри табличной части КонтактнаяИнформация и напрямую копируем строковое представление телефона в служебные поля.

Однако использовать такое решение в реальных рабочих базах категорически не рекомендуется! Ниже мы подробно разберем, почему этот "быстрый" способ является миной замедленного действия для вашей конфигурации.

В чем опасность простого копирования? Архитектура КИ в БСП

Современная контактная информация в конфигурациях 1С на базе БСП устроена гораздо сложнее, чем просто набор текстовых строк. Для обеспечения интеграции с мобильными устройствами, IP-телефонией, отправки SMS-сообщений и корректного поиска дублей система требует строгого форматирования данных.

Давайте выясним, к каким критическим проблемам приведет прямое копирование строки представления в поля номеров телефонов:

  1. Десинхронизация с полем "ЗначенияПолей". В БСП вся детальная структура контактной информации (код страны, код города, добавочный номер и т.д.) сериализуется и хранится в специальном поле ЗначенияПолей (в формате XML или JSON). При открытии карточки партнера на управляемой форме система парсит именно это сериализованное поле. Если вы обновили поля НомерТелефона и НомерТелефонаБезКодов вручную, но оставили поле ЗначенияПолей пустым или старым, то при первом же интерактивном переоткрытии и сохранении карточки пользователем ваши внесенные программно телефоны будут затерты пустыми значениями!
  2. Нарушение нормализации номеров. Поле НомерТелефона должно содержать строго очищенную от лишних символов последовательность цифр (например, 74951234567). Поле НомерТелефонаБезКодов должно содержать только локальный номер абонента (например, 1234567). Если записать туда сырую строку со скобками и дефисами типа "+7 (495) 123-45-67", сломаются стандартные механизмы фильтрации, поиска дублей партнеров по телефонам, а также интеграция со встроенными софтфонами.

Профессиональное решение с использованием программного интерфейса БСП

Для того чтобы сделать заполнение контактной информации надежным и корректным, мы должны задействовать экспортные функции общих модулей БСП. Система сама умеет разбирать текстовую строку на составляющие (код страны, код города, номер), приводить её к каноническому виду и формировать правильный XML или JSON для записи в базу данных.

Ниже представлен профессиональный шаблон кода для обработчика подписки на событие ПередЗаписью справочника Партнеры:


Процедура ПартнерПередЗаписьюПроверитьДополнитьКИПередЗаписью(Объект, Отказ) Экспорт
    
    // Предотвращаем выполнение кода при обмене данными, если это необходимо
    Если Объект.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    ТипТелефон = Перечисления.ТипыКонтактнойИнформации.Телефон;
    
    Для Каждого ТекСтрока Из Объект.КонтактнаяИнформация Цикл
        
        // Обрабатываем только телефонные номера с заполненным текстовым представлением
        Если ТекСтрока.Тип = ТипТелефон И ЗначениеЗаполнено(ТекСтрока.Представление) Тогда
            
            // Запускаем процесс парсинга и нормализации, только если служебные поля еще не заполнены
            Если ПустаяСтрока(ТекСтрока.НомерТелефона) Или ПустаяСтрока(ТекСтрока.ЗначенияПолей) Тогда
                
                Попытка
                    // 1. Используем БСП для разбора строки представления в структурированный XDTO-объект
                    ОбъектXDTO = УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияXDTOПоПредставлению(
                        ТекСтрока.Представление, 
                        ТипТелефон
                    );
                    
                    // 2. Сериализуем полученный объект в XML-строку для записи в поле "ЗначенияПолей"
                    ЗначенияПолейСтрокой = УправлениеКонтактнойИнформациейСлужебный.КонтактнаяИнформацияXDTOВXML(ОбъектXDTO);
                    ТекСтрока.ЗначенияПолей = ЗначенияПолейСтрокой;
                    
                    // 3. Извлекаем нормализованные и очищенные составляющие телефона
                    ДеталиТелефона = УправлениеКонтактнойИнформацией.СведенияОТелефоне(ЗначенияПолейСтрокой);
                    
                    // 4. Заполняем реквизиты строки табличной части "чистыми" данными
                    // НомерТелефона должен состоять только из цифр: КодСтраны + КодГорода + ЛокальныйНомер
                    ТекСтрока.НомерТелефона = ДеталиТелефона.КодСтраны + ДеталиТелефона.КодГорода + ДеталиТелефона.НомерТелефона;
                    
                    // Записываем только локальную часть номера
                    ТекСтрока.НомерТелефонаБезКодов = ДеталиТелефона.НомерТелефона;
                    
                Исключение
                    // В случае непредвиденных ошибок парсинга (например, некорректный формат текста) фиксируем событие в журнале
                    ИнформационнаяБаза = "ПрограммноеЗаполнениеКИ";
                    ЗаписьЖурналаРегистрации(ИнформационнаяБаза,
                        УровеньЖурналаРегистрации.Предупреждение,
                        Объект.Метаданные(),
                        Объект.Ссылка,
                        "Не удалось корректно распознать и нормализовать номер телефона: " + ТекСтрока.Представление + ". Ошибка: " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
                КонецПопытки;
                
            КонецЕсли;
            
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Разбор работы профессионального алгоритма

Давайте пошагово проанализируем, как работает предложенный нами надежный алгоритм:

  1. Проверка признака загрузки данных. В начале процедуры мы проверяем свойство Объект.ОбменДанными.Загрузка. Если происходит синхронизация данных (РИБ или интеграция), этот код не должен мешать импорту объектов, чтобы избежать конфликтов блокировок и замедления работы.
  2. Фильтрация по типу контактной информации. Контактная информация партнеров может содержать адреса, email, веб-страницы и т.д. Мы строго фильтруем строки с помощью перечисления Перечисления.ТипыКонтактнойИнформации.Телефон.
  3. Метод КонтактнаяИнформацияXDTOПоПредставлению(). Этот служебный метод БСП является ключевым. Он берет обычный текст (например, "+7 (999) 123-45-67") и превращает его во внутренний XDTO-объект, разбивая на логические сегменты (страна, город, номер, добавочный).
  4. Метод КонтактнаяИнформацияXDTOВXML(). Конвертирует структурированный объект обратно в строку XML, которую понимает платформа 1С. Мы записываем эту строку в поле ЗначенияПолей. Теперь при интерактивном открытии карточки партнера на форме отобразятся корректные данные, и они не затрутся пустыми значениями при ручном сохранении.
  5. Метод СведенияОТелефоне(). Возвращает удобную структуру с очищенными от форматирования текстовыми полями. Нам остается лишь сложить код страны, код города и локальный номер, чтобы получить абсолютно чистую строку телефона из одних цифр.

Рекомендации по интеграции кода в конфигурацию

Для внедрения данного механизма рекомендуется следовать стандартной методике разработки в среде 1С:

  1. Создайте новый общий модуль (например, _ПартнерыСобытия) или используйте существующий нетиповой модуль вашей организации. Обязательно установите у него свойства Сервер, Вызов сервера и отключите Глобальный.
  2. Создайте новый объект метаданных Подписка на событие. Назовите её, например, _ПартнерыПередЗаписью.
  3. В свойстве подписки Источник укажите класс СправочникОбъект.Партнеры.
  4. В свойстве Событие выберите ПередЗаписью.
  5. В поле Обработчик выберите созданную процедуру из вашего общего модуля.
  6. Проведите тестирование на копии базы данных, попробовав записать карточку партнера программно и интерактивно, контролируя заполнение полей через групповую обработку или консоль запросов.

Реализация через расширение конфигурации (альтернативный способ)

Если вы стремитесь сохранить конфигурацию на полной поддержке без включения возможности изменения, наилучшим решением будет реализация данного функционала через механизм Расширения конфигурации. Это современный стандарт разработки в экосистеме 1С.

Для реализации этой логики в расширении выполните следующие шаги:

  1. Создайте новое расширение или откройте существующее.
  2. Добавьте справочник Партнеры в расширение.
  3. В расширении перейдите в модуль объекта справочника Партнеры.
  4. Создайте обработчик события ПередЗаписью с аннотацией &Перед. Это позволит выполнить ваш код непосредственно перед стандартной обработкой записи объекта.

Пример кода в модуле объекта расширения:


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

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

← На главную