Как реализовать HTTP-сервис создания контрагента и его контактной информации в 1С

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

Интеграция 1С со сторонними системами (веб-сайтами, CRM-системами, мобильными приложениями) — одна из самых частых задач современного разработчика. Наиболее производительным и стандартным способом обмена данными является использование собственных HTTP-сервисов 1С. В этой статье мы подробно разберем, как создать надежный, безопасный и отказоустойчивый HTTP-сервис для создания контрагента и заполнения его контактной информации.

Мы откажемся от простых, но небезопасных подходов (вроде передачи конфиденциальных данных в URL-параметрах) и построим архитектуру сервиса на базе современных стандартов: метода POST, формата данных JSON, механизмов защиты от дублирования и интеграции с Библиотекой стандартных подсистем (БСП).

Шаг 1. Проектирование архитектуры: почему GET-запросы не подходят

На начальном этапе у разработчиков часто возникает соблазн передавать параметры создания контрагента (например, имя и телефон) прямо в строке запроса (URL), используя метод GET и шаблоны вида /{name}/{number}. Давайте разберем, почему от этого стоит отказаться:

  1. Безопасность персональных данных. Данные, переданные в URL-адресе, логируются веб-серверами (Apache, IIS), прокси-серверами и интернет-провайдерами. Номера телефонов, ИНН и имена клиентов окажутся в открытом виде в системных логах, что нарушает требования безопасности.
  2. Ограничение по объему. Строка URL имеет лимит длины (обычно около 2048 символов). Передать сложную структуру с адресами, телефонами, банковскими реквизитами и историей взаимодействий таким способом невозможно.
  3. Семантика HTTP-методов. Метод GET предназначен исключительно для чтения данных. Для создания новых записей в базе данных спецификация протокола HTTP предписывает использовать метод POST, а для обновления — POST, PUT или PATCH.

Поэтому правильным решением будет передача всей информации о контрагенте в теле запроса (Request Body) в структурированном формате JSON.

Шаг 2. Создание и настройка HTTP-сервиса в конфигураторе

Рассмотрим процесс создания объекта метаданных в конфигураторе 1С:

  1. В дереве метаданных найдем ветку Общие -> HTTP-сервисы и добавим новый сервис. Назовем его ИнтеграцияКонтрагенты.
  2. В свойстве Корневой URL укажем имя ресурса, например: agents. Полный путь к нашему сервису будет выглядеть так: http://[адрес_сервера]/[имя_базы]/hs/agents.
  3. Перейдем на вкладку Шаблоны URL и добавим новый шаблон с именем СоздатьИлиОбновить и шаблоном пути /v1/manage.
  4. Внутри шаблона создадим новый Метод. Укажем для него имя PostMethod, HTTP-метод: POST, а в поле Обработчик сгенерируем функцию в модуле сервиса, например: ManageCounterparty.

Шаг 3. Чтение и десериализация входящего JSON

Когда внешняя система пришлет нам POST-запрос с JSON в теле, нам необходимо прочитать эту строку и преобразовать ее в понятную для 1С структуру. Ниже приведен пример реализации десериализации JSON в модуле HTTP-сервиса:


Функция ManageCounterparty(Запрос)
    
    // Получаем тело запроса в виде текстовой строки
    ТелоЗапроса = Запрос.ПолучитьТелоКакСтроку("UTF-8");
    
    // Проверяем, что запрос не пустой
    Если ПустаяСтрока(ТелоЗапроса) Тогда
        Возврат СформироватьОтвет(400, "Ошибка: Пустое тело запроса.");
    КонецЕсли;
    
    // Десериализуем JSON в структуру 1С
    ДанныеКонтрагента = Новый Структура;
    Чтение = Новый ЧтениеJSON;
    
    Попытка
        Чтение.УстановитьСтроку(ТелоЗапроса);
        ДанныеКонтрагента = ПрочитатьJSON(Чтение);
        Чтение.Закрыть();
    Исключение
        Чтение.Закрыть();
        Возврат СформироватьОтвет(400, "Ошибка: Некорректный формат JSON. " + ОписаниеОшибки());
    КонецПопытки;
    
    // Переходим к бизнес-логике обработки полученных данных
    Возврат ОбработатьДанныеКонтрагента(ДанныеКонтрагента);
    
