Enum counterparty_match_kind (INN, NAME, ALIAS, MANUAL, PROPAGATED) и nullable-колонка osv_entry.counterparty_match_kind (NULL <=> counterparty_id NULL). Миграция 0004_dbml_v5_16: enum, колонка, backfill тремя UPDATE по уже смапленным строкам (ИНН без пробелов -> INN, trim(имя) -> NAME, остальные -> ALIAS), откат удаляет колонку и тип. CounterpartyIndex.resolve возвращает Resolution(entity_id, kind) (определение в domain/osv_mapping, R-4); маппинг пишет kind; EntryOut.match_kind. DBML_VERSION 5.16, Makefile/dbml_parity/CLAUDE/README/config.yaml. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
65 lines
3.3 KiB
Python
65 lines
3.3 KiB
Python
"""Часть 03 DBML v5.16 (учёт): план счетов и правила элиминации ВГО (Прил. 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"))
|