chore: копии схем контракта v1.0 и примеров в api/contracts
Скопировано из ../docs/contracts байт в байт (cp, diff -r чистый). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
e676e75c38
commit
f8a584af15
14
api/contracts/examples/request-image.json
Normal file
14
api/contracts/examples/request-image.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"schema_version": "1.0",
|
||||||
|
"job_id": "8d6b1f30-2e94-4a7c-b5d8-0f1e9c3a6b03",
|
||||||
|
"file_id": "c7e2a9b4-1d58-4630-a2f7-6b4d8e0c1f04",
|
||||||
|
"pipeline": "image",
|
||||||
|
"file_type": "PDF",
|
||||||
|
"original_name": "bb_2025_q3.pdf",
|
||||||
|
"s3": {
|
||||||
|
"bucket": "arm-ka",
|
||||||
|
"key": "uploads/c7e2a9b4-1d58-4630-a2f7-6b4d8e0c1f04/8d6b1f30-2e94-4a7c-b5d8-0f1e9c3a6b03/bb_2025_q3.pdf"
|
||||||
|
},
|
||||||
|
"reply_deadline": "2026-10-03T12:45:00Z",
|
||||||
|
"attempt": 1
|
||||||
|
}
|
||||||
14
api/contracts/examples/request-tabular.json
Normal file
14
api/contracts/examples/request-tabular.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"schema_version": "1.0",
|
||||||
|
"job_id": "3f2a9c1e-7b4d-4e0a-9d51-2c8e6a1b0f01",
|
||||||
|
"file_id": "a1c4e7d2-5b36-4f89-8e12-9d0c3b7a4e02",
|
||||||
|
"pipeline": "tabular",
|
||||||
|
"file_type": "XLSX",
|
||||||
|
"original_name": "osv_60_2025_q1.xlsx",
|
||||||
|
"s3": {
|
||||||
|
"bucket": "arm-ka",
|
||||||
|
"key": "uploads/a1c4e7d2-5b36-4f89-8e12-9d0c3b7a4e02/3f2a9c1e-7b4d-4e0a-9d51-2c8e6a1b0f01/osv_60_2025_q1.xlsx"
|
||||||
|
},
|
||||||
|
"reply_deadline": "2026-10-03T12:30:00Z",
|
||||||
|
"attempt": 1
|
||||||
|
}
|
||||||
12
api/contracts/examples/result-error.json
Normal file
12
api/contracts/examples/result-error.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"schema_version": "1.0",
|
||||||
|
"job_id": "3f2a9c1e-7b4d-4e0a-9d51-2c8e6a1b0f01",
|
||||||
|
"file_id": "a1c4e7d2-5b36-4f89-8e12-9d0c3b7a4e02",
|
||||||
|
"service": { "name": "tabular-parser", "version": "0.1.0" },
|
||||||
|
"status": "error",
|
||||||
|
"error": {
|
||||||
|
"code": "NOT_IMPLEMENTED",
|
||||||
|
"message": "Разбор ОСВ пока не реализован / OSV parsing is not implemented yet"
|
||||||
|
},
|
||||||
|
"documents": []
|
||||||
|
}
|
||||||
21
api/contracts/examples/result-message-done.json
Normal file
21
api/contracts/examples/result-message-done.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"schema_version": "1.0",
|
||||||
|
"job_id": "8d6b1f30-2e94-4a7c-b5d8-0f1e9c3a6b03",
|
||||||
|
"file_id": "c7e2a9b4-1d58-4630-a2f7-6b4d8e0c1f04",
|
||||||
|
"status": "done",
|
||||||
|
"service": { "name": "scan-gateway", "version": "0.1.0" },
|
||||||
|
"result_s3": {
|
||||||
|
"bucket": "arm-ka",
|
||||||
|
"key": "results/c7e2a9b4-1d58-4630-a2f7-6b4d8e0c1f04/8d6b1f30-2e94-4a7c-b5d8-0f1e9c3a6b03/result.json"
|
||||||
|
},
|
||||||
|
"result_schema_version": "1.0",
|
||||||
|
"raw_s3_key": "raw/8d6b1f30-2e94-4a7c-b5d8-0f1e9c3a6b03.json",
|
||||||
|
"metrics": {
|
||||||
|
"duration_ms": 18400,
|
||||||
|
"pages": 2,
|
||||||
|
"fields_total": 4,
|
||||||
|
"fields_low_confidence": 0,
|
||||||
|
"fields_unrecognized": 0,
|
||||||
|
"warnings": []
|
||||||
|
}
|
||||||
|
}
|
||||||
11
api/contracts/examples/result-message-error.json
Normal file
11
api/contracts/examples/result-message-error.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"schema_version": "1.0",
|
||||||
|
"job_id": "3f2a9c1e-7b4d-4e0a-9d51-2c8e6a1b0f01",
|
||||||
|
"file_id": "a1c4e7d2-5b36-4f89-8e12-9d0c3b7a4e02",
|
||||||
|
"status": "error",
|
||||||
|
"service": { "name": "tabular-parser", "version": "0.1.0" },
|
||||||
|
"error": {
|
||||||
|
"code": "NOT_IMPLEMENTED",
|
||||||
|
"message": "Разбор ОСВ пока не реализован / OSV parsing is not implemented yet"
|
||||||
|
}
|
||||||
|
}
|
||||||
7
api/contracts/examples/result-message-processing.json
Normal file
7
api/contracts/examples/result-message-processing.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"schema_version": "1.0",
|
||||||
|
"job_id": "3f2a9c1e-7b4d-4e0a-9d51-2c8e6a1b0f01",
|
||||||
|
"file_id": "a1c4e7d2-5b36-4f89-8e12-9d0c3b7a4e02",
|
||||||
|
"status": "processing",
|
||||||
|
"service": { "name": "tabular-parser", "version": "0.1.0" }
|
||||||
|
}
|
||||||
79
api/contracts/examples/result-osv-minimal.json
Normal file
79
api/contracts/examples/result-osv-minimal.json
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"schema_version": "1.0",
|
||||||
|
"job_id": "3f2a9c1e-7b4d-4e0a-9d51-2c8e6a1b0f01",
|
||||||
|
"file_id": "a1c4e7d2-5b36-4f89-8e12-9d0c3b7a4e02",
|
||||||
|
"service": { "name": "tabular-parser", "version": "0.1.0" },
|
||||||
|
"status": "done",
|
||||||
|
"documents": [
|
||||||
|
{
|
||||||
|
"document_type": "OSV",
|
||||||
|
"locator": "sheet:Лист_1",
|
||||||
|
"header": {
|
||||||
|
"organization_name": "ООО Ромашка",
|
||||||
|
"organization_inn": "7700000000",
|
||||||
|
"account_code_raw": "60",
|
||||||
|
"period_text": "1 квартал 2025 г.",
|
||||||
|
"period_year": 2025,
|
||||||
|
"period_quarter": "Q1",
|
||||||
|
"is_cumulative": false,
|
||||||
|
"data_type": "BU",
|
||||||
|
"currency": "RUB",
|
||||||
|
"header_variant": 1
|
||||||
|
},
|
||||||
|
"group_schema": [
|
||||||
|
{ "type": "COUNTERPARTY", "name": "Контрагенты", "has_inn": true }
|
||||||
|
],
|
||||||
|
"columns": {
|
||||||
|
"opening_debit": "C",
|
||||||
|
"opening_credit": "D",
|
||||||
|
"turnover_debit": "E",
|
||||||
|
"turnover_credit": "F",
|
||||||
|
"closing_debit": "G",
|
||||||
|
"closing_credit": "H"
|
||||||
|
},
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"row_number": 1,
|
||||||
|
"level": 0,
|
||||||
|
"parent_row_number": null,
|
||||||
|
"row_value": "60",
|
||||||
|
"group_type": "ACCOUNT",
|
||||||
|
"group_name": null,
|
||||||
|
"account_code_raw": "60",
|
||||||
|
"counterparty_name": null,
|
||||||
|
"counterparty_inn": null,
|
||||||
|
"data_type": "BU",
|
||||||
|
"opening_debit": "0.00",
|
||||||
|
"opening_credit": "1000.00",
|
||||||
|
"turnover_debit": "500.00",
|
||||||
|
"turnover_credit": "200.50",
|
||||||
|
"closing_debit": "0.00",
|
||||||
|
"closing_credit": "700.50"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"row_number": 2,
|
||||||
|
"level": 1,
|
||||||
|
"parent_row_number": 1,
|
||||||
|
"row_value": "ООО Лютик, ИНН 7711111111",
|
||||||
|
"group_type": "COUNTERPARTY",
|
||||||
|
"group_name": "Контрагенты",
|
||||||
|
"account_code_raw": "60",
|
||||||
|
"counterparty_name": "ООО Лютик",
|
||||||
|
"counterparty_inn": "7711111111",
|
||||||
|
"data_type": "BU",
|
||||||
|
"opening_debit": "0.00",
|
||||||
|
"opening_credit": "1000.00",
|
||||||
|
"turnover_debit": "500.00",
|
||||||
|
"turnover_credit": "200.50",
|
||||||
|
"closing_debit": "0.00",
|
||||||
|
"closing_credit": "700.50"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"checks": {
|
||||||
|
"total_row_matches_root": true,
|
||||||
|
"balance_identity_violations": [],
|
||||||
|
"parent_sum_violations": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
50
api/contracts/examples/result-statement-minimal.json
Normal file
50
api/contracts/examples/result-statement-minimal.json
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"schema_version": "1.0",
|
||||||
|
"job_id": "8d6b1f30-2e94-4a7c-b5d8-0f1e9c3a6b03",
|
||||||
|
"file_id": "c7e2a9b4-1d58-4630-a2f7-6b4d8e0c1f04",
|
||||||
|
"service": { "name": "scan-gateway", "version": "0.1.0" },
|
||||||
|
"status": "done",
|
||||||
|
"raw_s3_key": "raw/8d6b1f30-2e94-4a7c-b5d8-0f1e9c3a6b03.json",
|
||||||
|
"documents": [
|
||||||
|
{
|
||||||
|
"document_type": "BALANCE",
|
||||||
|
"locator": "pages:1-2",
|
||||||
|
"header": {
|
||||||
|
"form_name": "Бухгалтерский баланс",
|
||||||
|
"organization_name": "ООО Ромашка",
|
||||||
|
"organization_name_confidence": 97.5,
|
||||||
|
"inn": "7700000000",
|
||||||
|
"inn_confidence": 99,
|
||||||
|
"report_date_text": "30 сентября 2025 г.",
|
||||||
|
"report_date": "2025-09-30",
|
||||||
|
"units": "тыс. руб."
|
||||||
|
},
|
||||||
|
"columns": [
|
||||||
|
{ "column_index": 0, "label": "На 30 сентября 2025 г.", "period_date": "2025-09-30" },
|
||||||
|
{ "column_index": 1, "label": "На 31 декабря 2024 г.", "period_date": "2024-12-31" }
|
||||||
|
],
|
||||||
|
"lines": [
|
||||||
|
{
|
||||||
|
"line_code": "1100",
|
||||||
|
"line_code_confidence": 99,
|
||||||
|
"line_name": "Итого по разделу I",
|
||||||
|
"line_name_confidence": 96,
|
||||||
|
"values": [
|
||||||
|
{ "column_index": 0, "amount": "1234.50", "confidence": 95, "is_recognized": true },
|
||||||
|
{ "column_index": 1, "amount": "1100", "confidence": 93, "is_recognized": true }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"line_code": "1600",
|
||||||
|
"line_code_confidence": 99,
|
||||||
|
"line_name": "БАЛАНС (актив)",
|
||||||
|
"line_name_confidence": 98,
|
||||||
|
"values": [
|
||||||
|
{ "column_index": 0, "amount": "5678.00", "confidence": 94.5, "is_recognized": true },
|
||||||
|
{ "column_index": 1, "amount": "-12.30", "confidence": 90, "is_recognized": true }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
28
api/contracts/recognition-request.schema.json
Normal file
28
api/contracts/recognition-request.schema.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "arm-ka/recognition-request/v1",
|
||||||
|
"title": "Запрос распознавания файла (arm-core → tabular-parser / scan-gateway), контракт v1.0",
|
||||||
|
"description": "Тело сообщения на subject recognition.tabular.request или recognition.image.request; subject должен соответствовать полю pipeline (tabular → recognition.tabular.request, image → recognition.image.request). Заголовок Nats-Msg-Id = <job_id>:<attempt> (не поле тела). Один файл (stored_file) → один job.",
|
||||||
|
"$comment": "Версионирование: schema_version = MAJOR.MINOR. MINOR (1.1) — необязательные поля и новые значения enum; MAJOR (2.0) — удаление/переименование полей, смена типов или семантики. Потребитель принимает тот же MAJOR и любой MINOR. Новый MINOR раскатывается сначала на потребителей (ядро и сервисы обновляют копии схем раньше, чем производитель начнёт слать 1.1), потому что закрытые enum отвергают незнакомые значения.",
|
||||||
|
"type": "object",
|
||||||
|
"required": ["schema_version", "job_id", "file_id", "pipeline", "file_type", "original_name", "s3", "reply_deadline", "attempt"],
|
||||||
|
"properties": {
|
||||||
|
"schema_version": { "type": "string", "pattern": "^1\\.\\d+$", "description": "MAJOR.MINOR; производитель контракта v1.0 пишет \"1.0\"" },
|
||||||
|
"job_id": { "type": "string", "format": "uuid", "description": "recognition_job.id" },
|
||||||
|
"file_id": { "type": "string", "format": "uuid", "description": "stored_file.id" },
|
||||||
|
"pipeline": { "enum": ["tabular", "image"], "description": "конвейер распознавания; определяет subject запроса" },
|
||||||
|
"file_type": { "enum": ["XLS", "XLSX", "XLSB", "PDF", "PNG", "JPG"] },
|
||||||
|
"original_name": { "type": "string", "minLength": 1, "description": "имя файла, как загрузил пользователь" },
|
||||||
|
"s3": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "исходный файл в роли uploads",
|
||||||
|
"required": ["bucket", "key"],
|
||||||
|
"properties": {
|
||||||
|
"bucket": { "type": "string", "minLength": 1 },
|
||||||
|
"key": { "type": "string", "minLength": 1 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"reply_deadline": { "type": "string", "format": "date-time", "description": "срок ответа, UTC" },
|
||||||
|
"attempt": { "type": "integer", "minimum": 1, "description": "номер попытки, с 1" }
|
||||||
|
}
|
||||||
|
}
|
||||||
70
api/contracts/recognition-result-message.schema.json
Normal file
70
api/contracts/recognition-result-message.schema.json
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "arm-ka/recognition-result-message/v1",
|
||||||
|
"title": "Сообщение результата распознавания (tabular-parser / scan-gateway → arm-core), контракт v1.0",
|
||||||
|
"description": "Тело сообщения на subject recognition.result. Заголовок Nats-Msg-Id (не поле тела) на этом subject имеет две формы: ack:<job_id>:<attempt> — для status = processing; result:<job_id>:<attempt> — для done, needs_check и error. Форма запроса <job_id>:<attempt> описана в схеме recognition-request. status = processing — ack «взял в работу», публикуется до чтения файла из S3. group_schema в конверт не входит: источник — файл результата (recognition-result).",
|
||||||
|
"$comment": "Версионирование: schema_version = MAJOR.MINOR. MINOR (1.1) — необязательные поля и новые значения enum; MAJOR (2.0) — удаление/переименование полей, смена типов или семантики. Потребитель принимает тот же MAJOR и любой MINOR. Новый MINOR раскатывается сначала на потребителей (ядро и сервисы обновляют копии схем раньше, чем производитель начнёт слать 1.1), потому что закрытые enum отвергают незнакомые значения.",
|
||||||
|
"type": "object",
|
||||||
|
"required": ["schema_version", "job_id", "file_id", "status", "service"],
|
||||||
|
"properties": {
|
||||||
|
"schema_version": { "type": "string", "pattern": "^1\\.\\d+$", "description": "MAJOR.MINOR; производитель контракта v1.0 пишет \"1.0\"" },
|
||||||
|
"job_id": { "type": "string", "format": "uuid", "description": "recognition_job.id" },
|
||||||
|
"file_id": { "type": "string", "format": "uuid", "description": "stored_file.id" },
|
||||||
|
"status": { "enum": ["processing", "done", "needs_check", "error"] },
|
||||||
|
"service": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["name", "version"],
|
||||||
|
"properties": {
|
||||||
|
"name": { "enum": ["tabular-parser", "scan-gateway"] },
|
||||||
|
"version": { "type": "string" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"result_s3": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "файл результата (recognition-result): results/{file_id}/{job_id}/result.json",
|
||||||
|
"required": ["bucket", "key"],
|
||||||
|
"properties": {
|
||||||
|
"bucket": { "type": "string", "minLength": 1 },
|
||||||
|
"key": { "type": "string", "minLength": 1 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"result_schema_version": { "type": "string", "pattern": "^\\d+\\.\\d+$", "description": "schema_version файла результата, MAJOR.MINOR" },
|
||||||
|
"error": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["code", "message"],
|
||||||
|
"properties": {
|
||||||
|
"code": { "enum": ["UNSUPPORTED_FORMAT", "UNREADABLE", "TIMEOUT", "SCHEMA_MISMATCH", "NOT_IMPLEMENTED", "FILE_READ_ERROR", "INVALID_FORMAT", "INVALID_DOCUMENT", "RECOGNITION_FAILED", "UNKNOWN_ERROR"] },
|
||||||
|
"message": { "type": "string" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"raw_s3_key": { "type": ["string", "null"], "description": "scan-gateway: raw/{job_id}.json — сырой ответ ИС Сканирование; в БД не регистрируется" },
|
||||||
|
"metrics": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"duration_ms": { "type": "integer" },
|
||||||
|
"pages": { "type": "integer" },
|
||||||
|
"rows": { "type": "integer" },
|
||||||
|
"fields_total": { "type": "integer" },
|
||||||
|
"fields_low_confidence": { "type": "integer" },
|
||||||
|
"fields_unrecognized": { "type": "integer" },
|
||||||
|
"warnings": { "type": "array", "items": { "type": "string" } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"properties": { "status": { "enum": ["done", "needs_check"] } },
|
||||||
|
"required": ["status"]
|
||||||
|
},
|
||||||
|
"then": { "required": ["result_s3", "result_schema_version"] }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"properties": { "status": { "const": "error" } },
|
||||||
|
"required": ["status"]
|
||||||
|
},
|
||||||
|
"then": { "required": ["error"] }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
197
api/contracts/recognition-result.schema.json
Normal file
197
api/contracts/recognition-result.schema.json
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"$id": "arm-ka/recognition-result/v1",
|
||||||
|
"title": "Результат распознавания файла (tabular-parser / scan-gateway), контракт v1.0",
|
||||||
|
"description": "Один файл (stored_file) → один job → N документов. Сервисы не знают БД: только структура файла. Нормализация счетов, резолв контрагентов, проверки — в arm-core.",
|
||||||
|
"$comment": "Версионирование: schema_version = MAJOR.MINOR. MINOR (1.1) — необязательные поля и новые значения enum; MAJOR (2.0) — удаление/переименование полей, смена типов или семантики. Потребитель принимает тот же MAJOR и любой MINOR. Новый MINOR раскатывается сначала на потребителей (ядро и сервисы обновляют копии схем раньше, чем производитель начнёт слать 1.1), потому что закрытые enum отвергают незнакомые значения.",
|
||||||
|
"type": "object",
|
||||||
|
"required": ["schema_version", "job_id", "file_id", "service", "status", "documents"],
|
||||||
|
"properties": {
|
||||||
|
"schema_version": { "type": "string", "pattern": "^1\\.\\d+$", "description": "MAJOR.MINOR; производитель контракта v1.0 пишет \"1.0\"" },
|
||||||
|
"job_id": { "type": "string", "format": "uuid" },
|
||||||
|
"file_id": { "type": "string", "format": "uuid" },
|
||||||
|
"service": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["name", "version"],
|
||||||
|
"properties": {
|
||||||
|
"name": { "enum": ["tabular-parser", "scan-gateway"] },
|
||||||
|
"version": { "type": "string" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": { "enum": ["done", "needs_check", "error"] },
|
||||||
|
"error": {
|
||||||
|
"type": ["object", "null"],
|
||||||
|
"properties": {
|
||||||
|
"code": { "enum": ["UNSUPPORTED_FORMAT", "UNREADABLE", "TIMEOUT", "SCHEMA_MISMATCH", "NOT_IMPLEMENTED", "FILE_READ_ERROR", "INVALID_FORMAT", "INVALID_DOCUMENT", "RECOGNITION_FAILED", "UNKNOWN_ERROR"] },
|
||||||
|
"message": { "type": "string" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"metrics": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"duration_ms": { "type": "integer" },
|
||||||
|
"pages": { "type": "integer" },
|
||||||
|
"rows": { "type": "integer" },
|
||||||
|
"fields_total": { "type": "integer" },
|
||||||
|
"fields_low_confidence": { "type": "integer" },
|
||||||
|
"fields_unrecognized": { "type": "integer" },
|
||||||
|
"warnings": { "type": "array", "items": { "type": "string" } }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"raw_s3_key": { "type": ["string", "null"], "description": "scan-gateway: raw/{job_id}.json — сырой ответ ИС Сканирование; в БД не регистрируется" },
|
||||||
|
"documents": {
|
||||||
|
"type": "array",
|
||||||
|
"items": { "oneOf": [ { "$ref": "#/$defs/osvDocument" }, { "$ref": "#/$defs/statementDocument" } ] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"if": {
|
||||||
|
"properties": { "status": { "enum": ["done", "needs_check"] } },
|
||||||
|
"required": ["status"]
|
||||||
|
},
|
||||||
|
"then": {
|
||||||
|
"properties": { "documents": { "minItems": 1 } }
|
||||||
|
},
|
||||||
|
"$defs": {
|
||||||
|
"money": { "type": ["string", "null"], "pattern": "^-?\\d+(\\.\\d{1,2})?$", "description": "Decimal как строка, чтобы не терять копейки в JSON" },
|
||||||
|
"osvDocument": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["document_type", "locator", "header", "group_schema", "rows"],
|
||||||
|
"properties": {
|
||||||
|
"document_type": { "const": "OSV" },
|
||||||
|
"locator": { "type": "string", "examples": ["sheet:Лист_1"] },
|
||||||
|
"header": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["organization_name", "account_code_raw", "period_text"],
|
||||||
|
"properties": {
|
||||||
|
"organization_name": { "type": "string", "description": "как в r1 файла" },
|
||||||
|
"organization_inn": { "type": ["string", "null"] },
|
||||||
|
"account_code_raw": { "type": "string", "examples": ["60", "58.03"] },
|
||||||
|
"period_text": { "type": "string", "examples": ["1 квартал 2025 г.", "2024 г."] },
|
||||||
|
"period_year": { "type": ["integer", "null"] },
|
||||||
|
"period_quarter": { "enum": ["Q1", "Q2", "Q3", "Q4", null] },
|
||||||
|
"is_cumulative": { "type": ["boolean", "null"], "description": "по тексту; ядро может переопределить по данным (OQ-02)" },
|
||||||
|
"data_type": { "enum": ["BU", "NU", "SUM", "CURRENCY", "QUANTITY", null] },
|
||||||
|
"currency": { "type": ["string", "null"], "examples": ["RUB", "руб."] },
|
||||||
|
"header_variant": { "enum": [1, 2] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"group_schema": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "порядок группировок из шапки, после первого ACCOUNT",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["type"],
|
||||||
|
"properties": {
|
||||||
|
"type": { "enum": ["ACCOUNT", "DEPARTMENT", "COUNTERPARTY", "CONTRACT", "OTHER"] },
|
||||||
|
"name": { "type": "string", "description": "исходный текст из шапки" },
|
||||||
|
"has_inn": { "type": "boolean" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"columns": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "диагностика: какие колонки листа были приняты за шесть сумм и ИНН",
|
||||||
|
"additionalProperties": { "type": "string" }
|
||||||
|
},
|
||||||
|
"rows": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["row_number", "level", "row_value", "group_type"],
|
||||||
|
"properties": {
|
||||||
|
"row_number": { "type": "integer" },
|
||||||
|
"level": { "type": "integer" },
|
||||||
|
"parent_row_number": { "type": ["integer", "null"] },
|
||||||
|
"row_value": { "type": "string" },
|
||||||
|
"group_type": { "enum": ["ACCOUNT", "DEPARTMENT", "COUNTERPARTY", "CONTRACT", "OTHER", "TOTAL"] },
|
||||||
|
"group_name": { "type": ["string", "null"] },
|
||||||
|
"account_code_raw": { "type": ["string", "null"], "description": "код текущей ветки, как в файле (60.1)" },
|
||||||
|
"counterparty_name": { "type": ["string", "null"] },
|
||||||
|
"counterparty_inn": { "type": ["string", "null"] },
|
||||||
|
"data_type": { "enum": ["BU", "NU", "SUM", "CURRENCY", "QUANTITY", null] },
|
||||||
|
"opening_debit": { "$ref": "#/$defs/money" },
|
||||||
|
"opening_credit": { "$ref": "#/$defs/money" },
|
||||||
|
"turnover_debit": { "$ref": "#/$defs/money" },
|
||||||
|
"turnover_credit": { "$ref": "#/$defs/money" },
|
||||||
|
"closing_debit": { "$ref": "#/$defs/money" },
|
||||||
|
"closing_credit": { "$ref": "#/$defs/money" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"checks": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"total_row_matches_root": { "type": "boolean" },
|
||||||
|
"balance_identity_violations": { "type": "array", "items": { "type": "integer" }, "description": "row_number строк, где opening−turnover≠closing" },
|
||||||
|
"parent_sum_violations": { "type": "array", "items": { "type": "integer" } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"statementDocument": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["document_type", "locator", "header", "columns", "lines"],
|
||||||
|
"properties": {
|
||||||
|
"document_type": { "enum": ["BALANCE", "INCOME", "OTHER"] },
|
||||||
|
"locator": { "type": "string", "examples": ["pages:1-2"] },
|
||||||
|
"header": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"form_name": { "type": "string" },
|
||||||
|
"organization_name": { "type": ["string", "null"] },
|
||||||
|
"organization_name_confidence": { "type": ["number", "null"], "minimum": 0, "maximum": 100 },
|
||||||
|
"inn": { "type": ["string", "null"] },
|
||||||
|
"inn_confidence": { "type": ["number", "null"], "minimum": 0, "maximum": 100 },
|
||||||
|
"report_date_text": { "type": ["string", "null"] },
|
||||||
|
"report_date": { "type": ["string", "null"], "format": "date" },
|
||||||
|
"units": { "type": ["string", "null"], "examples": ["тыс. руб."] },
|
||||||
|
"okud": { "type": ["string", "null"] },
|
||||||
|
"okpo": { "type": ["string", "null"] },
|
||||||
|
"okopf": { "type": ["string", "null"] },
|
||||||
|
"okfs": { "type": ["string", "null"] },
|
||||||
|
"address": { "type": ["string", "null"] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"columns": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["column_index", "label"],
|
||||||
|
"properties": {
|
||||||
|
"column_index": { "type": "integer" },
|
||||||
|
"label": { "type": "string", "examples": ["На 30 сентября 2025 г."] },
|
||||||
|
"period_date": { "type": ["string", "null"], "format": "date" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lines": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["line_code", "line_name", "values"],
|
||||||
|
"properties": {
|
||||||
|
"line_code": { "type": "string" },
|
||||||
|
"line_code_confidence": { "type": ["number", "null"], "minimum": 0, "maximum": 100 },
|
||||||
|
"line_name": { "type": "string" },
|
||||||
|
"line_name_confidence": { "type": ["number", "null"], "minimum": 0, "maximum": 100 },
|
||||||
|
"values": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["column_index"],
|
||||||
|
"properties": {
|
||||||
|
"column_index": { "type": "integer" },
|
||||||
|
"amount": { "$ref": "#/$defs/money" },
|
||||||
|
"string_value": { "type": ["string", "null"] },
|
||||||
|
"confidence": { "type": ["number", "null"], "minimum": 0, "maximum": 100 },
|
||||||
|
"is_recognized": { "type": "boolean" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user