Как настроить авторизацию в API «Честного знака» и разагрегацию кодов маркировки в 1С 7.7?

Программист 1С v7.7 Торговля и дистрибуция
← На главную

При внедрении обязательной маркировки товаров (например, табака или обуви) возникает необходимость интеграции учетных систем с True API ГИС МТ «Честный знак». Несмотря на то, что платформа 1С 7.7 считается устаревшей, интеграцию можно успешно реализовать. Рассмотрим подробнее, как авторизоваться в API, подписать данные электронной подписью (ЭЦП) и выполнить разагрегацию (получение кодов вложенных пачек из кода транспортной упаковки или блока).

Особенности адресов API для разных групп товаров

Одной из частых проблем является использование неверных адресов (URL) для отправки запросов. Проанализируем ситуацию: для разных товарных групп и контуров (тестовый/промышленный) адреса отличаются.

  1. Промышленный контур (Табак): https://ismotp.crptech.ru/api/v3/true-api
  2. Тестовый контур (Табак): https://int01.gismt.crpt.tech/api/v3/true-api
  3. Другие группы товаров (например, молоко, обувь): https://ismp.crpt.ru/api/v3/

Для табака метод авторизации выглядит как /auth/simpleSignIn, тогда как для других групп (молоко и др.) может использоваться /auth/cert.

Шаг 1. Получение пары UUID и Data для авторизации

Авторизация в True API состоит из двух этапов. Сначала необходимо запросить уникальный идентификатор и строку данных, которую предстоит подписать. Выясним причину ошибки: запрос должен идти по защищенному протоколу с правильными заголовками, иначе API может вернуть HTML-страницу вместо JSON.

Посмотрим на пример функции для получения ключей:


Функция ВернутьПаруЗапрТокена(УРЛ, ПрефиксВерсии)
    WinHttp = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
    WinHttp.Option(2,"utf-8");
    WinHttp.SetTimeouts(0, 0, 0, 0);
    Url = "https://" + УРЛ + ПрефиксВерсии + "auth/key";    
    WinHttp.Open("GET", Url, 1);
    WinHttp.SetRequestHeader("Content-Type", "application/json");
    WinHttp.SetRequestHeader("Accept-Charset", "utf-8");
    WinHttp.Send();
    
    Рез = WinHttp.WaitForResponse(40);
    Если Рез = -1 Тогда
        Ответ = СокрЛП(WinHttp.ResponseText());
    КонецЕсли;
    // Используем парсер JSON для разбора ответа
    СЗ = глРазборJSON(Ответ); 
    Возврат СЗ;
КонецФункции

Шаг 2. Подписание данных электронной подписью

Полученную строку data необходимо подписать вашей ЭЦП. В старых реализациях часто использовалась библиотека CAPICOM, но она не поддерживает современные ГОСТ-алгоритмы и аппаратные токены (Рутокен, JaCarta). Разберем по шагам создание открепленной подписи (Detached) в формате Base64 с использованием актуального CAdESCOM.CPSigner.


Функция ComОбъектСертификатаПоОтпечатку(Отпечаток)
    CAPICOM_CURRENT_USER_STORE = 2; // Ветка "Личное"
    CAPICOM_MY_STORE = "My";
    CAPICOM_STORE_OPEN_READ_ONLY = 0;
    CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0;
    
    oStore = СоздатьОбъект("CAdESCOM.Store");
    oStore.Open(CAPICOM_CURRENT_USER_STORE, CAPICOM_MY_STORE, CAPICOM_STORE_OPEN_READ_ONLY);
    Certificates = oStore.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SHA1_HASH, Отпечаток);
    ComОбъект = Certificates.Item(1);
    oStore.Close();
    
    Возврат ComОбъект;
КонецФункции

