Інтеграція з 1С/BAS

Практичні функції 1С 8 для створення операції, відправки одного або багатьох документів, отримання результату, webhook і розбору JSON.

API документація Кабінет

1. Налаштування підключення

ПараметрЗначення
Хостjdoc.net.ua
HTTPSТак, порт 443.
АвторизаціяAuthorization: Bearer <API_KEY>
Створення операціїPOST /api/v1/operations
Файлиmultipart/form-data, поле files[].
ПакетДо 100 файлів за один запит.
Перем JDOC_API_HOST;
Перем JDOC_API_KEY;

Процедура JDOC_Ініціалізувати(APIКлюч) Экспорт
    JDOC_API_HOST = "jdoc.net.ua";
    JDOC_API_KEY = APIКлюч;
КонецПроцедуры

Функция JDOC_Соединение() Экспорт
    Возврат Новый HTTPСоединение(JDOC_API_HOST, 443,,,,, Новый ЗащищенноеСоединениеOpenSSL);
КонецФункции

Функция JDOC_НовыйIdempotencyKey(Префикс = "jdoc") Экспорт
    Возврат Префикс + "-" + Строка(Новый УникальныйИдентификатор);
КонецФункции

2. Допоміжні функції JSON і HTTP

Функция JDOC_ПрочитатьJSON(ОтветHTTP) Экспорт
    Тело = ОтветHTTP.ПолучитьТелоКакСтроку();
    ЧтениеJSON = Новый ЧтениеJSON;
    ЧтениеJSON.УстановитьСтроку(Тело);
    Возврат ПрочитатьJSON(ЧтениеJSON);
КонецФункции

Процедура JDOC_ПроверитьHTTP(ОтветHTTP) Экспорт
    Код = ОтветHTTP.КодСостояния;
    Если Код < 200 Или Код >= 300 Тогда
        ВызватьИсключение "JDOC HTTP " + Строка(Код) + ": " + ОтветHTTP.ПолучитьТелоКакСтроку();
    КонецЕсли;
КонецПроцедуры

3. Multipart/form-data для файлів

JDOC приймає файли у полі files[]. Для багатьох документів додайте кілька частин з однаковим name files[].

Функция JDOC_СобратьMultipart(МассивПутейКФайлам, Boundary, WebhookURL = "", MetadataJSON = "", ClientOperationID = "") Экспорт
    CRLF = Символы.ВК + Символы.ПС;
    Поток = Новый ПотокВПамяти;
    Запись = Новый ЗаписьДанных(Поток);

    Для Каждого ПутьКФайлу Из МассивПутейКФайлам Цикл
        Файл = Новый Файл(ПутьКФайлу);
        ИмяФайла = Файл.Имя;
        Mime = ?(НРег(Файл.Расширение) = ".pdf", "application/pdf", "application/octet-stream");

        Заголовок = "--" + Boundary + CRLF
            + "Content-Disposition: form-data; name=\"files[]\"; filename=\"" + ИмяФайла + "\"" + CRLF
            + "Content-Type: " + Mime + CRLF + CRLF;

        Запись.ЗаписатьСтроку(Заголовок, КодировкаТекста.UTF8);
        Запись.Записать(Новый ДвоичныеДанные(ПутьКФайлу));
        Запись.ЗаписатьСтроку(CRLF, КодировкаТекста.UTF8);
    КонецЦикла;

    Если WebhookURL <> "" Тогда
        Запись.ЗаписатьСтроку("--" + Boundary + CRLF
            + "Content-Disposition: form-data; name=\"webhook_url\"" + CRLF + CRLF
            + WebhookURL + CRLF, КодировкаТекста.UTF8);
    КонецЕсли;

    Если MetadataJSON <> "" Тогда
        Запись.ЗаписатьСтроку("--" + Boundary + CRLF
            + "Content-Disposition: form-data; name=\"metadata\"" + CRLF + CRLF
            + MetadataJSON + CRLF, КодировкаТекста.UTF8);
    КонецЕсли;

    Если ClientOperationID <> "" Тогда
        Запись.ЗаписатьСтроку("--" + Boundary + CRLF
            + "Content-Disposition: form-data; name=\"client_operation_id\"" + CRLF + CRLF
            + ClientOperationID + CRLF, КодировкаТекста.UTF8);
    КонецЕсли;

    Запись.ЗаписатьСтроку("--" + Boundary + "--" + CRLF, КодировкаТекста.UTF8);
    Запись.Закрыть();
    Возврат Поток.ЗакрытьИПолучитьДвоичныеДанные();
