arm-core/api/src/models/statements.py
Andrey Epifancev eaee3ec5f9 feat(model): DBML v5.16 — counterparty_match_kind, миграция 0004, шаг резолва в маппинге
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
2026-10-06 03:23:02 +04:00

120 lines
6.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Часть 06 DBML v5.16 «Бухгалтерская отчётность»: шапка, колонки-периоды, строки и значения форм ББ/ОФР (157н).
Первичка не мутируется: `*_original_value` / `original_amount` / `is_modified` — рядом с распознанным значением.
Логические проверки (ТЗ 6.3) и «требует проверки» не хранятся — считаются на лету.
"""
import datetime
import decimal
import uuid
from sqlalchemy import Boolean, Date, DateTime, ForeignKey, Index, Numeric, 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 StatementType, pg_enum
class FinancialStatementMeta(UUIDPrimaryMixin, Base):
"""Шапка распознанной формы ББ/ОФР; 1:1 с `document`."""
__tablename__ = "financial_statement_meta"
document_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("document.id"), nullable=False, unique=True
)
recognition_job_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("recognition_job.id"), nullable=False
)
statement_type: Mapped[StatementType] = mapped_column(pg_enum("statement_type"), nullable=False)
inn: Mapped[str | None] = mapped_column(String)
inn_original_value: Mapped[str | None] = mapped_column(String)
inn_confidence: Mapped[decimal.Decimal | None] = mapped_column(Numeric(5, 2))
inn_verified: Mapped[bool | None] = mapped_column(Boolean)
inn_modified: Mapped[bool | None] = mapped_column(Boolean)
organization_name: Mapped[str | None] = mapped_column(String)
report_date: Mapped[datetime.date | None] = mapped_column(Date)
report_date_original_value: Mapped[str | None] = mapped_column(String)
report_date_verified: Mapped[bool | None] = mapped_column(Boolean)
report_date_modified: Mapped[bool | None] = mapped_column(Boolean)
units: Mapped[str | None] = mapped_column(String)
units_original_value: Mapped[str | None] = mapped_column(String)
units_verified: Mapped[bool | None] = mapped_column(Boolean)
units_modified: Mapped[bool | None] = mapped_column(Boolean)
currency: Mapped[str | None] = mapped_column(String, server_default=text("'RUB'"))
okpo: Mapped[str | None] = mapped_column(String)
okopf: Mapped[str | None] = mapped_column(String)
okfs: Mapped[str | None] = mapped_column(String)
okud: Mapped[str | None] = mapped_column(String)
okei: Mapped[str | None] = mapped_column(String)
legal_form: Mapped[str | None] = mapped_column(String)
ownership_form: Mapped[str | None] = mapped_column(String)
address: Mapped[str | None] = mapped_column(String)
subject_to_audit: Mapped[bool | None] = mapped_column(Boolean)
reviewed_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("app_user.id"))
reviewed_at: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True))
checks_accepted_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("app_user.id"))
checks_accepted_at: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True))
checks_accepted_comment: Mapped[str | None] = mapped_column(Text)
class FinancialStatementColumn(UUIDPrimaryMixin, Base):
"""Колонка-период формы (2–3 сравнительные даты); `period_date` нужна межформенным проверкам и гудвиллу."""
__tablename__ = "financial_statement_column"
__table_args__ = (
Index("uq_financial_statement_column_meta_id_column_index", "meta_id", "column_index", unique=True),
)
meta_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("financial_statement_meta.id"), nullable=False
)
column_index: Mapped[int] = mapped_column(SmallInteger, nullable=False)
label: Mapped[str | None] = mapped_column(String)
period_date: Mapped[datetime.date | None] = mapped_column(Date)
is_current: Mapped[bool | None] = mapped_column(Boolean)
class FinancialStatementLine(UUIDPrimaryMixin, Base):
"""Строка формы с кодом; порядок, разделы и итоговые строки — шаблон формы на фронте."""
__tablename__ = "financial_statement_line"
__table_args__ = (Index("uq_financial_statement_line_meta_id_line_code", "meta_id", "line_code", unique=True),)
meta_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("financial_statement_meta.id"), nullable=False
)
line_code: Mapped[str | None] = mapped_column(String)
line_code_original_value: Mapped[str | None] = mapped_column(String)
line_code_confidence: Mapped[decimal.Decimal | None] = mapped_column(Numeric(5, 2))
line_code_modified: Mapped[bool | None] = mapped_column(Boolean)
line_name: Mapped[str | None] = mapped_column(String)
line_name_original_value: Mapped[str | None] = mapped_column(String)
line_name_confidence: Mapped[decimal.Decimal | None] = mapped_column(Numeric(5, 2))
line_name_modified: Mapped[bool | None] = mapped_column(Boolean)
class FinancialStatementValue(UUIDPrimaryMixin, Base):
"""Распознанное значение (строка x колонка): сумма, уверенность, признак ручной правки (Прил. 2 ТЗ)."""
__tablename__ = "financial_statement_value"
__table_args__ = (Index("uq_financial_statement_value_line_id_column_id", "line_id", "column_id", unique=True),)
line_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("financial_statement_line.id"), nullable=False
)
column_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
ForeignKey("financial_statement_column.id", name="fk_financial_statement_value_column_id_fs_column"),
nullable=False,
)
amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
string_value: Mapped[str | None] = mapped_column(String)
confidence: Mapped[decimal.Decimal | None] = mapped_column(Numeric(5, 2))
is_recognized: Mapped[bool | None] = mapped_column(Boolean)
is_modified: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default=text("false"))
original_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
modified_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("app_user.id"))
modified_at: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True))