КонецФункции

Шаг 4. Борьба с дублированием данных (Идентификация контрагента)

Поиск контрагента только по наименованию (например, с помощью функции НайтиПоНаименованию) крайне ненадежен. Различия в кавычках, пробелах или организационно-правовых формах (например, *ООО "Ромашка"* и *ООО Ромашка*) приведут к созданию множества дубликатов.

Рассмотрим надежные способы идентификации контрагента:

  1. Поиск по ИНН и КПП (для юридических лиц). Это государственный стандарт идентификации юрлиц в РФ.
  2. Поиск по внешнему идентификатору (UUID). Если интеграция идет с конкретной внешней CRM или сайтом, рекомендуется добавить в справочник Контрагенты дополнительный реквизит, например, ID_ВнешнейСистемы, и выполнять точный поиск по нему.

Проанализируем пример функции поиска и создания контрагента по ИНН:


Функция НайтиИлиСоздатьКонтрагента(ДанныеКонтрагента, ЭтоНовыйКонтрагент)
    
    ИНН = "";
    ДанныеКонтрагента.Свойство("ИНН", ИНН);
    Наименование = "";
    ДанныеКонтрагента.Свойство("Наименование", Наименование);
    
    Если ПустаяСтрока(ИНН) Или ПустаяСтрока(Наименование) Тогда
        ВызватьИсключение "Не заполнены обязательные поля: ИНН или Наименование!";
    КонецЕсли;
    
    // Ищем существующего контрагента с помощью запроса
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	Контрагенты.Ссылка КАК Ссылка
        |ИЗ
        |	Справочник.Контрагенты КАК Контрагенты
        |ГДЕ
        |	Контрагенты.ИНН = &ИНН";
    
    Запрос.УстановитьПараметр("ИНН", ИНН);
    РезультатЗапроса = Запрос.Выполнить();
    
    Если НЕ РезультатЗапроса.Пустой() Тогда
        // Контрагент найден, получаем его объект для изменения
        Выборка = РезультатЗапроса.Выбрать();
        Выборка.Следующий();
        КонтрагентОбъект = Выборка.Ссылка.ПолучитьОбъект();
        ЭтоНовыйКонтрагент = Ложь;
    Иначе
        // Контрагент не найден, создаем новый элемент
        КонтрагентОбъект = Справочники.Контрагенты.СоздатьЭлемент();
        КонтрагентОбъект.Наименование = Наименование;
        КонтрагентОбъект.НаименованиеПолное = Наименование;
        КонтрагентОбъект.ИНН = ИНН;
        
        // Заполняем КПП, если он передан для юрлица
        КПП = "";
        Если ДанныеКонтрагента.Свойство("КПП", КПП) Тогда
            КонтрагентОбъект.КПП = КПП;
        КонецЕсли;
        
        ЭтоНовыйКонтрагент = Истина;
    КонецЕсли;
    
    Возврат КонтрагентОбъект;
    
КонецФункции

Шаг 5. Заполнение контактной информации (Интеграция с БСП)

В современных конфигурациях 1С (ERP, УТ, КА, УНФ, БП), разработанных на базе Библиотеки стандартных подсистем (БСП), адреса и телефоны не хранятся в обычных строковых реквизитах справочника. Контактная информация записывается в табличную часть КонтактнаяИнформация в виде структурированного XML или JSON.

Попытка напрямую записать строку в ТЧ (например, СтрокаТЧ.Представление = НомерТелефона) приведет к тому, что в интерфейсе программы данные будут отображаться некорректно, а отчеты по контактной информации не увидят этот номер.

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


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

Шаг 6. Формирование корректных HTTP-ответов и обработка ошибок

При проектировании API важно возвращать правильные HTTP-статусы ответов, чтобы внешняя система понимала, успешно ли прошла операция, или возникли неполадки.

