arm-ka-docs/source/tz/АРМ КА.Техническое задание - 06_7. Функциональные требования - 01_FNR01 Модуль загрузки документов и создания записи.md

161 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
code: DOC-037740
title: "FNR01 Модуль загрузки документов и создания записи"
---
# FNR01 Модуль загрузки документов и создания записи
## ОСВ
### Алгоритм работы:
1. Пользователь авторизуется в системе
2. Система отрисовывает списочную форму сформированных консолидированных отчетов. Пользователь нажимает "Сформировать новый отчет"
3. Система отрисовывает модальное окно для выбора ГСК -> указания отчетного периода -> выбора компании -> добавления документов по компании
4. Пользователь нажимает "Добавить" и выбирает документы для загрузки (допустимые форматы файлов xls, xlsx).
5. Для каждого загружаемого файла ОСВ система создает запись в таблице **stored\\_file**
6. После создания записи **stored\\_file** система создает задание на распознавание в таблице **recognition\\_job.**
7. Сервис выполняет парсинг файла ОСВ. Для каждой распознанной расчетной строки система создает отдельную запись в таблице **osv\\_entry**.
8. После получения **account\\_code** система выполняет нормализацию счета и поиск соответствующей записи в справочнике **chart\\_of\\_account**.
1. в **osv\\_entry.account\\_id** записывается **chart\\_of\\_account.id.**
2. в **osv\\_entry.account\\_root** записывается корневой счет.
9. При наличии в строке контрагента система выполняет его сопоставление со справочником **legal\\_entity**. Если найдено единственное соответствие, в **osv\\_entry.counterparty\\_id** записывается **legal\\_entity.id**. Выполняется последовательный поиск по:
1. **counterparty\\_inn**
2. **legal\\_entity.name**
3. **legal\\_entity\\_alias.normalized\\_alias**
Маппинг stored\\_file
| | | | |
| --- | --- | --- | --- |
| **Поле stored\\_file** | **Источник** | **Пример** | **Правило заполнения** |
| id | Сгенерированный id | uuid | Генерируется до запуска парсинга |
| legal\\_entity\\_id | id владельца ОСВ | uuid организации | Идентификатор компании, для которой пользователь загрузил ОСВ |
| document\\_type | Константа для данного сценария | ОСВ | Всегда "ОСВ" |
| file\\_type | Расширение загруженного файла | XLSX | Для ОСВ используется тип XLSX, XLS |
| original\\_name | Имя исходного файла | ОСВ\\_ООО\\_Пекарня\\_6м2026.xlsx | Сохранить исходное имя файла |
| s3\\_key | Хранилище | ключ объекта | Формируется при сохранении файла в хранилище |
| content\\_hash | Содержимое файла | sha256 | Хеш файла для контроля дублей |
| size\\_bytes | Размер файла | 12345 | Размер файла |
| period\\_year | Шапка ОСВ | 2026 | Нормализованный год |
| period\\_quarter | Шапка ОСВ | Q2 | Заполнить нормализованным периодом |
| status | Система | Обработка | При запуске парсинга - "Обработка" После успешного завершения - "Загружен" При ошибке - "Ошибка" При расхождении контрольных сумм - "Требуется проверка" |
| current\\_recognition\\_job\\_id | Результат успешного запуска | uuid recognition\\_job | После успешного завершения парсинга записать id recognition\\_job |
| uploaded\\_by | id пользователя | uuid | Пользователь, выполнивший загрузку |
| uploaded\\_at | Системное время | timestamp | Дата и время загрузки |
Маппинг recognition\\_job
| | | | |
| --- | --- | --- | --- |
| **Поле recognition\\_job** | **Источник** | **Пример** | **Правило заполнения** |
| id | Сгенерированный id | uuid | Создать до передачи файла в сервис парсинга |
| file\\_id | id загруженного файла | uuid файла | stored\\_file.id на обрабатываемый файл |
| pipeline | Тип файла | tabular | Для ОСВ tabular |
| service\\_version | Версия сервиса парсинга | 1.0 | Заполняет сервис |
| status | Состояние обработки | queued / processing / done / error | Обновлять по жизненному циклу парсинга |
| attempt | Номер попытки | 1 | Увеличивать при повторном запуске |
| queue\\_msg\\_id | Сообщение очереди | id сообщения | Служебное поле дедупликации |
| requested\\_at | Системное время | timestamp | Время постановки в обработку |
| started\\_at | Системное время | timestamp | Время начала обработки |
| finished\\_at | Системное время | timestamp | Время завершения обработки |
| error\\_message | Ошибка сервиса | текст / NULL | Заполнять только при status = error |
| raw\\_result\\_s3\\_key | Результат парсинга | ключ JSON | Ключ JSON результата |
c. Система создаёт запись в таблице **osv\\_entry** и заполняет данными:
Маппинг osv\\_entry
| | | | | |
| --- | --- | --- | --- | --- |
| **Поле** | **Источник в ОСВ** | **Пример** | **Тип** | **Правило заполнения** |
| id | Сгенерированный id | - | uuid | Генерируется для каждой сохраняемой строки |
| stored\\_file\\_id | Сгенерированный id файла | stored\\_file.id | uuid | Записать id файла, из которого получена строка |
| recognition\\_job\\_id | Сгенерированный id парсинга | recognition\\_job.id | uuid | Записать id текущего запуска парсинга |
| legal\\_entity\\_id | id владельца ОСВ | stored\\_file.legal\\_entity\\_id | uuid | Организация-владелец ОСВ |
| account\\_code | Счет или унаследованный текущий счет | 62.01 | varchar | Сохранить исходный код счета |
| account\\_id | Результат нормализации account\\_code | id счета 62.01 | uuid / NULL | Найти точное соответствие account\\_code = chart\\_of\\_account.code. Если точного счета нет, account\\_id оставить NULL |
| account\\_root | Нормализация account\\_code до корневого счета | id счета 62.01 | varchar | Корневой счет первого уровня. 62.01.01 -> 62 |
| counterparty\\_name | Контрагенты | ООО «Ромашка» | varchar / NULL | Сохранить исходное наименование после |
| counterparty\\_inn | Поле ИНН контрагента | 1650123456 | varchar / NULL | Оставить только цифры. При пустом значении оставить NULL |
| counterparty\\_id | Результат сопоставления | uuid / NULL | uuid / NULL | Сначала поиск по ИНН. Если не найдено - по нормализованному имени legal\\_entity.name и legal\\_entity\\_alias.normalized\\_alias. При отсутствии совпадения оставить NULL |
| opening\\_debit | Сальдо на начало периода -> Дебет | 100000.00 | numeric / NULL | Перенести число из соответствующей ячейки |
| opening\\_credit | Сальдо на начало периода -> Кредит | 0.00 | numeric / NULL | Перенести число из соответствующей ячейки |
| turnover\\_debit | Обороты за период -> Дебет | 250000.00 | numeric / NULL | Перенести число из соответствующей ячейки |
| turnover\\_credit | Обороты за период -> Кредит | 170000.00 | numeric / NULL | Перенести число из соответствующей ячейки |
| closing\\_debit | Сальдо на конец периода -> Дебет | 180000.00 | numeric / NULL | Перенести число из соответствующей ячейки |
| closing\\_credit | Сальдо на конец периода -> Кредит | 0.00 | numeric / NULL | Перенести число из соответствующей ячейки |
Маппинг отчетного периода
| **Значение периода в исходной ОСВ** | **Возможные варианты написания** | **Значение в БД period\\_quarter** | **Нарастающий итог (is\\_cumulative)** | **Примечание** |
| --- | --- | --- | --- | --- |
| 1 квартал | 1 квартал, I квартал, 1 кв., I кв., за 1 квартал | 1 | true | |
| 3 месяца | 3 месяца, за 3 месяца, 3 мес., январь-март, 01.01-31.03 | 1 | true | |
| 2 квартал | 2 квартал, II квартал, 2 кв., II кв., за 2 квартал | 2 | false | Нужно уточнить, возможно ли такое, что в ОСВ указывается номер квартала, но считается все равно нарастающий итог |
| Полугодие | полугодие, 1 полугодие, I полугодие, за полугодие, за 1 полугодие | 2 | true | |
| 6 месяцев | 6 месяцев, за 6 месяцев, 6 мес., январь-июнь, 01.01-30.06 | 2 | true | |
| 3 квартал | 3 квартал, III квартал, 3 кв., III кв., за 3 квартал | 3 | false | Нужно уточнить, возможно ли такое, что в ОСВ указывается номер квартала, но считается все равно нарастающий итог |
| 9 месяцев | 9 месяцев, за 9 месяцев, 9 мес., январь-сентябрь, 01.01-30.09 | 3 | true | |
| 4 квартал | 4 квартал, IV квартал, 4 кв., IV кв., за 4 квартал | 4 | false | Нужно уточнить, возможно ли такое, что в ОСВ указывается номер квартала, но считается все равно нарастающий итог |
| Год | год, за год, за 2026 год, годовая, годовая отчетность | 4 | true | |
| 12 месяцев | 12 месяцев, за 12 месяцев, 12 мес., январь-декабрь, 01.01-31.12 | 4 | true | |
Данные полученные в формате json от ИС Сканирование маппируются:
* в таблицу **fin\\_report\\_header** по следующему правилу:
| | | |
| --- | --- | --- |
| Источник (JSON путь) | Целевое поле | Логика преобразования / Примечания/Пример заполнения |
| data\\_ocr[0].label.form\\_name | report\\_type | "Отчет о финансовых результатах"; "Бухгалтерский баланс" |
| data\\_ocr[0].inn.inn | org\\_id | Поиск организации по ИНН в справочнике получение org\\_id |
| data\\_ocr[0].organization.full\\_name | org\\_id | Сличение с наименованием в справочнике Organizations.full\\_name. При несовпадении ищем совпадение в связанной таблице Organization\\_aliases. alias\\_name по ключу org.id. Если не найдено совпадение то выводим предупреждение. |
| data\\_ocr[0].units.measurement | unit | в тыс рублей |
| - | currency | По умолчанию 'RUB', если валюта не указана в JSON |
| // ждем обновленный джейсон пока от ИС сканирование | reporting\\_date | формат даты: DD.MM.YYYY |
| Внешний контекст | package\\_id | ID пакета документов из внешней системы (не в JSON) |
| Системная генерация | report\\_id | Автоинкремент / UUID при вставке |
| Системное время | created\\_at | NOW() при загрузке документа |
| | | |
* в таблицу **F** **in\\_report\\_rows** по следующему правилу:
| | | |
| --- | --- | --- |
| Источник (JSON путь) | Целевое поле | Логика преобразования / Примечания/Пример |
| data\\_ocr[0].table\\_structure.rows[\\*] | (новая строка) | Итерация: одна запись в БД на каждую row из массива |
| rows[0].cells[1].value | наименование колонки | Строка нулевого индекса содержит значения для описания наименований колонок таблицы. Значения Наименование показателя и Код - константы, их можно не парсить каждый раз, но значения колонок периода потребуется переносить как есть полученное из json |
| rows[0].cells[2].value | наименование колонки |
| rows[0].cells[3].value | наименование колонки |
| rows[0].cells40].value | наименование колонки |
| rows[\\*].cells[0].value | row\\_name | Наименование показателя (напр. Выручка, Основные средства) |
| rows[\\*].cells[1].value | row\\_code | Код строки: '2110', '1150', '2400' и т.д. |
| rows[\\*].cells[2].value | value\\_current | Значение за текущий период. Парсить число, заменять , п, м NULL, значение данное в скобках трактовать как отрицательное. Пример: было (2100000) - стало -21000000 |
| rows[\\*].cells[3].value | value\\_prior\\_year | Значение за аналогичный период прошлого года. Аналогичная обработка |
| rows[\\*].cells[4].value (если есть) | value\\_prior2\\_year | Значение за второй предшествующий период (опционально) |
| rows[\\*].cells[\\*].confidence | confidence | Агрегация уверенности: пример: 0.91 |
| Контекст группировки (заголовки разделов) | section | Определение раздела: I. ВНЕОБОРОТНЫЕ АКТИВЫ, Доходы и расходы — по ближайшему заголовку выше строки |
| Анализ стиля/текста ячейки | is\\_total\\_row | TRUE, если row\\_name содержит Итого, БАЛАНС |
| rows[\\*].explanation\\_code (если есть в расширенной схеме) | explanation\\_code | Код пояснений (опционально, если присутствует в структуре) |
| Системная генерация | row\\_id | Автоинкремент / UUID |
| report\\_id из заголовка | report\\_id | FK: подставляется report\\_id из только что созданной записи fin\\_report\\_header |
На визуальную форму выводится шапка документа со структурой:
| Параметр | Поле | Пример |
| --- | --- | --- |
| Тип отчета | report\\_type | Баланс |
| Наименование организации | Organizations.full\\_name по ключу org\\_id | Акционерное общество Русский бисквит |
| ИНН | Organizations.inn по ключу org\\_id | 3528052718 |
| Единица измерения | unit | тыс. руб. |
| Отчетная дата | reporting\\_date | 30.09.2025 |
и табличной частью на основании данных таблицы **F** **in\\_report\\_rows** :
| Пояснение | Наименование показателя | Код | Период 1 (rows[0].cells[2].value) | Период 2 (rows[0].cells[3].value) | Период 3 (rows[0].cells[4].value) |
| --- | --- | --- | --- | --- | --- |
| | row\\_name | row\\_code | value\\_current | value\\_prior\\_year | value\\_prior2\\_year |
После того как парсинг по всем документам завершен (созданы и заполнены все таблицы по всем организациям участвующих в своде, создана сводная ОСВ, запись переходит в статус CREATED (черновик)