seed/dev/company_groups.yaml: ГК «Русский Бисквит» ровно как в fixtures/directories/ecp-export-russkiy-biskvit.xlsx (20 ЮЛ/ИП, crm_id, филиал «Санкт-Петербургский РФ», ГСК из РБ и Счастливочной), ГК Унагранде/НПЗ/Межениновская по ИНН из форм ББ/ОФР; алиасы под имена контрагентов и шапок ОСВ («Юг-Финанс / ПЕКАРНЯ СЧАСТЛИВОЧНАЯ», ...), чтобы документы из fixtures ложились на «своих» ЮЛ и резолвились. Загрузчик проверяет ИНН, виды, ссылки членов и уникальность «ЮЛ в одной ГСК/ГСЗ» до записи; apply — upsert по name/inn/(ГК, name), коды из последовательностей API, без удалений. `--no-dev-groups` / `run_seed(dev_groups=False)` — dev-данные без ГК; фикстуры тестов API используют его, чтобы начинать с пустых справочников. make check: 1132 passed; интеграция seed/import: 23 passed. Два теста падают и на main из-за обновлённых golden (test_mapping_golden 88 → 113, test_consolidation_fixtures UNMAPPED_TOTAL) — отдельная issue. Closes #31 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: cedd7915-2efe-41e5-988c-a9117033598b
101 lines
9.7 KiB
Markdown
101 lines
9.7 KiB
Markdown
# reference-data-seed Specification
|
||
|
||
## Purpose
|
||
Справочники продукта (роли, права и их матрица, план счетов, правила элиминации, состав обязательных документов) и
|
||
dev-данные загружаются из файлов репозитория одной идемпотентной командой; повторный запуск ничего не дублирует.
|
||
|
||
## Requirements
|
||
|
||
### Requirement: Идемпотентный seed справочников продукта
|
||
Команда `python -m scripts.seed` (из `api/`) SHALL загрузить из `api/seed/core/`: `regional_office` (Головной офис,
|
||
`is_head_office = true`), `role` — 7 системных ролей ТЗ 8.1 (`KA_RF`, `KA_GO`, `RKA`, `CLIENT_MANAGER`, `CURATOR_GO`,
|
||
`EXPERT`, `ADMIN`, `is_system = true`), `permission` — 16 сочетаний объект × действие из §10 правил с кодами
|
||
`<OBJECT>_<ACTION>` (`EXPORT` при совпадении), `role_permission` по матрице §10 (ASSUMPTION(OQ-16)), `chart_of_account`,
|
||
`elimination_rule` + `elimination_rule_account` версии 1 для ББ (§4), `required_document_rule` для `BASIC` и `EXTENDED`.
|
||
Записи SHALL вставляться или обновляться по натуральному ключу; удаление MUST NOT выполняться.
|
||
|
||
Исключение — матрица `role_permission` (ей после первичной загрузки владеет администратор, issue #9): в ПУСТУЮ таблицу
|
||
матрица файла SHALL загружаться целиком; в заполненную SHALL вставляться только пары, у которых роль или право
|
||
вставлены этим же запуском seed (их администратор снять не мог), а остальные пары файла MUST NOT добавляться — право,
|
||
снятое администратором, не возвращается, добавленное сверх файла не отзывается. Отчёт команды SHALL сообщать, что
|
||
матрица пропущена (или сколько добавлено пар новых ролей и прав).
|
||
|
||
#### Scenario: Первый запуск на пустой схеме
|
||
- **WHEN** после `alembic upgrade head` выполняется `python -m scripts.seed`
|
||
- **THEN** в `role` 7 строк, в `permission` 16, в `role_permission` — число строк равно сумме прав по матрице §10,
|
||
в `elimination_rule` 8 строк с `statement_type = balance`, `version_no = 1`, в `required_document_rule` для `BASIC`
|
||
10 строк (BALANCE, INCOME, OSV × 01, 58, 60, 62, 66, 67, 76, 90) и для `EXTENDED` 27 строк
|
||
|
||
#### Scenario: Повторный запуск
|
||
- **WHEN** `python -m scripts.seed` выполняется второй раз без изменения файлов
|
||
- **THEN** число строк во всех затронутых таблицах не меняется, команда завершается с кодом 0, в отчёте
|
||
`role_permission` помечена как пропущенная
|
||
|
||
#### Scenario: Право, снятое администратором
|
||
- **WHEN** администратор снял с роли `EXPERT` право `EX_VIEW`, после чего seed запущен снова
|
||
- **THEN** связь `EXPERT × EX_VIEW` не восстановлена, остальная матрица не изменилась
|
||
|
||
#### Scenario: Новые роль и право в файлах seed
|
||
- **WHEN** матрица заполнена, а в `permissions.yaml` добавлено новое право, в `roles.yaml` — новая роль, и в
|
||
`role_permissions.yaml` — их пары (новое право существующей роли, существующее право новой роли)
|
||
- **THEN** seed вставляет ровно эти пары; снятые ранее администратором связи существующих ролей и прав не возвращаются
|
||
|
||
#### Scenario: Администратор снял все связи
|
||
- **WHEN** таблица `role_permission` пуста и seed запущен снова
|
||
- **THEN** матрица файла загружается целиком, как при первом запуске
|
||
|
||
#### Scenario: Изменение названия роли в файле
|
||
- **WHEN** в `roles.yaml` изменено `name` роли `EXPERT` и seed запущен снова
|
||
- **THEN** строка `role` с `code = EXPERT` обновлена, новая не создана
|
||
|
||
### Requirement: Счета правил и чек-листа существуют в плане счетов
|
||
Все коды счетов, на которые ссылаются `elimination_rules_v1.yaml` и `required_document_rules.yaml`, SHALL резолвиться в
|
||
`chart_of_account.code` после seed; `elimination_rule_account.is_excluded = true` SHALL быть у исключений вида
|
||
«76 кроме 76.07.5, 76.07.9»; `chart_of_account.kind` SHALL быть задан для всех счетов, `is_off_balance = true`
|
||
для забалансовых счетов 001–012 и буквенных корней плана 1С (МЦ, НЕ, ГТД, ИНВ, КВ, ОТ, РВ, УСН) со всеми их субсчетами.
|
||
`chart_of_accounts.csv` SHALL содержать полный план счетов 1С заказчика (`fixtures/directories/chart-of-accounts-1c.xlsx`,
|
||
488 строк, включая буквенные субсчета `01.К`, `62.ОТ`, `76.АВ`; ASSUMPTION(OQ-113): выгрузка полна); `kind` строки — «Вид»
|
||
1С (у субсчёта может отличаться от родителя); субсчёт без родителя в выгрузке (`Я68.01`) загружается с пустым `parent_code`.
|
||
|
||
#### Scenario: Правило № 6 (основная пара)
|
||
- **WHEN** seed завершён
|
||
- **THEN** у правила `rule_no = 6` сторона 1 содержит счета 60.02, 60.22, 60.32, 62.01, 62.03, 62.21, 62.31, 76 и исключения
|
||
76.07.5, 76.07.9; сторона 2 — 60.01, 60.03, 60.21, 60.31, 62.02, 62.22, 62.32, 76 и исключение 76.07.1;
|
||
`elimination_mode = min`, `measure = closing`, `side_1 = D`
|
||
|
||
#### Scenario: Субсчета реальных ОСВ в плане счетов
|
||
- **WHEN** seed завершён
|
||
- **THEN** в `chart_of_account` есть `01.01`, `66.01`, `76.01`, `76.ОТ`, `01.К` и `МЦ.04` (строки ОСВ с этими кодами получают
|
||
`account_id`); `60.АВ` в плане 1С нет, `account_id` таких строк остаётся `NULL`
|
||
|
||
#### Scenario: Ссылка на несуществующий счёт
|
||
- **WHEN** в файл правил добавлен счёт, которого нет в `chart_of_accounts.csv`
|
||
- **THEN** seed падает до записи в БД с сообщением, какой счёт и в каком правиле не найден
|
||
|
||
### Requirement: Dev-данные только по явному флагу
|
||
`python -m scripts.seed --dev` SHALL дополнительно загрузить из `api/seed/dev/`: примеры региональных филиалов и по одному
|
||
`app_user` на каждую системную роль (`<role>@armka.local`, активные, с назначенной ролью через `user_role`). Без флага
|
||
`--dev` эти данные MUST NOT загружаться. Флаг `--dev` SHALL приниматься только при `DEBUG=true`: при `DEBUG=false`
|
||
команда MUST завершиться с кодом 2 и сообщением «--dev доступен только при DEBUG=true (dev-пользователи не для прода)»
|
||
до чтения файлов seed и обращения к БД (OQ-60).
|
||
|
||
#### Scenario: Dev-пользователи
|
||
- **WHEN** выполнен `python -m scripts.seed --dev`
|
||
- **THEN** в `app_user` 7 строк с email вида `ka_rf@armka.local`, каждая связана ровно с одной ролью через `user_role`
|
||
|
||
#### Scenario: Dev-ГК под документы fixtures
|
||
- **WHEN** `python -m scripts.seed --dev` на пустой схеме
|
||
- **THEN** созданы ГК «Русский Бисквит» (crm_id и состав — выгрузка ЕЦП CRM из fixtures: 20 ЮЛ/ИП, филиал
|
||
«Санкт-Петербургский РФ», ГСК из АО «Русский бисквит» и ООО «Пекарня Счастливочная») и ГК владельцев форм пакета ДКБ
|
||
(Унагранде, НПЗ, Межениновская); у ЮЛ `3528104476` алиасы «Юг-Финанс / ПЕКАРНЯ СЧАСТЛИВОЧНАЯ» и имя из шапки ОСВ, так
|
||
что документы из fixtures ложатся на «своих» ЮЛ с `counterparty_check = MATCH`; коды `GK-`/`GSK-NNNNNN` — из тех же
|
||
последовательностей, что API; повторный запуск ничего не меняет; без `--dev` ни одной ГК и ЮЛ нет
|
||
|
||
#### Scenario: Прод-режим
|
||
- **WHEN** выполнен `python -m scripts.seed` без `--dev`
|
||
- **THEN** таблица `app_user` пуста, `regional_office` содержит только Головной офис
|
||
|
||
#### Scenario: `--dev` без DEBUG
|
||
- **WHEN** при `DEBUG=false` выполнен `python -m scripts.seed --dev`
|
||
- **THEN** код возврата 2, в stderr — сообщение об отказе, БД не затронута
|