Рассмотрим основные статусы, которые мы будем использовать:

Соберем всю логику воедино в функции ОбработатьДанныеКонтрагента, защитив код блоком транзакции и обработки исключений:


Функция ОбработатьДанныеКонтрагента(ДанныеКонтрагента)
    
    ЭтоНовый = Ложь;
    
    НачатьТранзакцию();
    
    Попытка
        // Шаг 1: Находим или создаем карточку контрагента
        КонтрагентОбъект = НайтиИлиСоздатьКонтрагента(ДанныеКонтрагента, ЭтоНовый);
        
        // Шаг 2: Записываем базовые реквизиты контрагента
        КонтрагентОбъект.Записать(); 
        
        // Шаг 3: Заполняем контактную информацию (телефон)
        Телефон = "";
        Если ДанныеКонтрагента.Свойство("Телефон", Телефон) Тогда
            ЗаполнитьТелефонКонтрагента(КонтрагентОбъект, Телефон);
        КонецЕсли;
        
        // Финальная запись объекта со всеми изменениями
        КонтрагентОбъект.Записать();
        
        ЗафиксироватьТранзакцию();
        
    Исключение
        ОтменитьТранзакцию();
        ТекстОшибки = ОписаниеОшибки();
        ЗаписьЖурналаРегистрации("HTTP-сервисы.ИнтеграцияКонтрагенты",
            УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
        Возврат СформироватьОтвет(500, "Внутренняя ошибка сервера при записи контрагента. Подробности в ЖР.");
    КонецПопытки;
    
    // Формируем успешный ответ с UUID созданного/обновленного контрагента
    ИдентификаторКонтрагента = Строка(КонтрагентОбъект.Ссылка.УникальныйИдентификатор());
    СтруктураРезультата = Новый Структура;
    СтруктураРезультата.Вставить("status", "success");
    СтруктураРезультата.Вставить("id", ИдентификаторКонтрагента);
    
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку();
    ЗаписатьJSON(ЗаписьJSON, СтруктураРезультата);
    ТелоОтвета = ЗаписьJSON.Закрыть();
    
    КодСтатуса = ?(ЭтоНовый, 201, 200);
    Возврат СформироватьОтвет(КодСтатуса, ТелоОтвета);
    
КонецФункции

Функция СформироватьОтвет(КодСтатуса, ТекстСообщения)
    
    Ответ = Новый HTTPСервисОтвет(КодСтатуса);
    Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
    
    // Если статус ошибочный, формируем JSON-ошибку вручную
    Если КодСтатуса >= 400 Тогда
        ТекстСообщения = "{""status"":""error"",""message"":""" + СтрЗаменить(ТекстСообщения, """", "\""") + """}";
    КонецЕсли;
    
    Ответ.УстановитьТелоИзСтроки(ТекстСообщения, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
    Возврат Ответ;
    
КонецФункции

Шаг 7. Обеспечение безопасности при публикации

Публикация HTTP-сервиса на веб-сервере (IIS или Apache) открывает доступ к вашей базе данных из глобальной сети. Рассмотрим правила безопасности, которые строго необходимо соблюдать:

  1. Использование протокола HTTPS. Настройте веб-сервер на использование SSL/TLS-сертификатов. Без шифрования трафика логины, пароли авторизации и персональные данные контрагентов будут передаваться через интернет в открытом виде.
  2. Специальный пользователь API. Никогда не используйте системную учетную запись администратора для авторизации запросов сторонних сервисов. Создайте отдельного пользователя (например, api_user) со следующими параметрами:
    • Снимите флаг "Показывать в списке выбора".
    • Задайте сложный пароль (не менее 16 символов).
    • Назначьте минимально достаточную роль, которая разрешает только чтение/запись справочника Контрагенты и использование вашего HTTP-сервиса.
  3. Ограничение по IP. Если внешняя система имеет фиксированный статический IP-адрес, настройте правила брандмауэра или веб-сервера (IIS/Apache) так, чтобы они принимали входящие запросы к вашему HTTP-сервису исключительно с этого доверенного IP-адреса.

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

← На главную