diff --git a/README.md b/README.md index 1bd018f..3ecc8b1 100644 --- a/README.md +++ b/README.md @@ -569,7 +569,7 @@ S3 (storage); без S3 — предупреждение в логе, цикл `{failed, soft_failed, cross_form, accepted}` (нарушение — `{column_index, relation, expected, actual}`, у межформенной проверки `column_index = -1`). Не форма (ОСВ, расшифровка, ББ/ОФР без данных формы — созданные до Среза 3b) — 409 `DOCUMENT_NOT_STATEMENT`. Подтверждённая форма читается. Форма достраивается по справочнику строк редакции (`api/rules/statement_lines.yaml`): недостающие строки (`id = null`, `origin = template`) и ячейки (`id = null`); в БД не пишется. -- **`PATCH /documents/{id}/statement`** — `{header?: {inn?, report_date?, units?}, values?: [{line_id, column_id, amount}]}` +- **`PATCH /documents/{id}/statement`** — `{header?: {inn?, report_date?, units?}, values?: [{line_id | line_code, column_id, amount}]}` (до 5000 ячеек; `amount: null` очищает ячейку; не более двух знаков; `units` — непустая строка после обрезки пробелов до 50 символов, пробельная строка — 422, `null` — «не менять»; `inn: null` — 422 `INVALID_INN`, ИНН не очищается). Правится только неподтверждённая форма (`RECOGNIZED`/`NEEDS_CHECK`): `CONFIRMED` — 409 `DOCUMENT_READONLY` (исправление — новым файлом), заменённый файл — @@ -856,7 +856,7 @@ email без учёта регистра проверяет только сер | `FILE_CONTENT_NOT_FOUND` | 404 | `GET /files/{id}/content`: файл есть, объекта нет в S3 (истёк или пропал) | | `DOCUMENT_NOT_STATEMENT` | 409 | `…/statement`: документ — не форма ББ/ОФР (ОСВ, расшифровка, ББ/ОФР без данных формы — созданные до Среза 3b) | | `DOCUMENT_READONLY` | 409 | правка/акцепт формы: форма уже `CONFIRMED` (исправление — новым файлом) | -| UNKNOWN_CELL | 422 | PATCH …/statement: line_id/column_id не этой формы; line_code уже есть в форме (передайте line_id), нет в справочнике редакции или редакция не определена | +| `UNKNOWN_CELL` | `422` | `PATCH …/statement`: `line_id`/`column_id` не этой формы; `line_code` уже есть в форме (передайте `line_id`), нет в справочнике редакции или редакция не определена | | `DUPLICATE_CELL` | 422 | `PATCH …/statement`: одна ячейка указана в запросе дважды | | `NOTHING_TO_ACCEPT` | 409 | акцепт: непройденных жёстких проверок нет (в том числе уже акцептованы) | | `PERIOD_REQUIRED` | 409 | подтверждение формы: период не определён — поправьте дату отчёта | diff --git a/openspec/changes/statement-template-lines/design.md b/openspec/changes/statement-template-lines/design.md index c90cfd2..746d14a 100644 --- a/openspec/changes/statement-template-lines/design.md +++ b/openspec/changes/statement-template-lines/design.md @@ -27,8 +27,8 @@ ## Decisions ### D-1. Достраивать в ответе, а не в БД (подход B, решение владельца 09.10.2026) -БД хранит только пришедшее из источника; достройка — чистая функция `domain/statement_lines.complete_form` поверх -прочитанной формы в `build_out`. Альтернатива «дописать строки при маппинге» отклонена: нужна data-миграция для уже +БД хранит только пришедшее из источника; достройка — чистая функция `_lines_out` в `schemas/statements.py` (R-9) поверх +прочитанной формы в `build_out`; справочник и выбор строк по редакции — `domain/statement_lines.py`. Альтернатива «дописать строки при маппинге» отклонена: нужна data-миграция для уже загруженных документов, в БД появляются строки, которых не было в первичке, и проверки §7 начали бы видеть пустые итоги (пустая 1700 при непустых 1300–1500 — жёсткое нарушение), то есть изменился бы статус документов. @@ -36,17 +36,15 @@ ```yaml editions: - id: 66n - valid_until: 2024-12-31 forms: BALANCE: [{code: "1110", name: "Нематериальные активы"}, ...] # порядок формы INCOME: [...] - id: fsbu4 - valid_from: 2025-01-01 forms: {BALANCE: [...], INCOME: [...]} ``` Список, а не словарь — порядок строк формы сохраняется (пригодится фронту и будущему порядку в ответе; сейчас ответ -сортируется по коду, как раньше). Загрузка — один раз при импорте модуля (как `statement_checks.yaml`), валидация -pydantic: коды — четыре цифры, без повторов внутри формы, обе формы в обеих редакциях. Редакция выбирается существующим +сортируется по коду, как раньше). Загрузка — лениво, один раз на процесс (`lru_cache` у `load_line_catalog`), проверки +вручную в `load_line_catalog`/`_form_lines` (ошибка формата — `ValueError`): коды — четыре цифры, без повторов внутри формы, обе формы в обеих редакциях. Границы редакций в yaml не хранятся: редакция выбирается существующим `edition_for` — новой логики выбора нет. Состав (решение владельца 09.10.2026 — из шаблонов `../fixtures/statements-xlsx/templates/`): @@ -149,3 +147,5 @@ pydantic: коды — четыре цифры, без повторов внут | R-9 | 09.10.2026 | Достройка формы реализована функцией `_lines_out` в `schemas/statements.py`, а не `domain/statement_lines.complete_form` из D-3 | План конкретнее, поведение то же | Рефакторинг в domain позже | | R-10 | 09.10.2026 | Ключ достроенной строки на фронте `code-`, а не `code:` из D-6 | ':' разделяет rowKey и columnId в cellKey | Нет | | R-11 | 09.10.2026 | Адресация ячеек PATCH вынесена из `_apply_cells` в `_resolve_cells` (отклонение от кода плана ради ruff PLR0912/PLW2901); поведение и порядок проверок сохранены | Линтер | Нет | +| R-12 | 09.10.2026 | Правка фронта шаблонных строк перенесена и во встроенный `arm-core/web` в этой же ветке (те же файлы, что в arm-web) | Иначе после слияния встроенный фронт отправляет `line_id` `"null"` и дублирует ключи строк | Дифф PR вырос; если `arm-core/web` не поддерживается — откатить | +| R-13 | 09.10.2026 | M-2, M-3, M-4, M-5, M-6 финального ревью отложены в follow-up | Не блокируют слияние | M-2: форма без сумм может стать `RECOGNIZED` после ручного создания и очистки строки | diff --git a/openspec/changes/statement-template-lines/proposal.md b/openspec/changes/statement-template-lines/proposal.md index 9ba7ce7..dbb0ea3 100644 --- a/openspec/changes/statement-template-lines/proposal.md +++ b/openspec/changes/statement-template-lines/proposal.md @@ -57,7 +57,7 @@ DBML и контракты обмена не меняются, миграций ## Impact -- Код: `domain/statement_lines.py` (новый: загрузка справочника, достройка формы — чистые функции), +- Код: `domain/statement_lines.py` (новый: загрузка справочника по редакциям), достройка формы — `_lines_out` в `schemas/statements.py`, `api/rules/statement_lines.yaml` (новый), `schemas/statements.py` (`LineOut.id`/`ValueOut.id` nullable, `LineOut.origin`, `CellPatch` с `line_id | line_code`), `services/statements.py` (`build_out`, `_apply_cells`), `repositories/statements.py` (создание строки/ячейки, исключение пустых шаблонных строк в `statement_amounts`).