project.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. from datetime import datetime
  2. from pydantic import BaseModel
  3. class ProjectCreate(BaseModel):
  4. """Schema for creating a new project."""
  5. name: str
  6. description: str | None = None
  7. color: str | None = None
  8. target_count: int | None = None
  9. notes: str | None = None
  10. tags: str | None = None
  11. due_date: datetime | None = None
  12. priority: str = "normal"
  13. budget: float | None = None
  14. parent_id: int | None = None # For sub-projects
  15. class ProjectUpdate(BaseModel):
  16. """Schema for updating a project."""
  17. name: str | None = None
  18. description: str | None = None
  19. color: str | None = None
  20. status: str | None = None # active, completed, archived
  21. target_count: int | None = None
  22. notes: str | None = None
  23. tags: str | None = None
  24. due_date: datetime | None = None
  25. priority: str | None = None
  26. budget: float | None = None
  27. parent_id: int | None = None
  28. class ProjectStats(BaseModel):
  29. """Statistics for a project."""
  30. total_archives: int = 0 # Number of archive records
  31. total_items: int = 0 # Sum of quantities (total items printed)
  32. completed_prints: int = 0 # Sum of quantities for completed prints
  33. failed_prints: int = 0 # Sum of quantities for failed prints
  34. queued_prints: int = 0
  35. in_progress_prints: int = 0
  36. total_print_time_hours: float = 0.0
  37. total_filament_grams: float = 0.0
  38. progress_percent: float | None = None # Based on target_count
  39. # Cost tracking (Phase 6)
  40. estimated_cost: float = 0.0 # Based on filament cost
  41. total_energy_kwh: float = 0.0
  42. total_energy_cost: float = 0.0
  43. remaining_prints: int | None = None # target_count - completed_prints
  44. # BOM stats (Phase 7)
  45. bom_total_items: int = 0
  46. bom_completed_items: int = 0
  47. class ProjectChildPreview(BaseModel):
  48. """Minimal project data for child preview."""
  49. id: int
  50. name: str
  51. color: str | None
  52. status: str
  53. progress_percent: float | None = None
  54. class ProjectResponse(BaseModel):
  55. """Schema for project response."""
  56. id: int
  57. name: str
  58. description: str | None
  59. color: str | None
  60. status: str
  61. target_count: int | None
  62. notes: str | None = None
  63. attachments: list | None = None
  64. tags: str | None = None
  65. due_date: datetime | None = None
  66. priority: str = "normal"
  67. budget: float | None = None
  68. is_template: bool = False
  69. template_source_id: int | None = None
  70. parent_id: int | None = None
  71. parent_name: str | None = None # For display
  72. children: list[ProjectChildPreview] = []
  73. created_at: datetime
  74. updated_at: datetime
  75. stats: ProjectStats | None = None
  76. class Config:
  77. from_attributes = True
  78. class ArchivePreview(BaseModel):
  79. """Minimal archive data for project preview."""
  80. id: int
  81. print_name: str | None
  82. thumbnail_path: str | None
  83. status: str
  84. filament_type: str | None = None
  85. filament_color: str | None = None
  86. class ProjectListResponse(BaseModel):
  87. """Schema for project list item (lighter weight)."""
  88. id: int
  89. name: str
  90. description: str | None
  91. color: str | None
  92. status: str
  93. target_count: int | None
  94. created_at: datetime
  95. # Quick stats
  96. archive_count: int = 0 # Number of print jobs
  97. total_items: int = 0 # Sum of quantities (total items printed)
  98. queue_count: int = 0
  99. progress_percent: float | None = None
  100. # Preview of archives (up to 5)
  101. archives: list[ArchivePreview] = []
  102. class Config:
  103. from_attributes = True
  104. class BatchAddArchives(BaseModel):
  105. """Schema for batch adding archives to a project."""
  106. archive_ids: list[int]
  107. class BatchAddQueueItems(BaseModel):
  108. """Schema for batch adding queue items to a project."""
  109. queue_item_ids: list[int]
  110. # Phase 7: BOM Schemas - Tracks sourced/purchased parts
  111. class BOMItemCreate(BaseModel):
  112. """Schema for creating a BOM item."""
  113. name: str
  114. quantity_needed: int = 1
  115. unit_price: float | None = None
  116. sourcing_url: str | None = None
  117. archive_id: int | None = None
  118. stl_filename: str | None = None
  119. remarks: str | None = None
  120. class BOMItemUpdate(BaseModel):
  121. """Schema for updating a BOM item."""
  122. name: str | None = None
  123. quantity_needed: int | None = None
  124. quantity_acquired: int | None = None
  125. unit_price: float | None = None
  126. sourcing_url: str | None = None
  127. archive_id: int | None = None
  128. stl_filename: str | None = None
  129. remarks: str | None = None
  130. class BOMItemResponse(BaseModel):
  131. """Schema for BOM item response."""
  132. id: int
  133. project_id: int
  134. name: str
  135. quantity_needed: int
  136. quantity_acquired: int
  137. unit_price: float | None
  138. sourcing_url: str | None
  139. archive_id: int | None
  140. archive_name: str | None = None
  141. stl_filename: str | None
  142. remarks: str | None
  143. sort_order: int
  144. is_complete: bool = False
  145. created_at: datetime
  146. updated_at: datetime
  147. class Config:
  148. from_attributes = True
  149. # Phase 9: Timeline Schemas
  150. class TimelineEvent(BaseModel):
  151. """Schema for a timeline event."""
  152. event_type: str # archive_added, queue_started, queue_completed, status_changed, note_updated
  153. timestamp: datetime
  154. title: str
  155. description: str | None = None
  156. metadata: dict | None = None # Additional event-specific data