- модели LegalEntity.kpp / LegalEntityHistory.kpp (последней колонкой), миграция 0005_dbml_v5_17 (upgrade/downgrade); - domain/kpp.py: 9 символов (4 цифры, 2 цифры/латинские A-Z, 3 цифры), у ИП запрещён, иначе 422 INVALID_KPP; - схемы Create/Update/Out/Detail/HistoryOut, PATCH пишет снимок history и аудит before/after с kpp, поиск q по КПП; - импорт справочника: необязательная колонка КПП (синоним kpp), код INVALID_KPP, update обновляет непустой КПП; - dev-seed: необязательный ключ kpp (значений в данных нет, не выдумываем); - сверка с DBML, Makefile, README, CLAUDE.md, openspec/config.yaml — на v5.17. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EAKRDNzXtRrwmWz9z6PZu3
65 lines
3.3 KiB
Python
65 lines
3.3 KiB
Python
"""Часть 03 DBML v5.17 (учёт): план счетов и правила элиминации ВГО (Прил. 3/4 ТЗ как данные)."""
|
||
|
||
import datetime
|
||
import uuid
|
||
|
||
from sqlalchemy import Boolean, Date, ForeignKey, Index, Integer, SmallInteger, String, Text, text
|
||
from sqlalchemy.dialects.postgresql import UUID
|
||
from sqlalchemy.orm import Mapped, mapped_column
|
||
|
||
from .base import Base, UUIDPrimaryMixin
|
||
from .enums import AccountKind, AccountRowType, StatementType, pg_enum
|
||
|
||
|
||
class ChartOfAccount(UUIDPrimaryMixin, Base):
|
||
"""План счетов; `code` — нормализованный (60.01, 76.07.1)."""
|
||
|
||
__tablename__ = "chart_of_account"
|
||
|
||
code: Mapped[str] = mapped_column(String, nullable=False, unique=True)
|
||
parent_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("chart_of_account.id"))
|
||
name: Mapped[str] = mapped_column(String, nullable=False)
|
||
kind: Mapped[AccountKind | None] = mapped_column(pg_enum("account_kind"))
|
||
row_type: Mapped[AccountRowType] = mapped_column(pg_enum("account_row_type"), nullable=False)
|
||
is_off_balance: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default=text("false"))
|
||
|
||
|
||
class EliminationRule(UUIDPrimaryMixin, Base):
|
||
"""Правило элиминации (Прил. 3 — ББ, Прил. 4 — ОФР), версионируется; состав счетов — `elimination_rule_account`."""
|
||
|
||
__tablename__ = "elimination_rule"
|
||
__table_args__ = (
|
||
Index(
|
||
"uq_elimination_rule_statement_type_rule_no_version_no",
|
||
"statement_type",
|
||
"rule_no",
|
||
"version_no",
|
||
unique=True,
|
||
),
|
||
)
|
||
|
||
statement_type: Mapped[StatementType] = mapped_column(pg_enum("statement_type"), nullable=False)
|
||
rule_no: Mapped[int] = mapped_column(SmallInteger, nullable=False)
|
||
article_1_line: Mapped[str] = mapped_column(String, nullable=False)
|
||
article_2_line: Mapped[str] = mapped_column(String, nullable=False)
|
||
side_1: Mapped[str] = mapped_column(String, nullable=False)
|
||
measure: Mapped[str] = mapped_column(String, nullable=False)
|
||
elimination_mode: Mapped[str] = mapped_column(String, nullable=False)
|
||
vat_handling: Mapped[str | None] = mapped_column(String)
|
||
excise_adjust: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default=text("false"))
|
||
comment: Mapped[str | None] = mapped_column(Text)
|
||
version_no: Mapped[int] = mapped_column(Integer, nullable=False)
|
||
valid_from: Mapped[datetime.date] = mapped_column(Date, nullable=False)
|
||
valid_to: Mapped[datetime.date | None] = mapped_column(Date)
|
||
|
||
|
||
class EliminationRuleAccount(UUIDPrimaryMixin, Base):
|
||
"""Счета и субсчета сторон правила; `is_excluded` — исключение внутри маски («76 кроме 76.7.1»)."""
|
||
|
||
__tablename__ = "elimination_rule_account"
|
||
|
||
rule_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("elimination_rule.id"), nullable=False)
|
||
company_no: Mapped[int] = mapped_column(SmallInteger, nullable=False)
|
||
account_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("chart_of_account.id"), nullable=False)
|
||
is_excluded: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default=text("false"))
|