Функция ПодписатьТекст(ТекстДляПодписи, Отпечаток)
    CADESCOM_BASE64_TO_BINARY = 1;
    CADESCOM_CADES_TYPE = 1; // Усовершенствованная подпись
    bDetached = 1; // 1 - Открепленная подпись
    EncodingType = 0;
    
    oSigner = СоздатьОбъект("CAdESCOM.CPSigner");
    oSigner.Options = 2;
    oSigner.Certificate = ComОбъектСертификатаПоОтпечатку(Отпечаток);
    
    oSignedData = СоздатьОбъект("CAdESCOM.CadesSignedData");
    oSignedData.ContentEncoding = CADESCOM_BASE64_TO_BINARY;
    
    // Функция Кодировать() переводит строку в Base64
    oSignedData.Content = Кодировать(ТекстДляПодписи);    
    
    sSignedMessage = oSignedData.SignCades(oSigner, CADESCOM_CADES_TYPE, bDetached, EncodingType);
    
    // Очистка от переносов строк, если они появились
    sSignedMessage = СтрЗаменить(sSignedMessage, Симв(13), "");
    sSignedMessage = СтрЗаменить(sSignedMessage, Симв(10), "");
    
    Возврат sSignedMessage;
КонецФункции

Шаг 3. Отправка подписанных данных и получение Токена

После подписания мы формируем JSON-тело с оригинальным uuid и подписанной строкой data. Отправляем это POST-запросом.


Процедура ПолучитьТокен()
    WinHttp = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
    WinHttp.Open("POST", "https://ismotp.crptech.ru/api/v3/true-api/auth/simpleSignIn", 1);
    WinHttp.SetRequestHeader("Content-Type", "application/json");
    WinHttp.SetRequestHeader("Accept-Charset", "utf-8");
    
    СтрокаЗапроса = "{""uuid"": """ + СокрЛП(uuid) + """,""data"": """ + ПодписаннаяДата + """}";
    WinHttp.Send(СтрокаЗапроса);
    WinHttp.WaitForResponse(40);
    
    РезультатСтр = WinHttp.ResponseText();
    // Извлекаем "token" из JSON ответа
КонецПроцедуры

Важно: Полученный токен обычно живет около 10 часов. Его нужно подставлять во все последующие запросы в заголовок Authorization: Bearer [Ваш_Токен]. При частых запросах система может вернуть ошибку 429 Too Many Requests — в этом случае делайте паузу (например, с помощью внешней компоненты FormEx или 1С++) и повторяйте запрос.

Шаг 4. Разагрегация (получение списка КИЗ из упаковки)

Когда товар приходит в транспортной упаковке (коробах или блоках), учетной системе нужно знать коды каждой пачки. Для этого используется API-метод агрегации. Запрос делается по конкретному штрихкоду упаковки (перед запросом из ШК нужно удалить криптохвост до первого спецсимвола GS).


Процедура Разагрегация()
    token = ПолучитьТокенЦРПТ(); // Наша функция авторизации
    КодУпаковки = ОтрезатьЛишнееОтСтрМаркировки(СокрЛП(КодМаркировки));
    
    WinHttp = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
    Url = "https://ismotp.crptech.ru/api/v3/true-api/cises/aggregated/list?codes=" + КодУпаковки;
    
    WinHttp.Open("GET", Url, 0); 
    WinHttp.SetRequestHeader("Authorization", "Bearer " + token);
    WinHttp.SetRequestHeader("Content-Type", "application/json");
    WinHttp.Send();
    
    Ответ = WinHttp.ResponseText();
    СзКодов = глРазборJSON(Ответ);
    
    Если СзКодов.РазмерСписка() > 0 Тогда
        // Обрабатываем полученный массив вложенных марок (пачек)
        Сообщить("Успешно получены коды пачек!");
    КонецЕсли;
КонецПроцедуры

Стоит отметить, что метод возвращает только первый слой вложенности. Если вы запрашиваете короб, в ответе будут блоки. Чтобы получить пачки, потребуется выполнить повторный цикл запросов по кодам блоков. Для табачной продукции сервер нормально воспринимает коды как со скобками (01) и (21), так и без них, возвращая ответ в аналогичном формате.

← На главную