89 lines
3.0 KiB
Python
89 lines
3.0 KiB
Python
"""Модель проверенного набора seed и отчёта о применении (без доступа к БД)."""
|
||
|
||
from dataclasses import dataclass, field
|
||
|
||
from src.models.enums import AccountKind, AccountRowType, PermissionAction, PermissionObject
|
||
|
||
|
||
class SeedError(Exception):
|
||
"""Ошибка файлов seed (отсутствие, формат, ссылочная целостность); сообщение — по-русски, с файлом и записью."""
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class RegionalOfficeSeed:
|
||
name: str
|
||
is_head_office: bool
|
||
is_active: bool
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class RoleSeed:
|
||
code: str
|
||
name: str
|
||
description: str | None
|
||
is_system: bool
|
||
is_active: bool
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class PermissionSeed:
|
||
code: str
|
||
object_type: PermissionObject
|
||
action: PermissionAction
|
||
name: str
|
||
description: str | None
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class AccountSeed:
|
||
"""Строка плана счетов; `code` нормализован (60.01, 76.07.1), `parent_code` — код родителя или None."""
|
||
|
||
code: str
|
||
parent_code: str | None
|
||
name: str
|
||
kind: AccountKind | None
|
||
row_type: AccountRowType
|
||
is_off_balance: bool
|
||
|
||
|
||
@dataclass
|
||
class SeedData:
|
||
"""Проверенный набор seed; ничего не знает о БД."""
|
||
|
||
regional_offices: list[RegionalOfficeSeed] = field(default_factory=list)
|
||
roles: list[RoleSeed] = field(default_factory=list)
|
||
permissions: list[PermissionSeed] = field(default_factory=list)
|
||
#: код роли -> коды прав (порядок как в файле)
|
||
role_permissions: dict[str, list[str]] = field(default_factory=dict)
|
||
#: код счёта -> счёт; порядок файла (родитель раньше потомков). Реестр кодов для загрузчика правил: `account_codes`
|
||
accounts: dict[str, AccountSeed] = field(default_factory=dict)
|
||
|
||
|
||
def account_codes(data: SeedData) -> frozenset[str]:
|
||
"""Коды плана счетов набора: правила элиминации и чек-лист проверяют свои ссылки на счета по этому реестру."""
|
||
return frozenset(data.accounts)
|
||
|
||
|
||
@dataclass
|
||
class TableStat:
|
||
inserted: int = 0
|
||
updated: int = 0
|
||
unchanged: int = 0
|
||
|
||
|
||
@dataclass
|
||
class SeedReport:
|
||
"""Итог применения: по таблицам — сколько строк вставлено / обновлено / не изменилось."""
|
||
|
||
tables: dict[str, TableStat] = field(default_factory=dict)
|
||
|
||
def stat(self, table: str) -> TableStat:
|
||
return self.tables.setdefault(table, TableStat())
|
||
|
||
def format(self) -> str:
|
||
lines = ["Seed применён (вставлено / обновлено / без изменений):"]
|
||
lines += [
|
||
f" {name}: {stat.inserted} / {stat.updated} / {stat.unchanged}" for name, stat in self.tables.items()
|
||
]
|
||
return "\n".join(lines)
|