"""Часть 01 DBML v5.18 «Справочники»: филиалы, ГК и ЮЛ (SCD4), алиасы, ГСК/ГСЗ (SCD2).""" import datetime import uuid from sqlalchemy import Boolean, Date, DateTime, ForeignKey, Index, Sequence, String, text from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column from .base import SCHEMA, Base, UUIDPrimaryMixin from .enums import EntityType, LeHistoryEvent, RelatedGroupKind, pg_enum #: Последовательности кодов ГК и ГСК/ГСЗ (design D-5): `GK-000001`, `GSK-000001`/`GSZ-000001`. В DBML не описываются #: (не таблицы); создаются миграцией 0002 и `Base.metadata.create_all` (привязаны к metadata). COMPANY_GROUP_CODE_SEQ = Sequence("company_group_code_seq", schema=SCHEMA, metadata=Base.metadata) RELATED_GROUP_CODE_SEQ = Sequence("related_group_code_seq", schema=SCHEMA, metadata=Base.metadata) class RegionalOffice(UUIDPrimaryMixin, Base): """Филиал: ГО и региональные филиалы (DECISION-3: ГО — обычная запись с `is_head_office`).""" __tablename__ = "regional_office" name: Mapped[str] = mapped_column(String, nullable=False, unique=True) is_head_office: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default=text("false")) is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default=text("true")) class CompanyGroup(UUIDPrimaryMixin, Base): """ГК — текущее состояние (SCD4); история — `company_group_history`.""" __tablename__ = "company_group" code: Mapped[str] = mapped_column(String, nullable=False, unique=True) crm_id: Mapped[str | None] = mapped_column(String, unique=True) name: Mapped[str] = mapped_column(String, nullable=False) base_regional_office_id: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey("regional_office.id") ) is_archived: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default=text("false")) valid_from: Mapped[datetime.datetime] = mapped_column(DateTime(timezone=True), nullable=False) updated_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_at: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True)) class CompanyGroupHistory(UUIDPrimaryMixin, Base): """Прошлые снимки ГК (SCD4).""" __tablename__ = "company_group_history" __table_args__ = ( Index("uq_company_group_history_company_group_id_valid_from", "company_group_id", "valid_from", unique=True), ) company_group_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("company_group.id"), nullable=False ) crm_id: Mapped[str | None] = mapped_column(String) name: Mapped[str | None] = mapped_column(String) base_regional_office_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True)) valid_from: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True)) valid_to: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True)) changed_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("app_user.id")) class LegalEntity(UUIDPrimaryMixin, Base): """Организация (ЮЛ/ИП) — текущее состояние (SCD4); `company_group_id IS NULL` = монозаёмщик.""" __tablename__ = "legal_entity" inn: Mapped[str] = mapped_column(String, nullable=False, unique=True) crm_id: Mapped[str | None] = mapped_column(String, unique=True) entity_type: Mapped[EntityType | None] = mapped_column(pg_enum("entity_type")) name: Mapped[str] = mapped_column(String, nullable=False) company_group_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("company_group.id")) regional_office_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("regional_office.id")) close_date: Mapped[datetime.date | None] = mapped_column(Date) valid_from: Mapped[datetime.datetime] = mapped_column(DateTime(timezone=True), nullable=False) updated_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_at: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True)) # v5.17, последней колонкой (как её добавляет миграция 0005): КПП, nullable; у ИП запрещён — проверяет ядро kpp: Mapped[str | None] = mapped_column(String) class LegalEntityHistory(UUIDPrimaryMixin, Base): """Прошлые снимки ЮЛ (SCD4) и события для архива ГК.""" __tablename__ = "legal_entity_history" __table_args__ = ( Index("uq_legal_entity_history_legal_entity_id_valid_from", "legal_entity_id", "valid_from", unique=True), ) legal_entity_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("legal_entity.id"), nullable=False ) inn: Mapped[str | None] = mapped_column(String) crm_id: Mapped[str | None] = mapped_column(String) entity_type: Mapped[EntityType | None] = mapped_column(pg_enum("entity_type")) name: Mapped[str | None] = mapped_column(String) company_group_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True)) regional_office_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True)) close_date: Mapped[datetime.date | None] = mapped_column(Date) event_type: Mapped[LeHistoryEvent | None] = mapped_column(pg_enum("le_history_event")) effective_date: Mapped[datetime.date | None] = mapped_column(Date) valid_from: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True)) valid_to: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True)) changed_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("app_user.id")) kpp: Mapped[str | None] = mapped_column(String) # v5.17, последней колонкой: снимок КПП class LegalEntityAlias(UUIDPrimaryMixin, Base): """Словарь соответствий наименований контрагентов (ТЗ 6.5).""" __tablename__ = "legal_entity_alias" __table_args__ = ( Index( "uq_legal_entity_alias_legal_entity_id_normalized_alias", "legal_entity_id", "normalized_alias", unique=True ), Index("ix_legal_entity_alias_normalized_alias", "normalized_alias"), ) legal_entity_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("legal_entity.id"), nullable=False ) alias: Mapped[str] = mapped_column(String, nullable=False) normalized_alias: Mapped[str] = mapped_column(String, nullable=False) 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)) class RelatedGroup(UUIDPrimaryMixin, Base): """ГСК/ГСЗ — текущее состояние; иерархия групп не поддерживается (ТЗ 6.1).""" __tablename__ = "related_group" code: Mapped[str] = mapped_column(String, nullable=False, unique=True) company_group_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("company_group.id"), nullable=False ) kind: Mapped[RelatedGroupKind] = mapped_column(pg_enum("related_group_kind"), nullable=False) name: Mapped[str] = mapped_column(String, nullable=False) created_date: Mapped[datetime.date | None] = mapped_column(Date) class RelatedGroupMember(UUIDPrimaryMixin, Base): """Состав ГСК/ГСЗ — SCD2; исключение = закрытие версии (`is_current=false`).""" __tablename__ = "related_group_member" __table_args__ = ( # (related_group_id, legal_entity_id): partial UNIQUE WHERE is_current Index( "uq_related_group_member_group_entity_current", "related_group_id", "legal_entity_id", unique=True, postgresql_where=text("is_current"), ), # (legal_entity_id, kind): partial UNIQUE WHERE is_current — v5.14: ЮЛ в одной ГСК И одной ГСЗ одновременно Index( "uq_related_group_member_entity_kind_current", "legal_entity_id", "kind", unique=True, postgresql_where=text("is_current"), ), ) related_group_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("related_group.id"), nullable=False ) legal_entity_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("legal_entity.id"), nullable=False ) kind: Mapped[RelatedGroupKind] = mapped_column(pg_enum("related_group_kind"), nullable=False) valid_from: Mapped[datetime.datetime] = mapped_column(DateTime(timezone=True), nullable=False) valid_to: Mapped[datetime.datetime | None] = mapped_column(DateTime(timezone=True)) is_current: Mapped[bool] = mapped_column(Boolean, nullable=False) created_by: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("app_user.id"))