КонецФункции

4. Створити операцію: один документ

Функция JDOC_СоздатьОперациюОдинФайл(ПутьКФайлу, APIКлюч, IdempotencyKey = "", WebhookURL = "") Экспорт
    Если IdempotencyKey = "" Тогда IdempotencyKey = JDOC_НовыйIdempotencyKey("upload-one"); КонецЕсли;

    Boundary = "----JDOC1C" + СтрЗаменить(Строка(Новый УникальныйИдентификатор), "-", "");
    Файлы = Новый Массив;
    Файлы.Добавить(ПутьКФайлу);
    Тело = JDOC_СобратьMultipart(Файлы, Boundary, WebhookURL);

    Запрос = Новый HTTPЗапрос("/api/v1/operations");
    Запрос.Заголовки.Вставить("Authorization", "Bearer " + APIКлюч);
    Запрос.Заголовки.Вставить("Idempotency-Key", IdempotencyKey);
    Запрос.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Boundary);
    Запрос.УстановитьТелоИзДвоичныхДанных(Тело);

    Ответ = JDOC_Соединение().ОтправитьДляОбработки(Запрос);
    JDOC_ПроверитьHTTP(Ответ);
    Возврат JDOC_ПрочитатьJSON(Ответ);
КонецФункции

5. Створити операцію: кілька документів

Можна передати до 100 файлів за один запит.

Функция JDOC_СоздатьОперациюНесколькоФайлов(МассивПутейКФайлам, APIКлюч, IdempotencyKey = "", WebhookURL = "") Экспорт
    Если МассивПутейКФайлам.Количество() > 100 Тогда
        ВызватьИсключение "JDOC принимает до 100 файлов за один запрос.";
    КонецЕсли;

    Если IdempotencyKey = "" Тогда IdempotencyKey = JDOC_НовыйIdempotencyKey("upload-batch"); КонецЕсли;

    Boundary = "----JDOC1C" + СтрЗаменить(Строка(Новый УникальныйИдентификатор), "-", "");
    Тело = JDOC_СобратьMultipart(МассивПутейКФайлам, Boundary, WebhookURL);

    Запрос = Новый HTTPЗапрос("/api/v1/operations");
    Запрос.Заголовки.Вставить("Authorization", "Bearer " + APIКлюч);
    Запрос.Заголовки.Вставить("Idempotency-Key", IdempotencyKey);
    Запрос.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Boundary);
    Запрос.УстановитьТелоИзДвоичныхДанных(Тело);

    Ответ = JDOC_Соединение().ОтправитьДляОбработки(Запрос);
    JDOC_ПроверитьHTTP(Ответ);
    Возврат JDOC_ПрочитатьJSON(Ответ);
КонецФункции

6. Отримати операцію, результати і webhook-статус

Функция JDOC_ПолучитьОперацию(OperationID, APIКлюч) Экспорт
    Запрос = Новый HTTPЗапрос("/api/v1/operations/" + OperationID);
    Запрос.Заголовки.Вставить("Authorization", "Bearer " + APIКлюч);
    Ответ = JDOC_Соединение().Получить(Запрос);
    JDOC_ПроверитьHTTP(Ответ);
    Возврат JDOC_ПрочитатьJSON(Ответ);
КонецФункции

Функция JDOC_ПолучитьРезультатыОперации(OperationID, APIКлюч) Экспорт
    Запрос = Новый HTTPЗапрос("/api/v1/operations/" + OperationID + "/results");
    Запрос.Заголовки.Вставить("Authorization", "Bearer " + APIКлюч);
    Ответ = JDOC_Соединение().Получить(Запрос);
    JDOC_ПроверитьHTTP(Ответ);
    Возврат JDOC_ПрочитатьJSON(Ответ);
КонецФункции

