from datetime import datetime from sqlalchemy import JSON, Boolean, DateTime, Float, ForeignKey, Integer, String, Text, func from sqlalchemy.orm import Mapped, mapped_column from .database import Base class Machine(Base): __tablename__ = "machines" id: Mapped[int] = mapped_column(Integer, primary_key=True) code: Mapped[str] = mapped_column(String(50), unique=True, index=True) name: Mapped[str] = mapped_column(String(120)) brand: Mapped[str | None] = mapped_column(String(120)) model: Mapped[str | None] = mapped_column(String(120)) status: Mapped[str] = mapped_column(String(50), default="hors_planning") is_active: Mapped[bool] = mapped_column(Boolean, default=True) powered_on: Mapped[bool] = mapped_column(Boolean, default=True) cycle_signal_edge: Mapped[str] = mapped_column(String(20), default="rising") debounce_ms: Mapped[int] = mapped_column(Integer, default=300) min_cycle_time_sec: Mapped[int] = mapped_column(Integer, default=5) max_cycle_time_sec: Mapped[int] = mapped_column(Integer, default=300) stop_detection_delay_sec: Mapped[int] = mapped_column(Integer, default=180) last_cycle_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) status_since: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) class ProductionOrder(Base): __tablename__ = "production_orders" id: Mapped[int] = mapped_column(Integer, primary_key=True) order_number: Mapped[str] = mapped_column(String(80), unique=True, index=True) machine_id: Mapped[int] = mapped_column(ForeignKey("machines.id"), index=True) article_ref: Mapped[str] = mapped_column(String(80)) article_name: Mapped[str] = mapped_column(String(160)) mold_ref: Mapped[str | None] = mapped_column(String(80)) material_ref: Mapped[str | None] = mapped_column(String(80)) planned_qty: Mapped[int] = mapped_column(Integer) cavities: Mapped[int] = mapped_column(Integer, default=1) theoretical_cycle_time_sec: Mapped[float] = mapped_column(Float) status: Mapped[str] = mapped_column(String(40), default="planned") started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) ended_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) class MachineEvent(Base): __tablename__ = "machine_events" id: Mapped[int] = mapped_column(Integer, primary_key=True) machine_id: Mapped[int] = mapped_column(ForeignKey("machines.id"), index=True) event_type: Mapped[str] = mapped_column(String(80), index=True) timestamp: Mapped[datetime] = mapped_column(DateTime(timezone=True), index=True) payload: Mapped[dict] = mapped_column(JSON) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) class Cycle(Base): __tablename__ = "cycles" id: Mapped[int] = mapped_column(Integer, primary_key=True) machine_id: Mapped[int] = mapped_column(ForeignKey("machines.id"), index=True) production_order_id: Mapped[int | None] = mapped_column(ForeignKey("production_orders.id"), index=True) timestamp: Mapped[datetime] = mapped_column(DateTime(timezone=True), index=True) cycle_time_sec: Mapped[float] = mapped_column(Float) cavities: Mapped[int] = mapped_column(Integer, default=1) produced_qty: Mapped[int] = mapped_column(Integer, default=1) is_valid: Mapped[bool] = mapped_column(Boolean, default=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) class Downtime(Base): __tablename__ = "downtimes" id: Mapped[int] = mapped_column(Integer, primary_key=True) machine_id: Mapped[int] = mapped_column(ForeignKey("machines.id"), index=True) production_order_id: Mapped[int | None] = mapped_column(ForeignKey("production_orders.id"), index=True) start_time: Mapped[datetime] = mapped_column(DateTime(timezone=True), index=True) end_time: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), index=True) duration_sec: Mapped[int | None] = mapped_column(Integer) reason_code: Mapped[str | None] = mapped_column(String(80), ForeignKey("downtime_reasons.code")) comment: Mapped[str | None] = mapped_column(Text) auto_detected: Mapped[bool] = mapped_column(Boolean, default=True) qualified_by: Mapped[str | None] = mapped_column(String(120)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) class Scrap(Base): __tablename__ = "scraps" id: Mapped[int] = mapped_column(Integer, primary_key=True) machine_id: Mapped[int] = mapped_column(ForeignKey("machines.id"), index=True) production_order_id: Mapped[int | None] = mapped_column(ForeignKey("production_orders.id"), index=True) quantity: Mapped[int] = mapped_column(Integer) reason_code: Mapped[str] = mapped_column(String(80), ForeignKey("scrap_reasons.code")) comment: Mapped[str | None] = mapped_column(Text) operator_name: Mapped[str] = mapped_column(String(120)) timestamp: Mapped[datetime] = mapped_column(DateTime(timezone=True), index=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) class DowntimeReason(Base): __tablename__ = "downtime_reasons" code: Mapped[str] = mapped_column(String(80), primary_key=True) label: Mapped[str] = mapped_column(String(160)) class ScrapReason(Base): __tablename__ = "scrap_reasons" code: Mapped[str] = mapped_column(String(80), primary_key=True) label: Mapped[str] = mapped_column(String(160)) class Operator(Base): __tablename__ = "operators" id: Mapped[int] = mapped_column(Integer, primary_key=True) name: Mapped[str] = mapped_column(String(120), unique=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())