"""Enterprise-scoped SQLAlchemy models for the zootech lab module.""" from __future__ import annotations from datetime import UTC, datetime from uuid import uuid4 from sqlalchemy import Boolean, DateTime, Float, ForeignKey, Integer, String, Text, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column from app.db.base import Base class _LabAuditMixin: version: Mapped[int] = mapped_column(Integer, nullable=False, default=1) created_by: Mapped[str] = mapped_column(String(50), nullable=False, default="system") updated_by: Mapped[str] = mapped_column(String(50), nullable=False, default="system") class _LabTimestampMixin: created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC) ) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC), ) class _LabSoftDeleteMixin: is_deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) deleted_by: Mapped[str | None] = mapped_column(String(50), nullable=True) def soft_delete(self, deleted_by_user: str = "system", **_: object) -> None: if self.is_deleted: return self.is_deleted = True self.deleted_at = datetime.now(UTC) self.deleted_by = deleted_by_user class ZootechLabAnimalProfile(_LabTimestampMixin, _LabSoftDeleteMixin, _LabAuditMixin, Base): __tablename__ = "zootech_lab_animal_profile" __table_args__ = ( UniqueConstraint("enterprise_id", "profile_key", name="uq_zootech_lab_profile_ent_key"), UniqueConstraint("enterprise_id", "id", name="uq_zootech_lab_profile_ent_id"), ) enterprise_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) profile_key: Mapped[str] = mapped_column(String(64), nullable=False, index=True) label: Mapped[str] = mapped_column(String(200), nullable=False) ration_type: Mapped[str] = mapped_column(String(10), nullable=False, index=True) mass_kg: Mapped[float | None] = mapped_column(Float, nullable=True) milk_yield_kg: Mapped[float | None] = mapped_column(Float, nullable=True) external_no: Mapped[int | None] = mapped_column(Integer, nullable=True) norms_method: Mapped[str] = mapped_column(String(20), nullable=False, default="wesp") norms_params_json: Mapped[str | None] = mapped_column(Text, nullable=True) class ZootechLabProfileNorm(Base): __tablename__ = "zootech_lab_profile_norm" __table_args__ = ( UniqueConstraint("enterprise_id", "profile_id", "indicator_key", name="uq_zootech_lab_profile_norm"), ) enterprise_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) profile_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) indicator_key: Mapped[str] = mapped_column(String(64), nullable=False) min_value: Mapped[float | None] = mapped_column(Float, nullable=True) max_value: Mapped[float | None] = mapped_column(Float, nullable=True) class ZootechLabComponentNutrientValue(Base): __tablename__ = "zootech_lab_component_nutrient_value" __table_args__ = ( UniqueConstraint( "enterprise_id", "component_id", "nutrient_key", name="uq_zootech_lab_comp_nutrient", ), ) enterprise_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) component_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) nutrient_key: Mapped[str] = mapped_column(String(80), nullable=False, index=True) value: Mapped[float | None] = mapped_column(Float, nullable=True) class ZootechLabRecipeRation(_LabTimestampMixin, _LabSoftDeleteMixin, _LabAuditMixin, Base): __tablename__ = "zootech_lab_recipe_ration" enterprise_id: Mapped[str] = mapped_column(String(36), primary_key=True) recipe_id: Mapped[str] = mapped_column(String(36), primary_key=True) animal_profile_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True) calc_engine: Mapped[str | None] = mapped_column(String(20), nullable=True) seed_source: Mapped[str | None] = mapped_column(String(32), nullable=True) calculated_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) class ZootechLabRationLine(_LabTimestampMixin, _LabSoftDeleteMixin, _LabAuditMixin, Base): __tablename__ = "zootech_lab_ration_line" __table_args__ = (UniqueConstraint("enterprise_id", "id", name="uq_zootech_lab_ration_line_ent_id"),) enterprise_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) recipe_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) component_id: Mapped[str | None] = mapped_column(String(36), nullable=True, index=True) row_index: Mapped[int] = mapped_column(Integer, nullable=False, default=0) ingredient_name: Mapped[str | None] = mapped_column(String(200), nullable=True) daily_kg: Mapped[float | None] = mapped_column(Float, nullable=True) in_ration: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True) in_compound: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) class ZootechLabRationCalcTotal(Base): __tablename__ = "zootech_lab_ration_calc_total" __table_args__ = (UniqueConstraint("enterprise_id", "id", name="uq_zootech_lab_calc_total_ent_id"),) enterprise_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) recipe_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) scope: Mapped[str] = mapped_column(String(16), nullable=False, default="ration") metric_key: Mapped[str] = mapped_column(String(32), nullable=False) label: Mapped[str] = mapped_column(String(128), nullable=False, default="") value: Mapped[float | None] = mapped_column(Float, nullable=True) sort_order: Mapped[int] = mapped_column(Integer, nullable=False, default=0) class ZootechLabRationCalcIndicator(Base): __tablename__ = "zootech_lab_ration_calc_indicator" __table_args__ = (UniqueConstraint("enterprise_id", "id", name="uq_zootech_lab_calc_ind_ent_id"),) enterprise_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) recipe_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) scope: Mapped[str] = mapped_column(String(16), nullable=False, default="ration") indicator_key: Mapped[str | None] = mapped_column(String(64), nullable=True) label: Mapped[str] = mapped_column(String(128), nullable=False, default="") unit: Mapped[str] = mapped_column(String(32), nullable=False, default="") min_value: Mapped[float | None] = mapped_column(Float, nullable=True) max_value: Mapped[float | None] = mapped_column(Float, nullable=True) content: Mapped[float | None] = mapped_column(Float, nullable=True) diff: Mapped[float | None] = mapped_column(Float, nullable=True) sort_order: Mapped[int] = mapped_column(Integer, nullable=False, default=0) class ZootechLabRationCompoundLine(Base): __tablename__ = "zootech_lab_ration_compound_line" __table_args__ = (UniqueConstraint("enterprise_id", "id", name="uq_zootech_lab_compound_line_ent_id"),) enterprise_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) recipe_id: Mapped[str] = mapped_column(String(36), nullable=False, index=True) row_index: Mapped[int] = mapped_column(Integer, nullable=False, default=0) ingredient_name: Mapped[str | None] = mapped_column(String(200), nullable=True) daily_kg: Mapped[float | None] = mapped_column(Float, nullable=True) share_pct: Mapped[float | None] = mapped_column(Float, nullable=True) # Global RACION reference tables (not enterprise-scoped). class ZootechLabRacionNormyMoskwa(Base): __tablename__ = "zootech_lab_racion_normy_moskwa" __table_args__ = (UniqueConstraint("npitv", "pom", name="uq_zootech_lab_racion_moskwa_npitv_pom"),) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) npitv: Mapped[int] = mapped_column(Integer, nullable=False, index=True) pom: Mapped[int] = mapped_column(Integer, nullable=False, default=1) koef: Mapped[float | None] = mapped_column(Float, nullable=True) popr_k_json: Mapped[str | None] = mapped_column(Text, nullable=True) class ZootechLabRacionNormyMoskwaMeta(Base): __tablename__ = "zootech_lab_racion_normy_moskwa_meta" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) meta_key: Mapped[str] = mapped_column(String(32), nullable=False, unique=True) meta_json: Mapped[str | None] = mapped_column(Text, nullable=True) class ZootechLabRacionNormyPiter(Base): __tablename__ = "zootech_lab_racion_normy_piter" __table_args__ = ( UniqueConstraint("npitv", "konc", "udoy", name="uq_zootech_lab_racion_piter_npitv_konc_udoy"), ) id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) npitv: Mapped[int] = mapped_column(Integer, nullable=False, index=True) konc: Mapped[float] = mapped_column(Float, nullable=False) udoy: Mapped[float] = mapped_column(Float, nullable=False) normy_json: Mapped[str | None] = mapped_column(Text, nullable=True) class ZootechLabRacionNormyPiterMeta(Base): __tablename__ = "zootech_lab_racion_normy_piter_meta" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) meta_key: Mapped[str] = mapped_column(String(32), nullable=False, unique=True) meta_json: Mapped[str | None] = mapped_column(Text, nullable=True) class ZootechLabRacionNormyInfo(Base): __tablename__ = "zootech_lab_racion_normy_info" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=lambda: str(uuid4())) nperem: Mapped[int] = mapped_column(Integer, nullable=False, unique=True, index=True) znachenie_json: Mapped[str | None] = mapped_column(Text, nullable=True)