Функция JDOC_ПолучитьРезультатДокумента(DocumentID, APIКлюч) Экспорт
    Запрос = Новый HTTPЗапрос("/api/v1/documents/" + DocumentID + "/result");
    Запрос.Заголовки.Вставить("Authorization", "Bearer " + APIКлюч);
    Ответ = JDOC_Соединение().Получить(Запрос);
    JDOC_ПроверитьHTTP(Ответ);
    Возврат JDOC_ПрочитатьJSON(Ответ);
КонецФункции

Функция JDOC_ПолучитьWebhookСтатус(OperationID, APIКлюч) Экспорт
    Запрос = Новый HTTPЗапрос("/api/v1/operations/" + OperationID + "/webhook");
    Запрос.Заголовки.Вставить("Authorization", "Bearer " + APIКлюч);
    Ответ = JDOC_Соединение().Получить(Запрос);
    JDOC_ПроверитьHTTP(Ответ);
    Возврат JDOC_ПрочитатьJSON(Ответ);
КонецФункции

7. Дочекатися готового результату

Функция JDOC_ДочекатисяРезультату(OperationID, APIКлюч, ТаймаутСекунд = 180, ПаузаСекунд = 5) Экспорт
    Начало = ТекущаяДата();

    Пока Истина Цикл
        Операция = JDOC_ПолучитьОперацию(OperationID, APIКлюч);

        Если Операция.status = "PROCESSED" Или Операция.status = "PROCESSED_WITH_WARNINGS" Тогда
            Возврат Операция;
        КонецЕсли;

        Если Операция.status = "FAILED" Или Операция.status = "CANCELLED"
            Или Операция.status = "COMPLETED_WITH_ERRORS" Тогда
            Возврат Операция;
        КонецЕсли;

        Если ТекущаяДата() - Начало > ТаймаутСекунд Тогда
            ВызватьИсключение "JDOC: истек таймаут ожидания.";
        КонецЕсли;

        Пауза(ПаузаСекунд);
    КонецЦикла;
КонецФункции

8. Webhook: що отримує 1С/BAS

Якщо ви налаштували webhook у кабінеті, JDOC надсилає POST-запит у вашу систему після завершення обробки. Повний результат краще забирати через GET-запит за operation_id або document_id.

Основні headers

HeaderОпис
X-DocParser-EventТип події.
X-DocParser-Operation-IdID операції.
X-DocParser-Document-IdID документа, якщо подія документна.
X-DocParser-Event-IdID події для дедуплікації.
X-DocParser-TimestampTimestamp підпису.
X-DocParser-SignatureПідпис sha256=....

Приклад payload

{
  "event_type": "operation.completed",
  "event_id": "evt_xxx",
  "operation_id": "op_xxx",
  "status": "PROCESSED",
  "summary": {
    "files_total": 1,
    "processed": 1,
    "processed_with_warnings": 0,
    "rejected": 0,
    "failed": 0,
    "cancelled": 0
  },
  "documents": [
    {
      "document_id": "doc_xxx",
      "filename": "document.pdf",
      "status": "PROCESSED",
      "billing": {
        "billable": true,
        "documents_charged": 1
      }
    }
  ]
}

Перевірка підпису

Підпис рахується як HMAC-SHA256 від рядка timestamp + "." + raw_body секретом webhook.

Функция JDOC_WebhookПідписДійсний(ТелоJSON, Timestamp, Signature, Secret) Экспорт
    // Псевдокод: реалізація HMAC залежить від вашої конфігурації 1С/BAS
    СтрокаДляПодписи = Timestamp + "." + ТелоJSON;
    ОжидаемаяПодпись = "sha256=" + HMAC_SHA256_HEX(Secret, СтрокаДляПодписи);
    Возврат ОжидаемаяПодпись = Signature;
КонецФункции

9. Що читати з JSON

ДаніПоле
Номер документаdocuments[0].result.document.number
Датаdocuments[0].result.document.date
Контрагентиdocuments[0].result.parties
Рядкиdocuments[0].result.line_items
Сумиdocuments[0].result.totals
ПДВdocuments[0].result.taxes
Попередженняdocuments[0].warnings

10. Підтримка інтеграції

Якщо потрібна допомога з API або 1С/BAS, напишіть на support@jdoc.net.ua.