109 lines
4.0 KiB
Python
109 lines
4.0 KiB
Python
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 Recipe(db.Model, TimestampMixin, SoftDeleteMixin):
|
||
"""Рацион (рецепт) кормления."""
|
||
|
||
__tablename__ = "recipe"
|
||
|
||
id = Column(String(36), primary_key=True, default=default_uuid)
|
||
name = Column(String(100), nullable=False)
|
||
heads_per_trip = Column(Integer, default=1)
|
||
mixing_time = Column(Integer, default=0)
|
||
trip_percent = Column(Float, default=100.0)
|
||
dry_matter_locked = Column(Boolean, nullable=False, default=False)
|
||
unloading_link_broken = Column(Boolean, nullable=False, default=False)
|
||
target_component_id = Column(
|
||
String(36), ForeignKey("component.id"), nullable=True, index=True
|
||
)
|
||
ration_type = Column(String(10), nullable=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="")
|
||
|
||
ingredients = relationship(
|
||
"Ingredient",
|
||
back_populates="recipe",
|
||
cascade="all, delete-orphan",
|
||
passive_deletes=True,
|
||
)
|
||
unloading_groups = relationship(
|
||
"UnloadingGroup",
|
||
back_populates="recipe",
|
||
cascade="all, delete-orphan",
|
||
passive_deletes=True,
|
||
)
|
||
trips = relationship(
|
||
"Trip",
|
||
back_populates="recipe",
|
||
cascade="all, delete-orphan",
|
||
passive_deletes=True,
|
||
)
|
||
period_recipes_rel = relationship(
|
||
"PeriodRecipe",
|
||
cascade="all, delete-orphan",
|
||
passive_deletes=True,
|
||
overlaps="feeding_periods",
|
||
)
|
||
|
||
|
||
class UnloadingGroup(db.Model, TimestampMixin, SoftDeleteMixin):
|
||
"""Группа выгрузки для рецепта."""
|
||
|
||
__tablename__ = "unloading_group"
|
||
|
||
id = Column(String(36), primary_key=True, default=default_uuid)
|
||
name = Column(String(100), nullable=False)
|
||
# 'percent' или 'heads'
|
||
distribution_type = Column(String(20), nullable=False)
|
||
# процент или количество голов
|
||
value = Column(Float, nullable=False)
|
||
# вес в кг
|
||
weight = Column(Float, nullable=True)
|
||
# порядок выгрузки
|
||
order = Column(Integer, nullable=False)
|
||
|
||
recipe_id = Column(
|
||
String(36), ForeignKey("recipe.id"), nullable=False, index=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="")
|
||
|
||
recipe = relationship("Recipe", back_populates="unloading_groups")
|
||
|
||
|
||
class PeriodRecipe(db.Model, TimestampMixin, SoftDeleteMixin):
|
||
"""Связка периода кормления и рецепта."""
|
||
|
||
__tablename__ = "period_recipes"
|
||
|
||
period_id = Column(
|
||
String(36), ForeignKey("feeding_period.id"), primary_key=True
|
||
)
|
||
recipe_id = Column(
|
||
String(36), ForeignKey("recipe.id"), primary_key=True, index=True
|
||
)
|
||
order = Column(Integer, nullable=False, default=0)
|
||
|
||
version = Column(Integer, default=1, nullable=False)
|
||
# created_at / updated_at — из TimestampMixin (БД: NOT NULL у обоих)
|
||
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="")
|
||
|