project.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. from datetime import datetime
  2. from sqlalchemy import JSON, Boolean, DateTime, Float, ForeignKey, Integer, String, Text, func
  3. from sqlalchemy.orm import Mapped, mapped_column, relationship
  4. from backend.app.core.database import Base
  5. class Project(Base):
  6. """Project to group related prints (e.g., 'Voron Build' with multiple parts)."""
  7. __tablename__ = "projects"
  8. id: Mapped[int] = mapped_column(primary_key=True)
  9. name: Mapped[str] = mapped_column(String(255))
  10. description: Mapped[str | None] = mapped_column(Text, nullable=True)
  11. color: Mapped[str | None] = mapped_column(String(20), nullable=True) # Hex color for UI
  12. status: Mapped[str] = mapped_column(String(20), default="active") # active, completed, archived
  13. target_count: Mapped[int | None] = mapped_column(Integer, nullable=True) # Optional target number of prints
  14. # Phase 2: Rich text notes (HTML from WYSIWYG editor)
  15. notes: Mapped[str | None] = mapped_column(Text, nullable=True)
  16. # Phase 3: File attachments stored as JSON array
  17. # Format: [{"filename": "x.stl", "original_name": "part.stl", "size": 1234, "uploaded_at": "..."}]
  18. attachments: Mapped[list | None] = mapped_column(JSON, nullable=True)
  19. # Phase 4: Tags (comma-separated)
  20. tags: Mapped[str | None] = mapped_column(Text, nullable=True)
  21. # Phase 5: Due dates and priority
  22. due_date: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
  23. priority: Mapped[str] = mapped_column(String(20), default="normal") # low, normal, high, urgent
  24. # Phase 6: Budget tracking
  25. budget: Mapped[float | None] = mapped_column(Float, nullable=True)
  26. # Phase 8: Templates
  27. is_template: Mapped[bool] = mapped_column(Boolean, default=False)
  28. template_source_id: Mapped[int | None] = mapped_column(Integer, nullable=True)
  29. # Phase 10: Sub-projects (hierarchical)
  30. parent_id: Mapped[int | None] = mapped_column(ForeignKey("projects.id"), nullable=True)
  31. # Timestamps
  32. created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
  33. updated_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now(), onupdate=func.now())
  34. # Relationships
  35. archives: Mapped[list["PrintArchive"]] = relationship(back_populates="project")
  36. queue_items: Mapped[list["PrintQueueItem"]] = relationship(back_populates="project")
  37. children: Mapped[list["Project"]] = relationship(
  38. "Project",
  39. back_populates="parent",
  40. foreign_keys="Project.parent_id",
  41. )
  42. parent: Mapped["Project | None"] = relationship(
  43. "Project",
  44. back_populates="children",
  45. remote_side="Project.id",
  46. foreign_keys="Project.parent_id",
  47. )
  48. bom_items: Mapped[list["ProjectBOMItem"]] = relationship(back_populates="project", cascade="all, delete-orphan")
  49. from backend.app.models.archive import PrintArchive # noqa: E402
  50. from backend.app.models.print_queue import PrintQueueItem # noqa: E402
  51. from backend.app.models.project_bom import ProjectBOMItem # noqa: E402