from sqlalchemy import Column, DateTime, Float, ForeignKey, Integer, String, Text from sqlalchemy.orm import relationship from app import db from .base import SoftDeleteMixin, TimestampMixin, default_uuid class LoadingReport(db.Model, TimestampMixin, SoftDeleteMixin): """Отчёт о загрузке кормосмесителя.""" __bind_key__ = "reports" __tablename__ = "loading_report" id = Column(String(36), primary_key=True, default=default_uuid) recipe_id = Column(String(36), nullable=False) recipe_name = Column(String(100), nullable=False) start_time = Column(DateTime, nullable=False) end_time = Column(DateTime) target_mixing_time = Column(Integer) actual_mixing_time = Column(Integer) total_weight = Column(Float) dispenser_type = Column(String(20), nullable=False, default="dispenser") 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") client_id = Column(String(50), nullable=True) server_synced = Column(db.Boolean, default=False, nullable=False) sync_timestamp = Column(DateTime, nullable=True) sync_status = Column(String(20), default="pending", nullable=False) content_hash = Column(String(64), nullable=False, default="") components = relationship( "LoadingReportComponent", back_populates="report", cascade="all, delete-orphan", passive_deletes=True, ) component_loading_times = relationship( "ComponentLoadingTime", back_populates="report", cascade="all, delete-orphan", passive_deletes=True, ) class LoadingReportComponent(db.Model, TimestampMixin, SoftDeleteMixin): """Строка отчёта о загрузке (по компоненту).""" __bind_key__ = "reports" __tablename__ = "loading_report_component" id = Column(String(36), primary_key=True, default=default_uuid) report_id = Column( String(36), ForeignKey("loading_report.id"), nullable=False, index=True ) component_id = Column(String(36), nullable=True, index=True) component_name = Column(String(100), nullable=False) target_weight = Column(Float, nullable=False) actual_weight = Column(Float, nullable=False) overload = Column(Float) loading_order = Column(Integer, nullable=False) 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="") report = relationship("LoadingReport", back_populates="components") class ComponentLoadingTime(db.Model, TimestampMixin, SoftDeleteMixin): """Временные метки начала/конца загрузки компонента.""" __bind_key__ = "reports" __tablename__ = "component_loading_time" id = Column(String(36), primary_key=True, default=default_uuid) report_id = Column( String(36), ForeignKey("loading_report.id"), nullable=False, index=True ) component_name = Column(String(100), nullable=False) start_time = Column(DateTime, nullable=False) end_time = Column(DateTime, nullable=False) loading_duration = Column(Float, nullable=False) loading_order = Column(Integer, nullable=False) 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="") report = relationship("LoadingReport", back_populates="component_loading_times") class UnloadingReport(db.Model, TimestampMixin, SoftDeleteMixin): """Отчёт о выгрузке.""" __bind_key__ = "reports" __tablename__ = "unloading_report" id = Column(String(36), primary_key=True, default=default_uuid) recipe_id = Column(String(36), nullable=False) recipe_name = Column(String(100), nullable=False) loading_report_id = Column(String(36), nullable=False) start_time = Column(DateTime, nullable=False) end_time = Column(DateTime) total_weight = Column(Float, nullable=False) total_unloaded_weight = Column(Float, nullable=False) remaining_weight = Column(Float, nullable=False) 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") client_id = Column(String(50), nullable=True) server_synced = Column(db.Boolean, default=False, nullable=False) sync_timestamp = Column(DateTime, nullable=True) sync_status = Column(String(20), default="pending", nullable=False) content_hash = Column(String(64), nullable=False, default="") groups = relationship( "UnloadingReportGroup", back_populates="report", cascade="all, delete-orphan", passive_deletes=True, ) class UnloadingReportGroup(db.Model, TimestampMixin, SoftDeleteMixin): """Строка отчёта о выгрузке по группе.""" __bind_key__ = "reports" __tablename__ = "unloading_report_group" id = Column(String(36), primary_key=True, default=default_uuid) report_id = Column( String(36), ForeignKey("unloading_report.id"), nullable=False, index=True ) name = Column(String(100), nullable=False) target_weight = Column(Float, nullable=False) unloaded_weight = Column(Float, nullable=False) remaining_weight = Column(Float, nullable=False) distribution_type = Column(String(20), nullable=False) distribution_value = Column(Float, nullable=False) order = Column(Integer, nullable=False) 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="") report = relationship("UnloadingReport", back_populates="groups")