Интеграция 1С со сторонними системами (веб-сайтами, CRM-системами, мобильными приложениями) — одна из самых частых задач современного разработчика. Наиболее производительным и стандартным способом обмена данными является использование собственных HTTP-сервисов 1С. В этой статье мы подробно разберем, как создать надежный, безопасный и отказоустойчивый HTTP-сервис для создания контрагента и заполнения его контактной информации.
Мы откажемся от простых, но небезопасных подходов (вроде передачи конфиденциальных данных в URL-параметрах) и построим архитектуру сервиса на базе современных стандартов: метода POST, формата данных JSON, механизмов защиты от дублирования и интеграции с Библиотекой стандартных подсистем (БСП).
На начальном этапе у разработчиков часто возникает соблазн передавать параметры создания контрагента (например, имя и телефон) прямо в строке запроса (URL), используя метод GET и шаблоны вида /{name}/{number}. Давайте разберем, почему от этого стоит отказаться:
GET предназначен исключительно для чтения данных. Для создания новых записей в базе данных спецификация протокола HTTP предписывает использовать метод POST, а для обновления — POST, PUT или PATCH.Поэтому правильным решением будет передача всей информации о контрагенте в теле запроса (Request Body) в структурированном формате JSON.
Рассмотрим процесс создания объекта метаданных в конфигураторе 1С:
ИнтеграцияКонтрагенты.agents. Полный путь к нашему сервису будет выглядеть так: http://[адрес_сервера]/[имя_базы]/hs/agents.СоздатьИлиОбновить и шаблоном пути /v1/manage.PostMethod, HTTP-метод: POST, а в поле Обработчик сгенерируем функцию в модуле сервиса, например: ManageCounterparty.Когда внешняя система пришлет нам POST-запрос с JSON в теле, нам необходимо прочитать эту строку и преобразовать ее в понятную для 1С структуру. Ниже приведен пример реализации десериализации JSON в модуле HTTP-сервиса:
Функция ManageCounterparty(Запрос)
// Получаем тело запроса в виде текстовой строки
ТелоЗапроса = Запрос.ПолучитьТелоКакСтроку("UTF-8");
// Проверяем, что запрос не пустой
Если ПустаяСтрока(ТелоЗапроса) Тогда
Возврат СформироватьОтвет(400, "Ошибка: Пустое тело запроса.");
КонецЕсли;
// Десериализуем JSON в структуру 1С
ДанныеКонтрагента = Новый Структура;
Чтение = Новый ЧтениеJSON;
Попытка
Чтение.УстановитьСтроку(ТелоЗапроса);
ДанныеКонтрагента = ПрочитатьJSON(Чтение);
Чтение.Закрыть();
Исключение
Чтение.Закрыть();
Возврат СформироватьОтвет(400, "Ошибка: Некорректный формат JSON. " + ОписаниеОшибки());
КонецПопытки;
// Переходим к бизнес-логике обработки полученных данных
Возврат ОбработатьДанныеКонтрагента(ДанныеКонтрагента);
КонецФункции
Поиск контрагента только по наименованию (например, с помощью функции НайтиПоНаименованию) крайне ненадежен. Различия в кавычках, пробелах или организационно-правовых формах (например, *ООО "Ромашка"* и *ООО Ромашка*) приведут к созданию множества дубликатов.
Рассмотрим надежные способы идентификации контрагента:
Контрагенты дополнительный реквизит, например, ID_ВнешнейСистемы, и выполнять точный поиск по нему.Проанализируем пример функции поиска и создания контрагента по ИНН:
Функция НайтиИлиСоздатьКонтрагента(ДанныеКонтрагента, ЭтоНовыйКонтрагент)
ИНН = "";
ДанныеКонтрагента.Свойство("ИНН", ИНН);
Наименование = "";
ДанныеКонтрагента.Свойство("Наименование", Наименование);
Если ПустаяСтрока(ИНН) Или ПустаяСтрока(Наименование) Тогда
ВызватьИсключение "Не заполнены обязательные поля: ИНН или Наименование!";
КонецЕсли;
// Ищем существующего контрагента с помощью запроса
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Ссылка КАК Ссылка
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| Контрагенты.ИНН = &ИНН";
Запрос.УстановитьПараметр("ИНН", ИНН);
РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
// Контрагент найден, получаем его объект для изменения
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
КонтрагентОбъект = Выборка.Ссылка.ПолучитьОбъект();
ЭтоНовыйКонтрагент = Ложь;
Иначе
// Контрагент не найден, создаем новый элемент
КонтрагентОбъект = Справочники.Контрагенты.СоздатьЭлемент();
КонтрагентОбъект.Наименование = Наименование;
КонтрагентОбъект.НаименованиеПолное = Наименование;
КонтрагентОбъект.ИНН = ИНН;
// Заполняем КПП, если он передан для юрлица
КПП = "";
Если ДанныеКонтрагента.Свойство("КПП", КПП) Тогда
КонтрагентОбъект.КПП = КПП;
КонецЕсли;
ЭтоНовыйКонтрагент = Истина;
КонецЕсли;
Возврат КонтрагентОбъект;
КонецФункции
В современных конфигурациях 1С (ERP, УТ, КА, УНФ, БП), разработанных на базе Библиотеки стандартных подсистем (БСП), адреса и телефоны не хранятся в обычных строковых реквизитах справочника. Контактная информация записывается в табличную часть КонтактнаяИнформация в виде структурированного XML или JSON.
Попытка напрямую записать строку в ТЧ (например, СтрокаТЧ.Представление = НомерТелефона) приведет к тому, что в интерфейсе программы данные будут отображаться некорректно, а отчеты по контактной информации не увидят этот номер.
Выясним, как правильно записать телефон контрагента с помощью общего модуля БСП УправлениеКонтактнойИнформацией:
Процедура ЗаполнитьТелефонКонтрагента(КонтрагентОбъект, ЗначениеТелефона)
Если ПустаяСтрока(ЗначениеТелефона) Тогда
Возврат;
КонецЕсли;
// Получаем предопределенные виды контактной информации
ВидТелефона = Справочники.ВидыКонтактнойИнформации.ТелефонКонтрагента;
ТипТелефона = Перечисления.ТипыКонтактнойИнформации.Телефон;
// Очищаем старый телефон перед записью нового (если это необходимо по бизнес-логике)
ТаблицаКИ = КонтрагентОбъект.КонтактнаяИнформация.Выгрузить();
ПараметрыОтбора = Новый Структура("Вид", ВидТелефона);
НайденныеСтроки = ТаблицаКИ.НайтиСтроки(ПараметрыОтбора);
Для Каждого СтрокаКИ Из НайденныеСтроки Цикл
КонтрагентОбъект.КонтактнаяИнформация.Удалить(СтрокаКИ);
КонецЦикла;
// Используем программный интерфейс БСП для корректной записи
УправлениеКонтактнойИнформацией.ЗаписатьКонтактнуюИнформацию(
КонтрагентОбъект,
ЗначениеТелефона,
ВидТелефона,
ТипТелефона
);
КонецПроцедур
При проектировании 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.НеИспользовать);
Возврат Ответ;
КонецФункции
Публикация HTTP-сервиса на веб-сервере (IIS или Apache) открывает доступ к вашей базе данных из глобальной сети. Рассмотрим правила безопасности, которые строго необходимо соблюдать:
api_user) со следующими параметрами:
Контрагенты и использование вашего HTTP-сервиса.Соблюдение этих правил гарантирует стабильную, быструю и безопасную работу интеграции вашей базы 1С с любыми внешними информационными системами.