plan(#116): план 6 — экран на дополненном API ядра
line_code_confidence и okei в типах, header.source.confidence — строка, подсказка кода из StatementOut.edition_lines, ошибка элемента lines[] у поля строки по detail.line_id (lineErrorTarget вместо codeTakenKeys), значок документа в панели файлов по DocumentBrief.issue_counts (rowBadge). Закрыты O-1…O-6, снят В-2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BJKMLHdxMwSUeYcdkwqX4W
This commit is contained in:
parent
8a7711da5a
commit
1146c0bc3f
@ -89,8 +89,10 @@
|
|||||||
- «Сохранить» отправляет ровно один `PATCH /documents/{id}/statement` (`header`, `values`, `columns`, `lines`); пустой
|
- «Сохранить» отправляет ровно один `PATCH /documents/{id}/statement` (`header`, `values`, `columns`, `lines`); пустой
|
||||||
черновик — запроса нет; ответ заменяет `StatementOut` целиком.
|
черновик — запроса нет; ответ заменяет `StatementOut` целиком.
|
||||||
- Коды ошибок — дословно: 409 `LINES_UNRESOLVED` (`detail.lines[] {line_id, row_index, line_code_text}`), `DUPLICATE_FORM`
|
- Коды ошибок — дословно: 409 `LINES_UNRESOLVED` (`detail.lines[] {line_id, row_index, line_code_text}`), `DUPLICATE_FORM`
|
||||||
(`detail.document_id`), `LINE_CODE_TAKEN`, `PERIOD_REQUIRED`, `CHECKS_NOT_PASSED` (`detail.failures`); 422
|
(`detail.document_id`), `LINE_CODE_TAKEN` (`detail.line_id`, `detail.line_code`), `PERIOD_REQUIRED`,
|
||||||
`INVALID_LINE_CODE`, `INVALID_LINE_PATCH`, `UNKNOWN_LINE`, `UNKNOWN_COLUMN`, `UNKNOWN_CELL`, `LINE_CODE_REQUIRED`.
|
`CHECKS_NOT_PASSED` (`detail.failures`); 422 `INVALID_LINE_CODE`, `INVALID_LINE_PATCH`, `UNKNOWN_LINE`,
|
||||||
|
`LINE_CODE_REQUIRED` (у всех четырёх — `detail.line_id`, `detail.line_code` первого неверного элемента, план 3
|
||||||
|
P3-24), `UNKNOWN_COLUMN`, `UNKNOWN_CELL`.
|
||||||
- Новых зависимостей npm нет; `vitest` остаётся `3.1.4`; `package-lock.json` в git не попадает.
|
- Новых зависимостей npm нет; `vitest` остаётся `3.1.4`; `package-lock.json` в git не попадает.
|
||||||
- Компоненты (`.tsx`) юнит-тестами не покрываются; каждая чистая функция плана — в `.ts` с `.test.ts` рядом.
|
- Компоненты (`.tsx`) юнит-тестами не покрываются; каждая чистая функция плана — в `.ts` с `.test.ts` рядом.
|
||||||
- Перед коммитом — `npm run format`; зелёным считается `make lint typecheck test build` (P6-18); перед PR — то же, вывод
|
- Перед коммитом — `npm run format`; зелёным считается `make lint typecheck test build` (P6-18); перед PR — то же, вывод
|
||||||
@ -142,7 +144,7 @@
|
|||||||
| `src/widgets/DocumentReview/IssuesPanel.tsx` | список предупреждений документа со ссылкой «Показать» |
|
| `src/widgets/DocumentReview/IssuesPanel.tsx` | список предупреждений документа со ссылкой «Показать» |
|
||||||
| `src/widgets/DocumentReview/headerFields.ts`, `StatementHeaderBlock.tsx` | шапка: наименование организации, `needs_review_fields`, подсказки из `header.source` |
|
| `src/widgets/DocumentReview/headerFields.ts`, `StatementHeaderBlock.tsx` | шапка: наименование организации, `needs_review_fields`, подсказки из `header.source` |
|
||||||
| `src/widgets/DocumentReview/statementDraft.ts` | черновик правок и сборка тела `PATCH` (заменяет `draftToPatch`) |
|
| `src/widgets/DocumentReview/statementDraft.ts` | черновик правок и сборка тела `PATCH` (заменяет `draftToPatch`) |
|
||||||
| `src/widgets/DocumentReview/codeSuggestions.ts`, `lineMenu.ts` | подсказка кода из справочника, пункты меню строки, `LINE_CODE_TAKEN` у поля |
|
| `src/widgets/DocumentReview/codeSuggestions.ts`, `lineMenu.ts` | подсказка кода из `edition_lines`, пункты меню строки, ошибка элемента `lines[]` у поля строки |
|
||||||
| `src/widgets/DocumentReview/editRules.ts` | когда у колонки поле даты и у ячейки кнопка подтверждения |
|
| `src/widgets/DocumentReview/editRules.ts` | когда у колонки поле даты и у ячейки кнопка подтверждения |
|
||||||
| `src/widgets/DocumentReview/CodeCell.tsx`, `LineMenu.tsx`, `ValueCell.tsx`, `ColumnHeader.tsx` | ячейки таблицы и заголовок колонки |
|
| `src/widgets/DocumentReview/CodeCell.tsx`, `LineMenu.tsx`, `ValueCell.tsx`, `ColumnHeader.tsx` | ячейки таблицы и заголовок колонки |
|
||||||
| `src/widgets/DocumentReview/StatementTable.tsx`, `StatementReview.tsx`, `ChecksPanel.tsx` | сборка экрана, переключатели, сохранение, переход к строке |
|
| `src/widgets/DocumentReview/StatementTable.tsx`, `StatementReview.tsx`, `ChecksPanel.tsx` | сборка экрана, переключатели, сохранение, переход к строке |
|
||||||
@ -156,7 +158,7 @@
|
|||||||
|
|
||||||
| Маркер | Решение | Обоснование | Цена ошибки |
|
| Маркер | Решение | Обоснование | Цена ошибки |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| P6-1 | Подсказка кода — из самого ответа `StatementOut`: все строки `ok` с кодом (из файла и достроенные шаблонные) дают пары «код → `reference_name` (иначе `line_name`)»; отдельного справочника не запрашиваем | шаблонные строки ядро достраивает по полному составу редакции, поэтому ответ уже содержит весь справочник редакции; эндпоинта справочника нет | у формы без даты (редакции нет) подсказка беднее — O-3 |
|
| P6-1 | Подсказка кода — `StatementOut.edition_lines` (справочник строк редакции формы, у формы без даты — всех редакций; план 3 P3-22), затем коды строк `ok` файла, которых в справочнике нет (имя — `reference_name` ?? `line_name`); отдельного запроса нет | справочник приходит с ответом формы | нет |
|
||||||
| P6-2 | Якорь строки `unreadable` / `missing` — строка `ok` из источника (`row_index` не `null`) с наибольшим `row_index` меньше своего; якорь `detail` — строка `ok` из источника с `row_index = parent_row_index`; нет якоря (в том числе `detail` с `parent_row_index = null` или указывающим не на `ok`) — в начало первого раздела (после ведущих заголовков разделов; у ОФР — в начало таблицы). Вложение встаёт сразу после строки-якоря; несколько вложений одного якоря — по `row_index` | спека `arm-web` «Раскладка», S-62 («строка `detail` без родителя на экране — в начале раздела»), P3-17 (тот же порядок вложений в ответе ядра) | нет |
|
| P6-2 | Якорь строки `unreadable` / `missing` — строка `ok` из источника (`row_index` не `null`) с наибольшим `row_index` меньше своего; якорь `detail` — строка `ok` из источника с `row_index = parent_row_index`; нет якоря (в том числе `detail` с `parent_row_index = null` или указывающим не на `ok`) — в начало первого раздела (после ведущих заголовков разделов; у ОФР — в начало таблицы). Вложение встаёт сразу после строки-якоря; несколько вложений одного якоря — по `row_index` | спека `arm-web` «Раскладка», S-62 («строка `detail` без родителя на экране — в начале раздела»), P3-17 (тот же порядок вложений в ответе ядра) | нет |
|
||||||
| P6-3 | Скрытие (пустые подстроки, расшифровки) применяется **после** раскладки, фильтром | иначе скрытый якорь сдвинул бы вложения к соседу | нет |
|
| P6-3 | Скрытие (пустые подстроки, расшифровки) применяется **после** раскладки, фильтром | иначе скрытый якорь сдвинул бы вложения к соседу | нет |
|
||||||
| P6-4 | Справочное имя (`reference_name`) — основное; файловое (`line_name`, после срезания приклеенных заголовков разделов) показывается вторым серым текстом, только если отличается после нормализации: нижний регистр, `ё` → `е`, оставлены только буквы и цифры | переносы OCR («задолжен-ность») не должны давать ложного «отличается» | лишнее или пропущенное второе имя — только показ |
|
| P6-4 | Справочное имя (`reference_name`) — основное; файловое (`line_name`, после срезания приклеенных заголовков разделов) показывается вторым серым текстом, только если отличается после нормализации: нижний регистр, `ё` → `е`, оставлены только буквы и цифры | переносы OCR («задолжен-ность») не должны давать ложного «отличается» | лишнее или пропущенное второе имя — только показ |
|
||||||
@ -164,42 +166,41 @@
|
|||||||
| P6-6 | Подтверждение ячейки — в черновике; доступно, только если у строки есть `id` и у значения есть `id` (у достроенных ячеек — нет, ядро ответит `UNKNOWN_CELL`); сумма в черновике той же ячейки отменяет её подтверждение | `PATCH`: в элементе `values` ровно одно из `amount` / `confirmed`; правка суммы и так снимает `needs_review` | нет |
|
| P6-6 | Подтверждение ячейки — в черновике; доступно, только если у строки есть `id` и у значения есть `id` (у достроенных ячеек — нет, ядро ответит `UNKNOWN_CELL`); сумма в черновике той же ячейки отменяет её подтверждение | `PATCH`: в элементе `values` ровно одно из `amount` / `confirmed`; правка суммы и так снимает `needs_review` | нет |
|
||||||
| P6-7 | Одно действие на строку в черновике (`code` / `detail` / `confirm`), новое заменяет прежнее; пустое поле кода и код, равный текущему, — не действие; у достроенных шаблонных строк (`id = null`) действий строки нет | 422 `INVALID_LINE_PATCH` при двух действиях; `lines[]` адресуется только `line_id` | нет |
|
| P6-7 | Одно действие на строку в черновике (`code` / `detail` / `confirm`), новое заменяет прежнее; пустое поле кода и код, равный текущему, — не действие; у достроенных шаблонных строк (`id = null`) действий строки нет | 422 `INVALID_LINE_PATCH` при двух действиях; `lines[]` адресуется только `line_id` | нет |
|
||||||
| P6-8 | Сумма в шаблонную строку по `line_code` X и назначение кода X другой строке в одном сохранении — ошибка черновика «Код X назначается строке, а в шаблонную строку X введены суммы — сохраните по очереди», запрос не уходит | ядро ответит 422 `UNKNOWN_CELL` (P3-10), а сообщение ядра не говорит, что делать | нет |
|
| P6-8 | Сумма в шаблонную строку по `line_code` X и назначение кода X другой строке в одном сохранении — ошибка черновика «Код X назначается строке, а в шаблонную строку X введены суммы — сохраните по очереди», запрос не уходит | ядро ответит 422 `UNKNOWN_CELL` (P3-10), а сообщение ядра не говорит, что делать | нет |
|
||||||
| P6-9 | 409 `LINE_CODE_TAKEN` показывается у полей кода черновика, чей код совпадает с кодом строки, созданной правкой (`origin = template`, `id` не `null`), у которой есть сумма; не нашли таких — текстом сервера над таблицей | в `detail` ответа нет кода и строки (O-2) | при ответе ядра с другой причиной красное поле не там — текст сервера показывается всё равно |
|
| P6-9 | Ошибка элемента `lines[]` (409 `LINE_CODE_TAKEN`, 422 `INVALID_LINE_CODE`, `INVALID_LINE_PATCH`, `UNKNOWN_LINE`, `LINE_CODE_REQUIRED`) показывается у поля кода строки `detail.line_id` (текст сервера в подсказке поля и `message.error`); строки с этим `id` на экране нет — текстом над таблицей | ядро отдаёт `detail.line_id` и `detail.line_code` (план 3 P3-24) | нет |
|
||||||
| P6-10 | Строка «неразобранная» для кнопки «Подтвердить данные» — `line_status ∈ {unreadable, missing}` и хотя бы у одного значения `amount !== null` или `string_value !== null` (ровно условие ядра для 409 `LINES_UNRESOLVED`) | кнопка и сервер считают одинаково | нет |
|
| P6-10 | Строка «неразобранная» для кнопки «Подтвердить данные» — `line_status ∈ {unreadable, missing}` и хотя бы у одного значения `amount !== null` или `string_value !== null` (ровно условие ядра для 409 `LINES_UNRESOLVED`) | кнопка и сервер считают одинаково | нет |
|
||||||
| P6-11 | Подтверждение даты отчёта — кнопка «Подтвердить дату» у поля из `needs_review_fields` (уходит `header.report_date` тем же значением); дата колонки — поле `ГГГГ-ММ-ДД` у заголовка колонки (как поле даты отчёта) с кнопкой «Подтвердить дату», если дата есть и у колонки `COLUMN_DATE_UNCERTAIN` / `COLUMN_WITHOUT_DATE` | перепечатывать ту же дату ради подтверждения неочевидно; формат ввода — как у существующего поля даты | нет |
|
| P6-11 | Подтверждение даты отчёта — кнопка «Подтвердить дату» у поля из `needs_review_fields` (уходит `header.report_date` тем же значением); дата колонки — поле `ГГГГ-ММ-ДД` у заголовка колонки (как поле даты отчёта) с кнопкой «Подтвердить дату», если дата есть и у колонки `COLUMN_DATE_UNCERTAIN` / `COLUMN_WITHOUT_DATE` | перепечатывать ту же дату ради подтверждения неочевидно; формат ввода — как у существующего поля даты | нет |
|
||||||
| P6-12 | Панель файлов: у строк документов файла с непустым `job.warnings` (и у строки файла без документов) — значок с числом предупреждений, красный при хотя бы одном `error`; клик открывает список: предупреждения файла (`message` и `locator`), `job.mapping_warnings` (как `info`) и `DocumentOut.issues` этого документа, загружаемые при открытии (`GET /documents/{id}`). Значка «есть предупреждения документа» без предупреждений файла нет — их видно на экране документа | `DocumentBrief` не несёт `issues` (O-4); N запросов на каждое открытие панели — дорого | документ с предупреждением листа ОСВ без предупреждений файла не помечен в панели |
|
| P6-12 | Панель файлов: у строки документа — значок с числом «предупреждения файла (`job.warnings`) + `issue_counts.error` + `issue_counts.info`» документа, красный при хотя бы одном `error` (в файле или `issue_counts.error > 0`); у строки файла без документов — только `job.warnings`; нуль — значка нет. Клик открывает список: предупреждения файла (`message` и `locator`), `job.mapping_warnings` (как `info`) и `DocumentOut.issues` документа, загружаемые при открытии (`GET /documents/{id}`) | `DocumentBrief.issue_counts` (план 3 P3-23) помечает документ без запроса на каждый; подробности — по клику | акцептованное нарушение тоже даёт значок — подробности в списке |
|
||||||
| P6-13 | `job.warnings` на клиенте нормализуется так же, как ядро: строка → `{code: "LEGACY_WARNING", severity: "info", message, locator: null}`, объект с `code`, `severity ∈ {error, info}`, `message` — как есть, прочее пропускается, не список → `[]` | экран не падает при ошибке порядка выкладки | нет |
|
| P6-13 | `job.warnings` на клиенте нормализуется так же, как ядро: строка → `{code: "LEGACY_WARNING", severity: "info", message, locator: null}`, объект с `code`, `severity ∈ {error, info}`, `message` — как есть, прочее пропускается, не список → `[]` | экран не падает при ошибке порядка выкладки | нет |
|
||||||
| P6-14 | Сценарий T11 — на локальном стенде; строки `unreadable` / `missing` / `detail` и записи `issues` всех видов подставляются перехватом `GET` и `PATCH …/statement` (`page.route`) из фикстуры плана, пока сервисы шлют 1.x; на реальных формах 1.x — регрессия | до шага 5 выкладки 2.0-данных на стенде нет | повторный прогон на `aep_3` после шага 5 — follow-up |
|
| P6-14 | Сценарий T11 — на локальном стенде; строки `unreadable` / `missing` / `detail` и записи `issues` всех видов подставляются перехватом `GET` и `PATCH …/statement` (`page.route`) из фикстуры плана, пока сервисы шлют 1.x; на реальных формах 1.x — регрессия | до шага 5 выкладки 2.0-данных на стенде нет | повторный прогон на `aep_3` после шага 5 — follow-up |
|
||||||
| P6-15 | Цвета: ячейка `needs_review` — `#fff7e6`, исправлено — `#e6f4ff`, строка `unreadable` / `missing` целиком — `#fff1f0`, строка `ok` с `needs_review` — фон ячеек наименования и кода `#fff7e6`; подтверждённая ячейка — маленькая серая галочка перед суммой; уровень `error` — красный значок `ExclamationCircleOutlined` `#cf1322`, `info` — синий `InfoCircleOutlined` `#1677ff` | палитра уже используется на экране и в панели файлов | только вид |
|
| P6-15 | Цвета: ячейка `needs_review` — `#fff7e6`, исправлено — `#e6f4ff`, строка `unreadable` / `missing` целиком — `#fff1f0`, строка `ok` с `needs_review` — фон ячеек наименования и кода `#fff7e6`; подтверждённая ячейка — маленькая серая галочка перед суммой; уровень `error` — красный значок `ExclamationCircleOutlined` `#cf1322`, `info` — синий `InfoCircleOutlined` `#1677ff` | палитра уже используется на экране и в панели файлов | только вид |
|
||||||
| P6-16 | Ячейка кода: `ok` — код; `unreadable` — серым `line_code_text` (пусто — «—»), подсказка «Код не распознан: «<текст>»»; `missing` — серым «—», подсказка «Кода в строке нет»; `detail` — пусто, подсказка «Расшифровка — в суммы формы не входит»; у `ok` в подсказке «Уверенность кода: N%» (если меньше 100 и код не правлен), «Код подтверждён», «Код назначен аналитиком» | спека: «в ячейке кода серым — сырой текст с подсказкой» | только вид |
|
| P6-16 | Ячейка кода: `ok` — код; `unreadable` — серым `line_code_text` (пусто — «—»), подсказка «Код не распознан: «<текст>»»; `missing` — серым «—», подсказка «Кода в строке нет»; `detail` — пусто, подсказка «Расшифровка — в суммы формы не входит»; у `ok` в подсказке «Уверенность кода: N%» (если меньше 100 и код не правлен), «Код подтверждён», «Код назначен аналитиком» | спека: «в ячейке кода серым — сырой текст с подсказкой» | только вид |
|
||||||
| P6-17 | `header.source.<поле>.confidence` читается как `number \| string \| null` и форматируется через `Number()` | ядро отдаёт `header_source` из JSONB как пришло (в контракте — число), прочие уверенности — строки Decimal (O-5) | нет |
|
| P6-17 | `header.source.<поле>.confidence` — `string \| null` (строка Decimal, как прочие уверенности API, план 3 P3-20), в подсказке — `Number()` и округление до целого | одно правило для всех уверенностей | нет |
|
||||||
| P6-18 | `node_modules` worktree — симлинк на установленный каталог с eslint, prettier и vitest 3.1.4; поэтому вместо `make check` (он начинается с `npm install` и поставил бы пакеты в чужой каталог) гоняется `make lint typecheck test build` — те же проверки без установки | память владельца: симлинк, как в прежних срезах | нет; в описании PR сказано, что install пропущен |
|
| P6-18 | `node_modules` worktree — симлинк на установленный каталог с eslint, prettier и vitest 3.1.4; поэтому вместо `make check` (он начинается с `npm install` и поставил бы пакеты в чужой каталог) гоняется `make lint typecheck test build` — те же проверки без установки | память владельца: симлинк, как в прежних срезах | нет; в описании PR сказано, что install пропущен |
|
||||||
| P6-19 | Предупреждения ОСВ-документа (`DocumentOut.issues`, `OSV_*`) — блок `IssuesPanel` над таблицей экрана ОСВ, все записи — у документа (строки ОСВ не адресуются `line_ids`) | спека: «предупреждения листа ОСВ … из `DocumentOut.issues[]`»; экран документа уже загружает `DocumentOut` | нет |
|
| P6-19 | Предупреждения ОСВ-документа (`DocumentOut.issues`, `OSV_*`) — блок `IssuesPanel` над таблицей экрана ОСВ, все записи — у документа (строки ОСВ не адресуются `line_ids`) | спека: «предупреждения листа ОСВ … из `DocumentOut.issues[]`»; экран документа уже загружает `DocumentOut` | нет |
|
||||||
|
|
||||||
## Чего не хватает в API ядра для экрана (`O-n`, план 3 не правился)
|
## Чего не хватает в API ядра для экрана (`O-n`)
|
||||||
|
|
||||||
- **O-1.** План 3, A8: в `LineOut` не перечислен `line_code_confidence`, хотя спека `arm-core` («Ответ `GET …/statement`
|
Все пункты закрыты сведением с планом 3 (18.10.2026, его P3-20…P3-24; спека `arm-core` и гайд §5.6.1 дополнены);
|
||||||
по v2.0») его требует. Экран показывает его в подсказке кода (P6-16). Без поля подсказка без уверенности; тип —
|
маркеры сохранены.
|
||||||
`string | null`.
|
|
||||||
- **O-2.** 409 `LINE_CODE_TAKEN` (A13) и 422 `INVALID_LINE_CODE` / `UNKNOWN_LINE` / `INVALID_LINE_PATCH` не несут в
|
- **O-1.** Закрыт: `LineOut.line_code_confidence` (строка Decimal) в A8 плана 3; тип — `string | null` (T1).
|
||||||
`detail` ни `line_id`, ни `line_code`. Экран вычисляет место сам (P6-9) или показывает текст над таблицей. Просьба к
|
- **O-2.** Закрыт: у 409 `LINE_CODE_TAKEN` и 422 `INVALID_LINE_CODE`, `UNKNOWN_LINE`, `INVALID_LINE_PATCH`,
|
||||||
ядру: `detail.line_id` и `detail.line_code` у этих кодов.
|
`LINE_CODE_REQUIRED` в `detail` есть `line_id` и `line_code` (P3-24); экран ставит ошибку у поля строки (P6-9,
|
||||||
- **O-3.** Нет эндпоинта справочника строк редакции (код → наименования). Подсказка кода строится из ответа (P6-1); у
|
`lineErrorTarget`, T7).
|
||||||
формы без даты отчёта (редакции нет, шаблонные строки не достраиваются) подсказка — только из строк файла. Кандидат:
|
- **O-3.** Закрыт: `StatementOut.edition_lines [{code, name}]` (P3-22), у формы без даты — коды всех редакций; подсказка
|
||||||
`GET /directories/statement-lines?document_type=&edition=`.
|
кода — из него (P6-1).
|
||||||
- **O-4.** `DocumentBrief` (в `FileOut.documents[]`) не несёт сводки `issues` — панель файлов не может пометить документ с
|
- **O-4.** Закрыт: `DocumentBrief.issue_counts {error, info}` (P3-23); панель помечает документ без запроса (P6-12,
|
||||||
предупреждениями без запроса на каждый документ (P6-12). Кандидат: `DocumentBrief.issues_summary {error: int, info: int}`.
|
`rowBadge`, T10).
|
||||||
- **O-5.** Тип `header.source.<поле>.confidence` не зафиксирован (A8: `dict[str, dict[str, Any]]` из JSONB — число;
|
- **O-5.** Закрыт: `header.source.<поле>.confidence` — строка Decimal (P3-20); P6-17.
|
||||||
остальные уверенности API — строки Decimal). Нужна одна строка в гайде §5.6.1.
|
- **O-6.** Закрыт: `StatementHeaderOut.okei` (P3-21); в блоке шапки поле не показывается (четыре поля T5), запись `issues`
|
||||||
- **O-6.** В `StatementHeaderOut` нет `okei`, хотя `headerField` контракта его содержит; запись `issues` с `field = "okei"`
|
с `field = "okei"` по-прежнему уходит в список документа (Review Focus 2).
|
||||||
экран покажет у документа. Не блокирует.
|
|
||||||
|
|
||||||
## Открытые вопросы владельцу
|
## Открытые вопросы владельцу
|
||||||
|
|
||||||
- **В-1.** Приёмка экрана на шаге 4 выкладки — по перехвату с фикстурой (P6-14) и регрессии на формах 1.x; проверка на
|
- **В-1.** Приёмка экрана на шаге 4 выкладки — по перехвату с фикстурой (P6-14) и регрессии на формах 1.x; проверка на
|
||||||
реальных 2.0-данных (`aep_3`, РБ 1 кв. 2025) — после перехода сервисов (шаг 5), отдельной задачей. Устраивает?
|
реальных 2.0-данных (`aep_3`, РБ 1 кв. 2025) — после перехода сервисов (шаг 5), отдельной задачей. Устраивает?
|
||||||
- **В-2.** Панель файлов не помечает документы, у которых есть только предупреждения документа (O-4, P6-12). Достаточно до
|
- **В-2.** Снят 18.10.2026: `DocumentBrief.issue_counts` (план 3 P3-23) — панель помечает и документы только с
|
||||||
доработки `DocumentBrief`?
|
предупреждениями документа (P6-12).
|
||||||
- **В-3.** Подтверждённая ячейка помечается маленькой галочкой (P6-15) — в спеке и макете вида нет. Устраивает?
|
- **В-3.** Подтверждённая ячейка помечается маленькой галочкой (P6-15) — в спеке и макете вида нет. Устраивает?
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -292,7 +293,10 @@ export interface IssueOut {
|
|||||||
line_ids: string[]; column_id: string | null; column_index: number | null; field: string | null;
|
line_ids: string[]; column_id: string | null; column_index: number | null; field: string | null;
|
||||||
source: 'service' | 'core'; relation: string | null; codes: string[]; expected: string | null; actual: string | null;
|
source: 'service' | 'core'; relation: string | null; codes: string[]; expected: string | null; actual: string | null;
|
||||||
}
|
}
|
||||||
export interface HeaderSourceOut { text: string | null; confidence: number | string | null }
|
export interface HeaderSourceOut { text: string | null; confidence: string | null }
|
||||||
|
export interface EditionLineOut { code: string; name: string }
|
||||||
|
export interface IssueCountsOut { error: number; info: number }
|
||||||
|
export interface LineErrorDetail { code: string; message: string; line_id: string; line_code: string | null }
|
||||||
export interface UnresolvedLineOut { line_id: string; row_index: number | null; line_code_text: string | null }
|
export interface UnresolvedLineOut { line_id: string; row_index: number | null; line_code_text: string | null }
|
||||||
export type CellTarget = { line_id: string } | { line_code: string };
|
export type CellTarget = { line_id: string } | { line_code: string };
|
||||||
export type CellPatch = (CellTarget & { column_id: string; amount: string | null })
|
export type CellPatch = (CellTarget & { column_id: string; amount: string | null })
|
||||||
@ -308,13 +312,15 @@ export interface StatementPatch {
|
|||||||
|
|
||||||
Изменения существующих: `JobBrief.warnings: FileWarningOut[]` (`mapping_warnings` — `string[]`); `DocumentOut.issues:
|
Изменения существующих: `JobBrief.warnings: FileWarningOut[]` (`mapping_warnings` — `string[]`); `DocumentOut.issues:
|
||||||
IssueOut[]` (`warnings: string[]` остаётся); `StatementHeaderOut` + `needs_review_fields: string[]`, `source:
|
IssueOut[]` (`warnings: string[]` остаётся); `StatementHeaderOut` + `needs_review_fields: string[]`, `source:
|
||||||
Partial<Record<string, HeaderSourceOut>>`, `organization_name_modified: boolean`; `ColumnOut` + `period_kind: PeriodKind`,
|
Partial<Record<string, HeaderSourceOut>>`, `organization_name_modified: boolean`, `okei: string | null`; `ColumnOut` +
|
||||||
|
`period_kind: PeriodKind`,
|
||||||
`label_confidence: string | null`; `LineOut` + `row_index: number | null`, `source_ref: string | null`, `line_status:
|
`label_confidence: string | null`; `LineOut` + `row_index: number | null`, `source_ref: string | null`, `line_status:
|
||||||
LineStatus`, `line_code_text: string | null`, `line_code_confidence: string | null` (O-1), `reference_name: string | null`,
|
LineStatus`, `line_code_text: string | null`, `line_code_confidence: string | null`, `reference_name: string | null`,
|
||||||
`parent_row_index: number | null`, `needs_review: boolean`, `is_confirmed: boolean`, `line_code_modified: boolean`;
|
`parent_row_index: number | null`, `needs_review: boolean`, `is_confirmed: boolean`, `line_code_modified: boolean`;
|
||||||
`ValueOut` + `text: string | null`, `needs_review: boolean`, `is_confirmed: boolean`; `FailedCheckOut` + `codes:
|
`ValueOut` + `text: string | null`, `needs_review: boolean`, `is_confirmed: boolean`; `FailedCheckOut` + `codes:
|
||||||
string[]`, `line_ids: string[]`; `StatementOut.document.form_variant: 'full' | 'simplified' | null`;
|
string[]`, `line_ids: string[]`; `StatementOut.document.form_variant: 'full' | 'simplified' | null`;
|
||||||
`StatementOut.issues: IssueOut[]`.
|
`StatementOut.issues: IssueOut[]`, `StatementOut.edition_lines: EditionLineOut[]`; `DocumentBrief.issue_counts:
|
||||||
|
IssueCountsOut` (и `DocumentOut`, который его расширяет).
|
||||||
- Produces (`statementGrid.ts`):
|
- Produces (`statementGrid.ts`):
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
@ -341,8 +347,8 @@ export function cellFlags(value: ValueOut | undefined): { attention: boolean; mo
|
|||||||
документ `BALANCE`, `NEEDS_CHECK`, 2025 `Q3`, `reporting_date "2025-09-30"`, `form_variant "full"`, `edition "fsbu4"`;
|
документ `BALANCE`, `NEEDS_CHECK`, 2025 `Q3`, `reporting_date "2025-09-30"`, `form_variant "full"`, `edition "fsbu4"`;
|
||||||
шапка: ИНН `7700000000` (уверенность `100`), дата отчёта `2025-09-30` (`original_value "30 сентября 2025 г."`,
|
шапка: ИНН `7700000000` (уверенность `100`), дата отчёта `2025-09-30` (`original_value "30 сентября 2025 г."`,
|
||||||
уверенность `67`), единицы «тыс. руб.», `organization_name "ООО Ромашка"`, `needs_review_fields ["report_date"]`,
|
уверенность `67`), единицы «тыс. руб.», `organization_name "ООО Ромашка"`, `needs_review_fields ["report_date"]`,
|
||||||
`source {organization_name: {text: "ООО «Ромашкa»", confidence: 67}, report_date: {text: "30 сентября 2025 г.",
|
`okei "384"`, `source {organization_name: {text: "ООО «Ромашкa»", confidence: "67.00"}, report_date: {text: "30
|
||||||
confidence: 67}}`; колонки `c1` (`column_index 2`, «На 30 сентября 2025 г.», `2025-09-30`, `absolute`) и `c2`
|
сентября 2025 г.", confidence: "67.00"}}`; колонки `c1` (`column_index 2`, «На 30 сентября 2025 г.», `2025-09-30`, `absolute`) и `c2`
|
||||||
(`column_index 3`, `label null`, `period_date null`, `none`); строки:
|
(`column_index 3`, `label null`, `period_date null`, `none`); строки:
|
||||||
|
|
||||||
| id | `row_index` | статус | код / `line_code_text` | наименование (`reference_name`) | `parent_row_index` | особенности (колонка `c1`) |
|
| id | `row_index` | статус | код / `line_code_text` | наименование (`reference_name`) | `parent_row_index` | особенности (колонка `c1`) |
|
||||||
@ -370,6 +376,9 @@ export function cellFlags(value: ValueOut | undefined): { attention: boolean; mo
|
|||||||
relation `RELATION_FAILED` error, `line_ids [l-1200, l-1210, l-1230, l-1240]`, `column_id c1`, `relation "1200 = 1210 + 1220
|
relation `RELATION_FAILED` error, `line_ids [l-1200, l-1210, l-1230, l-1240]`, `column_id c1`, `relation "1200 = 1210 + 1220
|
||||||
+ 1230 + 1240 + 1250 + 1260"`, `codes [...]`, `expected "155"`, `actual "200"`; `i7` warning `NAME_MISMATCH` info, source
|
+ 1230 + 1240 + 1250 + 1260"`, `codes [...]`, `expected "155"`, `actual "200"`; `i7` warning `NAME_MISMATCH` info, source
|
||||||
`core`, `line_ids [l-1230]`. `checks.failed` — одно нарушение с теми же `codes`, `line_ids`, `column_index 2`.
|
`core`, `line_ids [l-1230]`. `checks.failed` — одно нарушение с теми же `codes`, `line_ids`, `column_index 2`.
|
||||||
|
`edition_lines` — коды ББ `fsbu4` по одному в порядке бланка с первыми именами (в том числе `{code: "1250", name:
|
||||||
|
"Денежные средства и денежные эквиваленты"}`, `{code: "1370", name: "Нераспределенная прибыль (непокрытый убыток)"}`,
|
||||||
|
`{code: "1170", name: "Финансовые вложения"}`; кода `1120` нет).
|
||||||
|
|
||||||
- [ ] **Step 1: Write the failing tests** (`statementGrid.test.ts`):
|
- [ ] **Step 1: Write the failing tests** (`statementGrid.test.ts`):
|
||||||
- `buildStatementGrid переносит поля v2` — на фикстуре строка `l-u7`: `lineStatus 'unreadable'`, `rowIndex 7`,
|
- `buildStatementGrid переносит поля v2` — на фикстуре строка `l-u7`: `lineStatus 'unreadable'`, `rowIndex 7`,
|
||||||
@ -666,15 +675,18 @@ export function buildStatementPatch(draft: StatementDraft, ctx: { rows: GridRow[
|
|||||||
- Modify: `CodeCell.tsx`, `StatementTable.tsx`, `StatementReview.tsx`
|
- Modify: `CodeCell.tsx`, `StatementTable.tsx`, `StatementReview.tsx`
|
||||||
|
|
||||||
**Interfaces:**
|
**Interfaces:**
|
||||||
- Consumes: `GridRow` (T1), `StatementDraft`, `LineAction` (T6).
|
- Consumes: `GridRow`, `EditionLineOut`, `LineErrorDetail` (T1), `StatementDraft`, `LineAction` (T6).
|
||||||
- Produces:
|
- Produces:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// codeSuggestions.ts
|
// codeSuggestions.ts
|
||||||
export type CodeOption = { code: string; name: string };
|
export type CodeOption = { code: string; name: string };
|
||||||
export function codeOptions(rows: GridRow[]): CodeOption[]; // P6-1: строки ok с кодом, name = referenceName ?? name ?? '', по коду, без повторов
|
export function codeOptions(editionLines: EditionLineOut[], rows: GridRow[]): CodeOption[];
|
||||||
|
// P6-1: сначала edition_lines по порядку, затем коды строк ok файла вне справочника (name = referenceName ?? name ?? ''), без повторов
|
||||||
export function filterCodeOptions(options: CodeOption[], query: string, limit?: number /* 20 */): CodeOption[];
|
export function filterCodeOptions(options: CodeOption[], query: string, limit?: number /* 20 */): CodeOption[];
|
||||||
export function codeTakenKeys(draft: StatementDraft, rows: GridRow[]): string[]; // P6-9
|
export function lineErrorTarget(error: unknown): { lineId: string; lineCode: string | null } | null;
|
||||||
|
// P6-9: detail.line_id / detail.line_code ошибки элемента lines[] (409 LINE_CODE_TAKEN, 422 INVALID_LINE_CODE,
|
||||||
|
// INVALID_LINE_PATCH, UNKNOWN_LINE, LINE_CODE_REQUIRED); иная ошибка или нет line_id — null
|
||||||
// lineMenu.ts
|
// lineMenu.ts
|
||||||
export type LineMenuKey = 'mark_detail' | 'assign_code' | 'change_code' | 'confirm_code' | 'unconfirm_code' | 'reset';
|
export type LineMenuKey = 'mark_detail' | 'assign_code' | 'change_code' | 'confirm_code' | 'unconfirm_code' | 'reset';
|
||||||
export function lineMenuItems(row: GridRow, action: LineAction | undefined): { key: LineMenuKey; label: string }[];
|
export function lineMenuItems(row: GridRow, action: LineAction | undefined): { key: LineMenuKey; label: string }[];
|
||||||
@ -690,8 +702,10 @@ export function showsCodeInput(row: GridRow, action: LineAction | undefined): bo
|
|||||||
любой строки с действием `code`.
|
любой строки с действием `code`.
|
||||||
|
|
||||||
- [ ] **Step 1: Write the failing tests:**
|
- [ ] **Step 1: Write the failing tests:**
|
||||||
- `codeOptions` (фикстура) — содержит `{code: '1250', name: 'Денежные средства и денежные эквиваленты'}` (шаблонная) и
|
- `codeOptions` (фикстура) — первые элементы — `edition_lines` по порядку; `{code: '1250', name: 'Денежные средства и
|
||||||
`{code: '1370', name: 'Нераспределенная прибыль'}` один раз; нет строк `unreadable` / `detail`;
|
денежные эквиваленты'}` и `1370` — по одному разу; код строки `ok` файла вне справочника (добавить в тест строку
|
||||||
|
`ok` 1231) — в конце, с её именем; у формы с `edition_lines: []` — только коды строк `ok`; нет строк `unreadable` /
|
||||||
|
`detail`;
|
||||||
- `filterCodeOptions` — `'12'` → коды на `12…`; `'денеж'` → 1250; `'ДЕНЁЖ'` → 1250 (`ё` = `е`, регистр не важен); `''` →
|
- `filterCodeOptions` — `'12'` → коды на `12…`; `'денеж'` → 1250; `'ДЕНЁЖ'` → 1250 (`ё` = `е`, регистр не важен); `''` →
|
||||||
первые 20;
|
первые 20;
|
||||||
- `lineMenuItems` — `l-u7` → `['mark_detail']`; `l-d2` → `['assign_code']`; `l-1230` (`needsReview`) → `['mark_detail',
|
- `lineMenuItems` — `l-u7` → `['mark_detail']`; `l-d2` → `['assign_code']`; `l-1230` (`needsReview`) → `['mark_detail',
|
||||||
@ -699,16 +713,17 @@ export function showsCodeInput(row: GridRow, action: LineAction | undefined): bo
|
|||||||
действии — последним `reset`; шаблонная 1250 → `[]`; подписи дословно;
|
действии — последним `reset`; шаблонная 1250 → `[]`; подписи дословно;
|
||||||
- `applyLineMenu` — `confirm_code` → `{kind: 'confirm', confirmed: true}`; `reset` убирает ключ; новое действие заменяет
|
- `applyLineMenu` — `confirm_code` → `{kind: 'confirm', confirmed: true}`; `reset` убирает ключ; новое действие заменяет
|
||||||
прежнее;
|
прежнее;
|
||||||
- `codeTakenKeys` — `{l-u7: code '1170'}` → `['l-u7']` (`l-t1170` создана правкой, сумма 3); `{l-u7: code '1250'}` → `[]`
|
- `lineErrorTarget` — `ApiError` 409 `{code: 'LINE_CODE_TAKEN', message, line_id: 'l-u7', line_code: '1170'}` →
|
||||||
(шаблонная 1250 пуста).
|
`{lineId: 'l-u7', lineCode: '1170'}`; 422 `INVALID_LINE_PATCH` с `line_code: null` → `{lineId, lineCode: null}`; 409
|
||||||
|
`LINES_UNRESOLVED` → `null`; 422 массивом (pydantic) → `null`.
|
||||||
- [ ] **Step 2:** `npx vitest run src/widgets/DocumentReview/codeSuggestions.test.ts src/widgets/DocumentReview/lineMenu.test.ts` — FAIL.
|
- [ ] **Step 2:** `npx vitest run src/widgets/DocumentReview/codeSuggestions.test.ts src/widgets/DocumentReview/lineMenu.test.ts` — FAIL.
|
||||||
- [ ] **Step 3: Implement**; `CodeCell` в режиме правки при `showsCodeInput` — `AutoComplete` (ширина колонки кода в
|
- [ ] **Step 3: Implement**; `CodeCell` в режиме правки при `showsCodeInput` — `AutoComplete` (ширина колонки кода в
|
||||||
режиме правки — 160) с опциями «<код> — <имя>», значение — код; ошибка формата или `codeTakenKeys` — `status='error'`
|
режиме правки — 160) с опциями «<код> — <имя>», значение — код; ошибка формата или строка `lineErrorTarget` ответа — `status='error'`
|
||||||
с подсказкой; у строки с действием `detail` — серый тег «→ расшифровка», с `confirm` — «→ код подтверждён» /
|
с подсказкой; у строки с действием `detail` — серый тег «→ расшифровка», с `confirm` — «→ код подтверждён» /
|
||||||
«→ подтверждение снято». `LineMenu` — кнопка `MoreOutlined` в ячейке наименования (`Dropdown`, `trigger click`),
|
«→ подтверждение снято». `LineMenu` — кнопка `MoreOutlined` в ячейке наименования (`Dropdown`, `trigger click`),
|
||||||
только в режиме правки. Ответ 409 `LINE_CODE_TAKEN` на сохранение: `codeTakenKeys` не пуст — красные поля и
|
только в режиме правки. Ответ на сохранение с ошибкой элемента `lines[]` (409 `LINE_CODE_TAKEN`, 422 коды строк из
|
||||||
`message.error` с текстом сервера; пуст — тот же текст над таблицей (P6-9). Ответ 422 с кодами из Global Constraints —
|
Global Constraints): `lineErrorTarget` — красное поле кода этой строки с текстом сервера и `message.error`; строки на
|
||||||
`message.error(e.message)`, черновик сохраняется.
|
экране нет — тот же текст над таблицей (P6-9). Прочие 422 — `message.error(e.message)`; черновик сохраняется.
|
||||||
- [ ] **Step 4:** `make lint typecheck test build` — PASS; на перехвате фикстуры: ввести 1250 у «ИЧ,250» → перехваченное
|
- [ ] **Step 4:** `make lint typecheck test build` — PASS; на перехвате фикстуры: ввести 1250 у «ИЧ,250» → перехваченное
|
||||||
тело `PATCH` содержит `lines: [{line_id: 'l-u7', line_code: '1250'}]` и только его.
|
тело `PATCH` содержит `lines: [{line_id: 'l-u7', line_code: '1250'}]` и только его.
|
||||||
- [ ] **Step 5: Commit** `feat(statement): правка строк — код с подсказкой из справочника, меню строки, LINE_CODE_TAKEN (#<issue>)`.
|
- [ ] **Step 5: Commit** `feat(statement): правка строк — код с подсказкой из справочника, меню строки, LINE_CODE_TAKEN (#<issue>)`.
|
||||||
@ -802,7 +817,10 @@ export function confirmErrorInfo(e: unknown): { code: string | undefined; messag
|
|||||||
export function toFileWarnings(value: unknown): FileWarningOut[]; // P6-13
|
export function toFileWarnings(value: unknown): FileWarningOut[]; // P6-13
|
||||||
export function warningsLevel(list: readonly { severity: Severity }[]): Severity | null;
|
export function warningsLevel(list: readonly { severity: Severity }[]): Severity | null;
|
||||||
export const warningText = (w: FileWarningOut): string => (w.locator ? `${w.message} — ${w.locator}` : w.message);
|
export const warningText = (w: FileWarningOut): string => (w.locator ? `${w.message} — ${w.locator}` : w.message);
|
||||||
// documentRows.ts: DocumentRow + fileWarnings: FileWarningOut[]; mappingWarnings: string[]
|
// documentRows.ts: DocumentRow + fileWarnings: FileWarningOut[]; mappingWarnings: string[]; issueCounts: IssueCountsOut
|
||||||
|
export function rowBadge(row: DocumentRow): { count: number; level: Severity } | null;
|
||||||
|
// P6-12: count = fileWarnings.length + issueCounts.error + issueCounts.info; level 'error', если есть error в файле
|
||||||
|
// или issueCounts.error > 0; count 0 — null
|
||||||
```
|
```
|
||||||
|
|
||||||
`IssuesPanel` получает режим `mode: 'statement' | 'document'`: в `document` все записи — пункты без ссылок (P6-19).
|
`IssuesPanel` получает режим `mode: 'statement' | 'document'`: в `document` все записи — пункты без ссылок (P6-19).
|
||||||
@ -817,9 +835,12 @@ export const warningText = (w: FileWarningOut): string => (w.locator ? `${w.mess
|
|||||||
- `warningText` — `'m — file:x_ofr.json'`; без `locator` — `'m'`;
|
- `warningText` — `'m — file:x_ofr.json'`; без `locator` — `'m'`;
|
||||||
- `buildDocumentRows` — файл с двумя документами и `job.warnings` из одного `JSON_FAILED` → у обеих строк
|
- `buildDocumentRows` — файл с двумя документами и `job.warnings` из одного `JSON_FAILED` → у обеих строк
|
||||||
`fileWarnings` длины 1; файл `ERROR` без документов — у строки файла тоже; `job null` → `[]`; `mapping_warnings`
|
`fileWarnings` длины 1; файл `ERROR` без документов — у строки файла тоже; `job null` → `[]`; `mapping_warnings`
|
||||||
переносятся как есть.
|
переносятся как есть; `issue_counts` документа → `issueCounts` (строка файла без документов — `{error: 0, info: 0}`);
|
||||||
|
- `rowBadge` — документ без предупреждений файла с `issue_counts {error: 0, info: 2}` → `{count: 2, level: 'info'}`;
|
||||||
|
`JSON_FAILED` в файле и `{error: 0, info: 1}` → `{count: 2, level: 'error'}`; `{error: 1, info: 0}` без файла →
|
||||||
|
`level 'error'`; всё по нулям → `null`.
|
||||||
- [ ] **Step 2:** `npx vitest run src/widgets/FilesDrawer/fileWarnings.test.ts src/widgets/FilesDrawer/documentRows.test.ts` — FAIL.
|
- [ ] **Step 2:** `npx vitest run src/widgets/FilesDrawer/fileWarnings.test.ts src/widgets/FilesDrawer/documentRows.test.ts` — FAIL.
|
||||||
- [ ] **Step 3: Implement**; `FilesList` — в колонке «Статус» под плашкой значок с числом (`warningsLevel` → цвет P6-15),
|
- [ ] **Step 3: Implement**; `FilesList` — в колонке «Статус» под плашкой значок с числом (`rowBadge` → цвет P6-15),
|
||||||
клик (`stopPropagation`, строка-ссылка не срабатывает) открывает `Popover` `FileWarningsPopover`: «Предупреждения
|
клик (`stopPropagation`, строка-ссылка не срабатывает) открывает `Popover` `FileWarningsPopover`: «Предупреждения
|
||||||
файла» (тег уровня + `warningText`), «Предупреждения обработки» (`mappingWarnings`, `info`), «Предупреждения документа»
|
файла» (тег уровня + `warningText`), «Предупреждения обработки» (`mappingWarnings`, `info`), «Предупреждения документа»
|
||||||
— при открытии `getDocument(documentId)` → `issues` (загрузка — `Spin`, ошибка — «Не удалось загрузить», без
|
— при открытии `getDocument(documentId)` → `issues` (загрузка — `Spin`, ошибка — «Не удалось загрузить», без
|
||||||
@ -863,8 +884,9 @@ await page.route('**/api/v1/documents/*/statement', async (route) => {
|
|||||||
«Назначить код» (тело `PATCH` — `lines: [{line_id: 'l-u7', line_code: '1250'}]`); «Подтверждение заблокировано»
|
«Назначить код» (тело `PATCH` — `lines: [{line_id: 'l-u7', line_code: '1250'}]`); «Подтверждение заблокировано»
|
||||||
(подсказка «Разберите строки без кода: 2», клик ведёт к первой); подтверждение ячейки, дата колонки, организация,
|
(подсказка «Разберите строки без кода: 2», клик ведёт к первой); подтверждение ячейки, дата колонки, организация,
|
||||||
подтверждение даты — одно тело. Перехват `POST …/confirm` с 409 `LINES_UNRESOLVED` и `DUPLICATE_FORM`, `PATCH` с 409
|
подтверждение даты — одно тело. Перехват `POST …/confirm` с 409 `LINES_UNRESOLVED` и `DUPLICATE_FORM`, `PATCH` с 409
|
||||||
`LINE_CODE_TAKEN` (код 1170) — тексты и места по T7, T9. Перехват `GET /legal-entities/*/files` с `job.warnings`
|
`LINE_CODE_TAKEN` (`detail {line_id: 'l-u7', line_code: '1170'}`) — тексты и места по T7, T9. Перехват
|
||||||
(`JSON_FAILED` `error`, `locator 'file:x_ofr.json'`) — сценарий «Потерянный ОФР в карточке».
|
`GET /legal-entities/*/files` с `job.warnings` (`JSON_FAILED` `error`, `locator 'file:x_ofr.json'`) и
|
||||||
|
`documents[].issue_counts` — сценарий «Потерянный ОФР в карточке», значок у документа без предупреждений файла.
|
||||||
- [ ] **Step 3:** итог сверки — в ledger и в описание PR: что сверено (экраны 41, 41-02, 39), что отличается и почему
|
- [ ] **Step 3:** итог сверки — в ledger и в описание PR: что сверено (экраны 41, 41-02, 39), что отличается и почему
|
||||||
(новые элементы, которых нет в макете: поле кода, меню строки, кнопки подтверждения, значки уровней).
|
(новые элементы, которых нет в макете: поле кода, меню строки, кнопки подтверждения, значки уровней).
|
||||||
- [ ] **Step 4:** README и CLAUDE.md arm-web; `npm run format`; `make lint typecheck test build` — PASS.
|
- [ ] **Step 4:** README и CLAUDE.md arm-web; `npm run format`; `make lint typecheck test build` — PASS.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user