243 lines
13 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.

"""Часть 08 DBML v5.18 «КФО»: корректировки, гудвилл, результат КФО (шапка, строки, разрез по компаниям), КФО клиента.
Корректировки и гудвилл — ручные решения аналитика, хранятся поверх первички (overlay). Результат КФО
замораживается при VERIFIED. Деньги — `numeric(18,2)`, проценты — `numeric(7,4)` / `numeric(9,4)`.
"""
import datetime
import decimal
import uuid
from sqlalchemy import Boolean, CheckConstraint, DateTime, ForeignKey, Index, Integer, Numeric, String, Text, text
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column
from .base import Base, UUIDPrimaryMixin
from .enums import CorrectionStatus, StatementType, pg_enum
class VgoAssignment(UUIDPrimaryMixin, Base):
"""Выбор правила для строки ОСВ в рамках версии и типа отчётности."""
__tablename__ = "vgo_assignment"
__table_args__ = (
Index(
"uq_vgo_assignment_version_type_entry",
"consolidation_version_id",
"statement_type",
"osv_entry_id",
unique=True,
),
Index("ix_vgo_assignment_osv_entry_id", "osv_entry_id"),
CheckConstraint("action IN ('ASSIGN', 'UNASSIGNED')", name="action_values"),
CheckConstraint(
"(action = 'ASSIGN' AND rule_id IS NOT NULL) OR (action = 'UNASSIGNED' AND rule_id IS NULL)",
name="action_rule_consistency",
),
CheckConstraint("rule_id IS NULL OR NOT is_exclude", name="rule_not_excluded"),
)
consolidation_version_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("consolidation_version.id", name="fk_vgo_assignment_version"), nullable=False
)
statement_type: Mapped[StatementType] = mapped_column(pg_enum("statement_type"), nullable=False)
osv_entry_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("osv_entry.id", name="fk_vgo_assignment_entry"), nullable=False
)
rule_id: Mapped[uuid.UUID | None] = mapped_column(
UUID(as_uuid=True), ForeignKey("elimination_rule.id", name="fk_vgo_assignment_rule")
)
action: Mapped[str] = mapped_column(String, nullable=False)
is_exclude: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default=text("true"))
created_by: Mapped[uuid.UUID | None] = mapped_column(
UUID(as_uuid=True), ForeignKey("app_user.id", name="fk_vgo_assignment_created_by")
)
created_at: Mapped[datetime.datetime] = mapped_column(
DateTime(timezone=True), nullable=False, server_default=text("now()")
)
updated_by: Mapped[uuid.UUID | None] = mapped_column(
UUID(as_uuid=True), ForeignKey("app_user.id", name="fk_vgo_assignment_updated_by")
)
updated_at: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True))
class Correction(UUIDPrimaryMixin, Base):
"""Корректировка ВГО: итог = свод первички − Σ применённых корректировок; пара — по (rule_id, компании)."""
__tablename__ = "correction"
__table_args__ = (
Index("ix_correction_consolidation_version_id", "consolidation_version_id"),
Index(
"ix_correction_version_rule_entities",
"consolidation_version_id",
"rule_id",
"legal_entity_id",
"counterparty_id",
),
)
consolidation_version_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("consolidation_version.id"), nullable=False
)
statement_type: Mapped[StatementType] = mapped_column(pg_enum("statement_type"), nullable=False)
rule_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("elimination_rule.id"))
parent_correction_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("correction.id"))
legal_entity_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("legal_entity.id"))
counterparty_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("legal_entity.id"))
debit_line_code: Mapped[str | None] = mapped_column(String)
debit_account_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("chart_of_account.id"))
debit_adjustment: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
credit_line_code: Mapped[str | None] = mapped_column(String)
credit_account_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("chart_of_account.id"))
credit_adjustment: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
deviation_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
deviation_percent: Mapped[decimal.Decimal | None] = mapped_column(Numeric(9, 4))
reason_code: Mapped[str | None] = mapped_column(String)
comment: Mapped[str] = mapped_column(Text, nullable=False)
status: Mapped[CorrectionStatus] = mapped_column(
pg_enum("correction_status"), nullable=False, server_default=text("'DRAFT'")
)
version_no: Mapped[int] = mapped_column(Integer, nullable=False, server_default=text("1"))
created_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("app_user.id"))
created_at: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True))
updated_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("app_user.id"))
updated_at: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True))
class Goodwill(UUIDPrimaryMixin, Base):
"""Гудвилл по паре «головная организация — дочерняя» (ТЗ 6.7); доля участия вводится вручную, %."""
__tablename__ = "goodwill"
__table_args__ = (
Index(
"uq_goodwill_version_head_subsidiary",
"consolidation_version_id",
"head_legal_entity_id",
"subsidiary_legal_entity_id",
unique=True,
),
)
consolidation_version_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("consolidation_version.id"), nullable=False
)
head_legal_entity_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("legal_entity.id"), nullable=False
)
subsidiary_legal_entity_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("legal_entity.id"), nullable=False
)
ownership_share: Mapped[decimal.Decimal | None] = mapped_column(Numeric(7, 4))
financial_investment_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
charter_capital_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
additional_capital_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
participation_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
goodwill_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
include_in_kfo: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default=text("false"))
comment: Mapped[str | None] = mapped_column(Text)
created_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("app_user.id"))
created_at: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True))
updated_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("app_user.id"))
updated_at: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True))
class KfoResult(UUIDPrimaryMixin, Base):
"""Шапка результата КФО версии + контрольные пороги (ТЗ 6.8); `is_frozen = true` после VERIFIED."""
__tablename__ = "kfo_result"
consolidation_version_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("consolidation_version.id"), nullable=False, unique=True
)
computed_at: Mapped[datetime.datetime] = mapped_column(DateTime(timezone=True), nullable=False)
is_frozen: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default=text("false"))
net_assets: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
balance_total: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
revenue: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
sales_profit: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
total_deviation_bb: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
total_deviation_ofr: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
threshold_bb_exceeded: Mapped[bool | None] = mapped_column(Boolean)
threshold_ofr_exceeded: Mapped[bool | None] = mapped_column(Boolean)
threshold_justification: Mapped[str | None] = mapped_column(Text)
goodwill_total: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
has_deviations: Mapped[bool | None] = mapped_column(Boolean)
class KfoResultLine(UUIDPrimaryMixin, Base):
"""Строка КФО (ФСБУ 4/2023): сумма по компаниям -> авто-элиминация -> корректировки -> итог."""
__tablename__ = "kfo_result_line"
__table_args__ = (
Index(
"uq_kfo_result_line_result_type_code",
"kfo_result_id",
"statement_type",
"line_code",
unique=True,
),
)
kfo_result_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("kfo_result.id"), nullable=False)
statement_type: Mapped[StatementType] = mapped_column(pg_enum("statement_type"), nullable=False)
line_code: Mapped[str] = mapped_column(String, nullable=False)
line_name: Mapped[str | None] = mapped_column(String)
sum_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
eliminated_auto: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
eliminated_manual: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
goodwill_adjust: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
consolidated_amount: Mapped[decimal.Decimal] = mapped_column(Numeric(18, 2), nullable=False)
vgo_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
source_kind: Mapped[str | None] = mapped_column(String)
deviation_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
comment: Mapped[str | None] = mapped_column(Text)
ordinal: Mapped[int | None] = mapped_column(Integer)
class KfoResultLineCompany(Base):
"""Разрез статьи КФО по компаниям (ЕХ 6.6); составной PK (kfo_result_line_id, legal_entity_id)."""
__tablename__ = "kfo_result_line_company"
kfo_result_line_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("kfo_result_line.id"), primary_key=True
)
legal_entity_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True), ForeignKey("legal_entity.id"), primary_key=True
)
amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
share_percent: Mapped[decimal.Decimal | None] = mapped_column(Numeric(7, 4))
class ClientKfoLine(UUIDPrimaryMixin, Base):
"""Сравнение с КФО клиента: ручной ввод сумм клиента и расхождение относительно наименьшего (Методика, сн. 14)."""
__tablename__ = "client_kfo_line"
__table_args__ = (
Index(
"uq_client_kfo_line_version_type_code",
"consolidation_version_id",
"statement_type",
"line_code",
unique=True,
),
)
consolidation_version_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
ForeignKey("consolidation_version.id", name="fk_client_kfo_line_consolidation_version_id"),
nullable=False,
)
statement_type: Mapped[StatementType] = mapped_column(pg_enum("statement_type"), nullable=False)
line_code: Mapped[str] = mapped_column(String, nullable=False)
client_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
client_vgo_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
bank_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
bank_vgo_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
deviation_amount: Mapped[decimal.Decimal | None] = mapped_column(Numeric(18, 2))
deviation_percent: Mapped[decimal.Decimal | None] = mapped_column(Numeric(9, 4))
deviation_reason: Mapped[str | None] = mapped_column(Text)
comment: Mapped[str | None] = mapped_column(Text)
entered_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("app_user.id"))
entered_at: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True))