from sqlalchemy import Boolean, Column, DateTime, Float, ForeignKey, Integer, String from sqlalchemy.orm import relationship from app import db from .base import SoftDeleteMixin, TimestampMixin, default_uuid class FeedMixer(db.Model, TimestampMixin, SoftDeleteMixin): """Кормосмеситель.""" __tablename__ = "feed_mixer" id = Column(String(36), primary_key=True, default=default_uuid) name = Column(String(100), nullable=False) model = Column(String(100)) gosnomer = Column(String(20)) operator = Column(String(100)) ip_address = Column(String(15)) is_active = Column(Boolean, default=True) version = Column(Integer, default=1, nullable=False) created_by = Column(String(50), nullable=False, default="system") updated_by = Column(String(50), nullable=False, default="system") sync_timestamp = Column(DateTime, nullable=True) sync_status = Column(String(20), default="pending", nullable=False) content_hash = Column(String(64), nullable=False, default="") trips = relationship( "Trip", back_populates="mixer", cascade="all, delete-orphan", passive_deletes=True, ) class FeedDispenser(db.Model, TimestampMixin, SoftDeleteMixin): """Кормораздатчик (шкаф управления).""" __tablename__ = "feed_dispenser" id = Column(String(36), primary_key=True, default=default_uuid) name = Column(String(100), nullable=False) farm = Column(String(100), nullable=False) operator = Column(String(100), nullable=False) type = Column(String(20), nullable=False, default="dispenser") is_active = Column(Boolean, default=True) version = Column(Integer, default=1, nullable=False) created_by = Column(String(50), nullable=False, default="system") updated_by = Column(String(50), nullable=False, default="system") sync_timestamp = Column(DateTime, nullable=True) sync_status = Column(String(20), default="pending", nullable=False) content_hash = Column(String(64), nullable=False, default="") periods = relationship( "FeedingPeriod", back_populates="dispenser", cascade="all, delete-orphan", passive_deletes=True, ) class FeedingLocation(db.Model, TimestampMixin, SoftDeleteMixin): """Место кормления (группа точек выгрузки).""" __tablename__ = "feeding_location" id = Column(String(36), primary_key=True, default=default_uuid) name = Column(String(100), nullable=False) mixer_id = Column(String(36), ForeignKey("feed_mixer.id"), nullable=True) is_active = Column(Boolean, default=True) version = Column(Integer, default=1, nullable=False) created_by = Column(String(50), nullable=False, default="system") updated_by = Column(String(50), nullable=False, default="system") sync_timestamp = Column(DateTime, nullable=True) sync_status = Column(String(20), default="pending", nullable=False) content_hash = Column(String(64), nullable=False, default="") class FeedingPeriod(db.Model, TimestampMixin, SoftDeleteMixin): """Период кормления (расписание для кормораздатчика).""" __tablename__ = "feeding_period" id = Column(String(36), primary_key=True, default=default_uuid) name = Column(String(100), nullable=False) dispenser_id = Column( String(36), ForeignKey("feed_dispenser.id"), nullable=False ) is_active = Column(Boolean, default=True) version = Column(Integer, default=1, nullable=False) created_by = Column(String(50), nullable=False, default="system") updated_by = Column(String(50), nullable=False, default="system") sync_timestamp = Column(DateTime, nullable=True) sync_status = Column(String(20), default="pending", nullable=False) content_hash = Column(String(64), nullable=False, default="") recipes = relationship( "Recipe", secondary="period_recipes", backref="feeding_periods", lazy="joined", overlaps="period_recipes_rel", ) period_recipes_rel = relationship( "PeriodRecipe", cascade="all, delete-orphan", passive_deletes=True, overlaps="feeding_periods,recipes", ) dispenser = relationship("FeedDispenser", back_populates="periods") class FeedingPoint(db.Model, TimestampMixin, SoftDeleteMixin): """Точка кормления (конкретное место выгрузки).""" __tablename__ = "feeding_point" id = Column(String(36), primary_key=True, default=default_uuid) name = Column(String(100), nullable=False) mixer_id = Column(String(36), ForeignKey("feed_mixer.id"), nullable=True) location_id = Column( String(36), ForeignKey("feeding_location.id"), nullable=True ) period_id = Column( String(36), ForeignKey("feeding_period.id"), nullable=True ) is_active = Column(Boolean, default=True) version = Column(Integer, default=1, nullable=False) created_by = Column(String(50), nullable=False, default="system") updated_by = Column(String(50), nullable=False, default="system") sync_timestamp = Column(DateTime, nullable=True) sync_status = Column(String(20), default="pending", nullable=False) content_hash = Column(String(64), nullable=False, default="") class Trip(db.Model, TimestampMixin, SoftDeleteMixin): """Рейс кормораздатчика.""" __tablename__ = "trip" id = Column(String(36), primary_key=True, default=default_uuid) mixer_id = Column(String(36), ForeignKey("feed_mixer.id"), nullable=False) recipe_id = Column(String(36), ForeignKey("recipe.id"), nullable=False) daily_ration_percent = Column(Float, nullable=False) heads_count = Column(Integer, nullable=False) mixing_time = Column(Integer, nullable=False) correction_percent = Column(Float, nullable=False) status = Column(String(20), nullable=False) created_at = Column(DateTime, nullable=False) started_at = Column(DateTime) completed_at = Column(DateTime) version = Column(Integer, default=1, nullable=False) updated_at = Column(DateTime, nullable=False) created_by = Column(String(50), nullable=False, default="system") updated_by = Column(String(50), nullable=False, default="system") sync_timestamp = Column(DateTime, nullable=True) sync_status = Column(String(20), default="pending", nullable=False) content_hash = Column(String(64), nullable=False, default="") mixer = relationship("FeedMixer", back_populates="trips") recipe = relationship("Recipe", back_populates="trips")