Интеграция прикладных решений 1С с внешними веб-сервисами — одна из самых частых задач, с которыми сталкивается современный разработчик. Одним из наиболее популярных сервисов для проверки и автозаполнения реквизитов контрагентов по ИНН является DaData. Сервис предоставляет удобный API, возвращающий детальную информацию в формате JSON.
В этой статье мы подробно рассмотрим, как правильно отправить HTTP-запрос к сервису DaData, получить информацию о контрагенте по его ИНН, корректно распарсить полученный JSON-ответ стандартными средствами платформы 1С:Предприятие 8.3 и извлечь нужные реквизиты, такие как ОГРН, КПП и коды ОКВЭД.
Начинающие разработчики, ранее не работавшие с форматом JSON, часто пытаются анализировать полученный текст вручную. Они используют построчный или посимвольный обход через объект ЧтениеJSON, проверяя типы элементов с помощью ТипЗначенияJSON.ИмяСвойства, ТипЗначенияJSON.Строка и других низкоуровневых свойств.
Такой подход делает код громоздким, сложным для понимания, отладки и поддержки. Любое минимальное изменение в структуре ответа стороннего сервиса приведет к полной неработоспособности алгоритма. Платформа 1С:Предприятие, начиная с версии 8.3.6, предоставляет мощные встроенные механизмы десериализации JSON в стандартные коллекции (структуры, массивы и соответствия) с помощью всего одной функции — ПрочитатьJSON(). Для проверки структуры, валидации и генерации кода обработки сложных ответов сторонних API можно использовать инструмент для валидации JSON и генерации кода 1С.
Давайте разберем по шагам, как построить правильное и элегантное решение для интеграции с DaData.
Для взаимодействия с внешним сервисом нам потребуется настроить защищенное соединение SSL, заполнить необходимые заголовки запроса (включая авторизационный токен) и передать тело запроса с ИНН в формате JSON. Для отладки и проверки отправки подобных запросов прямо в 1С пригодится инструмент для тестирования REST API.
Проанализируем процедуру настройки соединения и отправки запроса. Для авторизации в DaData используется уникальный токен (API-ключ), который выдается в личном кабинете сервиса.
Рассмотрим код функции, выполняющей отправку запроса:
&НаСервере
Функция ПолучитьДанныеКонтрагентаИзDaData(Знач ИНН, Знач Токен) Экспорт
// Настраиваем безопасное соединение OpenSSL, так как DaData работает только по HTTPS
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
// Создаем HTTP-соединение с хостом сервиса
HTTPСоединение = Новый HTTPСоединение("suggestions.dadata.ru", , , , , , ЗащищенноеСоединение);
// Формируем заголовки запроса в соответствии с требованиями API DaData
Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type", "application/json");
Заголовки.Вставить("Accept", "application/json");
Заголовки.Вставить("Authorization", "Token " + Токен);
// Определяем адрес ресурса для поиска организации по ИНН
АдресРесурса = "/suggestions/api/4_1/rs/findById/party";
// Создаем объект HTTP-запроса
HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса, Заголовки);
// Формируем тело запроса в формате JSON.
// Для поиска передаем ИНН в параметре "query"
ТелоЗапроса = "{""query"": """ + ИНН + """}";
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8);
Попытка
// Отправляем запрос методом POST (ОтправитьДляОбработки)
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Исключение
ЗаписатьЛогОшибки("Не удалось связаться с сервисом DaData: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
Возврат HTTPОтвет;
КонецФункции
После получения ответа от сервера с кодом состояния 200 (ОК) нам необходимо обработать JSON-данные. Функция 1С ПрочитатьJSON() может преобразовывать JSON в коллекции двумя способами:
ПрочитатьJSON(ЧтениеJSON, Истина). В этом случае все объекты JSON будут преобразованы в коллекции типа Соответствие. Ключи JSON станут ключами соответствия. Этот способ незаменим, когда ключи в JSON содержат символы, недопустимые для имен переменных в 1С (например, пробелы, дефисы или начинаются с цифр). Однако обращаться к свойствам придется через метод Получить("ИмяСвойства"), что делает код длинным: Результат.Получить("suggestions")[0].Получить("data").Получить("ogrn").ПрочитатьJSON(ЧтениеJSON, Ложь). Все объекты JSON преобразуются в стандартные Структуры 1С, а массивы JSON — в коллекции типа Массив. Поскольку API DaData использует латинские символы и нижнее подчеркивание в именах полей, все ключи являются абсолютно валидными идентификаторами для платформы 1С. Мы можем использовать этот способ и обращаться к свойствам напрямую через точку: Результат.suggestions[0].data.ogrn. Это делает код максимально лаконичным и читаемым!Выясним, как выглядит оптимальный алгоритм чтения JSON-ответа при десериализации его в структуру:
&НаСервере
Функция РаспарситьJSONОтвет(HTTPОтвет)
Если HTTPОтвет = Неопределено Или HTTPОтвет.КодСостояния <> 200 Тогда
Возврат Неопределено;
КонецЕсли;
// Получаем тело ответа в виде строки
ОтветСтрокой = HTTPОтвет.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8);
// Инициализируем объект ЧтениеJSON
ЧтениеJSON = Новый ЧтениеJSON();
ЧтениеJSON.УстановитьСтроку(ОтветСтрокой);
Попытка
// Читаем JSON в структуру 1С (Ложь по умолчанию для второго параметра)
РезультатДесериализации = ПрочитатьJSON(ЧтениеJSON, Ложь);
Исключение
ЗаписатьЛогОшибки("Ошибка чтения формата JSON: " + ОписаниеОшибки());
РезультатДесериализации = Неопределено;
КонецПопытки;
ЧтениеJSON.Закрыть();
Возврат РезультатДесериализации;
КонецФункции
Структура JSON-ответа от DaData представляет собой корневой объект, содержащий один массив под именем suggestions. Каждый элемент этого массива — это найденная организация. Внутри элемента есть текстовое поле value (наименование) и объект data, где содержатся детальные реквизиты.
Посмотрим на пример структуры хранения данных в ответе:
suggestions (Массив)
value — Наименование компании (строка)data (Структура)
inn — ИНН организации (строка)kpp — КПП (строка, для ИП может быть пустой)ogrn — ОГРН (строка)okved — Основной код ОКВЭД (строка)name (Структура) — сведения о наименовании (содержит поля full_with_opf, short_with_opf)Рассмотрим, как красиво и безопасно извлечь эти реквизиты в коде 1С с использованием обращений через точку:
&НаСервере
Процедура ЗаполнитьРеквизитыНаФорме(ИНН, Токен)
HTTPОтвет = ПолучитьДанныеКонтрагентаИзDaData(ИНН, Токен);
ДанныеОтвета = РаспарситьJSONОтвет(HTTPОтвет);
Если ДанныеОтвета = Неопределено Тогда
Сообщить("Не удалось получить или распознать данные от сервиса.");
Возврат;
КонецЕсли;
// Проверяем, вернул ли сервис совпадения
МассивКонтрагентов = ДанныеОтвета.suggestions;
Если МассивКонтрагентов.Количество() = 0 Тогда
Сообщить("Организация с ИНН " + ИНН + " не найдена в базе DaData.");
Возврат;
КонецЕсли;
// Получаем первого контрагента из списка
СведенияКонтрагента = МассивКонтрагентов[0];
// Извлекаем наименование и детальные данные
НаименованиеКраткое = СведенияКонтрагента.value;
Детали = СведенияКонтрагента.data;
// Извлекаем ОГРН и КПП напрямую из структуры
ОГРН = Детали.ogrn;
КПП = ?(Детали.Свойство("kpp"), Детали.kpp, ""); // У ИП КПП отсутствует, проверяем свойство безопасным методом
// Выводим информацию пользователю
Сообщить("Наименование: " + НаименованиеКраткое);
Сообщить("ОГРН: " + ОГРН);
Если ЗначениеЗаполнено(КПП) Тогда
Сообщить("КПП: " + КПП);
Иначе
Сообщить("КПП: отсутствует (Индивидуальный предприниматель)");
КонецЕсли;
КонецПроцедуры
Часто у разработчиков возникает вопрос: «Как получить текстовое наименование (вид деятельности) ОКВЭД, а не только его числовой код?». Здесь есть важное тарифное ограничение со стороны самого сервиса DaData.
Ограничение тарифа DaData: Полный массив видов деятельности с их текстовыми расшифровками (поле data.okveds) возвращается сервисом только на платных тарифах («Расширенный» и «Максимальный»). На бесплатном тарифе или тарифе «Легкий» это поле всегда возвращается пустым (значение null), а доступен только базовый код основного вида деятельности в поле data.okved (например, "62.01").
Проанализируем два практических варианта решения этой проблемы для пользователей бесплатного тарифа:
В большинстве типовых конфигураций 1С (Бухгалтерия предприятия, ERP, УНФ) уже встроен справочник классификатора ОКВЭД (например, КлассификаторВидовЭкономическойДеятельности). Мы можем быстро найти текстовое наименование вида деятельности локально по коду, полученному из DaData. Это самый быстрый способ, не требующий дополнительных внешних запросов к сети.
&НаСервере
Функция ПолучитьНаименованиеОКВЭДИз1С(Знач КодОКВЭД)
// Задаем имя справочника классификатора (в разных конфигурациях имя может отличаться)
ИмяСправочника = "КлассификаторВидовЭкономическойДеятельности";
Если Метаданные.Справочники.Найти(ИмяСправочника) = Неопределено Тогда
Возврат "Классификатор ОКВЭД не найден в текущей конфигурации 1С";
КонецЕсли;
// Выполняем поиск по коду
СсылкаОКВЭД = Справочники[ИмяСправочника].НайтиПоКоду(КодОКВЭД);
Если ЗначениеЗаполнено(СсылкаОКВЭД) Тогда
Возврат СсылкаОКВЭД.Наименование;
Иначе
Возврат "Код " + КодОКВЭД + " не найден в локальном справочнике";
КонецЕсли;
КонецФункции
Если в вашей конфигурации нет встроенного справочника ОКВЭД, можно отправить отдельный бесплатный поисковый запрос к специальному методу API DaData — findById/okved2. Этот метод позволяет бесплатно найти текстовую расшифровку любого кода ОКВЭД 2.
Посмотрим на реализацию такой функции:
&НаСервере
Функция ПолучитьНаименованиеОКВЭДЧерезAPI(Знач КодОКВЭД, Знач Токен)
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
HTTPСоединение = Новый HTTPСоединение("suggestions.dadata.ru", , , , , , ЗащищенноеСоединение);
Заголовки = Новый Соответствие();
Заголовки.Вставить("Content-Type", "application/json");
Заголовки.Вставить("Accept", "application/json");
Заголовки.Вставить("Authorization", "Token " + Токен);
// Адрес ресурса для поиска по справочнику ОКВЭД 2
АдресРесурса = "/suggestions/api/4_1/rs/findById/okved2";
HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса, Заголовки);
ТелоЗапроса = "{""query"": """ + КодОКВЭД + """}";
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8);
Попытка
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Исключение
Возврат "Ошибка запроса к API ОКВЭД";
КонецПопытки;
Если HTTPОтвет.КодСостояния = 200 Тогда
ЧтениеJSON = Новый ЧтениеJSON();
ЧтениеJSON.УстановитьСтроку(HTTPОтвет.ПолучитьТелоКакСтроку(КодировкаТекста.UTF8));
РезультатДесериализации = ПрочитатьJSON(ЧтениеJSON, Ложь);
ЧтениеJSON.Закрыть();
Если РезультатДесериализации <> Неопределено
И РезультатДесериализации.suggestions.Количество() > 0 Тогда
// Возвращаем текстовое наименование вида деятельности
Возврат РезультатДесериализации.suggestions[0].value;
КонецЕсли;
КонецЕсли;
Возврат "Расшифровка не найдена на сервисе DaData";
КонецФункции
Для удобства объединим все рассмотренные механизмы в единый блок кода, который вы можете перенести в общий модуль или модуль вашей управляемой формы для полноценной работы. Мы будем использовать современное чтение JSON в Структуру для простоты обращения к свойствам и добавим обработку ОКВЭД.
&НаСервере
Процедура ВыполнитьЗаполнениеРеквизитовПоИНН(Знач ВходнойИНН)
// Укажите ваш API-токен DaData
ТокенАвторизации = "ВАШ_ЛИЧНЫЙ_ТОКЕН_DADATA";
Если ПустаяСтрока(ВходнойИНН) Тогда
Сообщить("Пожалуйста, заполните ИНН контрагента.");
Возврат;
КонецЕсли;
// 1. Отправляем запрос к сервису
HTTPОтвет = ПолучитьДанныеКонтрагентаИзDaData(ВходнойИНН, ТокенАвторизации);
// 2. Десериализуем полученный JSON в структуры и массивы
ДанныеОтвета = РаспарситьJSONОтвет(HTTPОтвет);
Если ДанныеОтвета = Неопределено Тогда
Сообщить("Произошла ошибка при отправке запроса или разборе JSON-ответа.");
Возврат;
КонецЕсли;
МассивКонтрагентов = ДанныеОтвета.suggestions;
Если МассивКонтрагентов.Количество() = 0 Тогда
Сообщить("По указанному ИНН организации не найдено.");
Возврат;
КонецЕсли;
// Работаем с первой найденной организацией
ОрганизацияДанные = МассивКонтрагентов[0];
Детали = ОрганизацияДанные.data;
// 3. Извлекаем основные реквизиты контрагента
НаименованиеКраткое = ОрганизацияДанные.value;
НаименованиеПолное = Детали.name.full_with_opf;
ОГРН = Детали.ogrn;
КПП = ?(Детали.Свойство("kpp"), Детали.kpp, "");
КодОКВЭД = ?(Детали.Свойство("okved"), Детали.okved, "");
// Выясняем тип организации (ЮрЛицо или ИП)
ТипКонтрагента = "";
Если Детали.Свойство("type") Тогда
Если Детали.type = "LEGAL" Тогда
ТипКонтрагента = "Юридическое лицо";
ИначеЕсли Детали.type = "INDIVIDUAL" Тогда
ТипКонтрагента = "Индивидуальный предприниматель";
КонецЕсли;
КонецЕсли;
// 4. Получаем текстовое описание вида деятельности ОКВЭД
НазваниеВидаДеятельности = "";
Если ЗначениеЗаполнено(КодОКВЭД) Тогда
// Сначала пытаемся найти ОКВЭД в локальной 1С базе
НазваниеВидаДеятельности = ПолучитьНаименованиеОКВЭДИз1С(КодОКВЭД);
// Если в 1С нет классификатора, делаем быстрый бесплатный запрос к DaData
Если Найти(НазваниеВидаДеятельности, "не найден") > 0 Тогда
НазваниеВидаДеятельности = ПолучитьНаименованиеОКВЭДЧерезAPI(КодОКВЭД, ТокенАвторизации);
КонецЕсли;
КонецЕсли;
// Выводим результат в окно сообщений
Сообщить("=== РЕЗУЛЬТАТ ЗАПОЛНЕНИЯ ПО ИНН ===");
Сообщить("Тип контрагента: " + ТипКонтрагента);
Сообщить("Краткое наименование: " + НаименованиеКраткое);
Сообщить("Полное наименование: " + НаименованиеПолное);
Сообщить("ОГРН: " + ОГРН);
Если ЗначениеЗаполнено(КПП) Тогда
Сообщить("КПП: " + КПП);
КонецЕсли;
Если ЗначениеЗаполнено(КодОКВЭД) Тогда
Сообщить("Основной вид деятельности (ОКВЭД): " + КодОКВЭД + " — " + НазваниеВидаДеятельности);
КонецЕсли;
Сообщить("====================================");
КонецПроцедуры
Использование этого кода позволяет навсегда отказаться от сложных посимвольных парсеров. Мы получили компактный, чистый и полностью поддерживаемый код, который работает быстро и надежно, используя всю мощь встроенной сериализации платформы 1С:Предприятие 8.3.