project.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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. target_parts_count: int | None = None
  10. notes: str | None = None
  11. tags: str | None = None
  12. due_date: datetime | None = None
  13. priority: str = "normal"
  14. budget: float | None = None
  15. parent_id: int | None = None # For sub-projects
  16. class ProjectUpdate(BaseModel):
  17. """Schema for updating a project."""
  18. name: str | None = None
  19. description: str | None = None
  20. color: str | None = None
  21. status: str | None = None # active, completed, archived
  22. target_count: int | None = None
  23. target_parts_count: int | None = None
  24. notes: str | None = None
  25. tags: str | None = None
  26. due_date: datetime | None = None
  27. priority: str | None = None
  28. budget: float | None = None
  29. parent_id: int | None = None
  30. class ProjectStats(BaseModel):
  31. """Statistics for a project."""
  32. total_archives: int = 0 # Number of archive records
  33. total_items: int = 0 # Sum of quantities (total items printed)
  34. completed_prints: int = 0 # Sum of quantities for completed prints
  35. failed_prints: int = 0 # Sum of quantities for failed prints
  36. queued_prints: int = 0
  37. in_progress_prints: int = 0
  38. total_print_time_hours: float = 0.0
  39. total_filament_grams: float = 0.0
  40. progress_percent: float | None = None # Based on target_count (plates)
  41. parts_progress_percent: float | None = None # Based on target_parts_count
  42. # Cost tracking (Phase 6)
  43. estimated_cost: float = 0.0 # Based on filament cost
  44. total_energy_kwh: float = 0.0
  45. total_energy_cost: float = 0.0
  46. remaining_prints: int | None = None # target_count - total_archives
  47. remaining_parts: int | None = None # target_parts_count - completed_prints
  48. # BOM stats (Phase 7)
  49. bom_total_items: int = 0
  50. bom_completed_items: int = 0
  51. bom_cost: float = 0.0 # Total cost of BOM items (sum of unit_price * quantity_needed)
  52. class ProjectChildPreview(BaseModel):
  53. """Minimal project data for child preview."""
  54. id: int
  55. name: str
  56. color: str | None
  57. status: str
  58. progress_percent: float | None = None
  59. class ProjectResponse(BaseModel):
  60. """Schema for project response."""
  61. id: int
  62. name: str
  63. description: str | None
  64. color: str | None
  65. status: str
  66. target_count: int | None
  67. target_parts_count: int | None = None
  68. notes: str | None = None
  69. attachments: list | None = None
  70. tags: str | None = None
  71. due_date: datetime | None = None
  72. priority: str = "normal"
  73. budget: float | None = None
  74. is_template: bool = False
  75. template_source_id: int | None = None
  76. parent_id: int | None = None
  77. parent_name: str | None = None # For display
  78. children: list[ProjectChildPreview] = []
  79. created_at: datetime
  80. updated_at: datetime
  81. stats: ProjectStats | None = None
  82. class Config:
  83. from_attributes = True
  84. class ArchivePreview(BaseModel):
  85. """Minimal archive data for project preview."""
  86. id: int
  87. print_name: str | None
  88. thumbnail_path: str | None
  89. status: str
  90. filament_type: str | None = None
  91. filament_color: str | None = None
  92. class ProjectListResponse(BaseModel):
  93. """Schema for project list item (lighter weight)."""
  94. id: int
  95. name: str
  96. description: str | None
  97. color: str | None
  98. status: str
  99. target_count: int | None
  100. target_parts_count: int | None = None
  101. budget: float | None = None
  102. created_at: datetime
  103. # Quick stats
  104. archive_count: int = 0 # Number of print jobs
  105. total_items: int = 0 # Sum of quantities (total items printed, including failed)
  106. completed_count: int = 0 # Sum of quantities for completed prints only
  107. failed_count: int = 0 # Sum of quantities for failed prints
  108. queue_count: int = 0
  109. progress_percent: float | None = None
  110. # Preview of archives (up to 5)
  111. archives: list[ArchivePreview] = []
  112. class Config:
  113. from_attributes = True
  114. class BatchAddArchives(BaseModel):
  115. """Schema for batch adding archives to a project."""
  116. archive_ids: list[int]
  117. class BatchAddQueueItems(BaseModel):
  118. """Schema for batch adding queue items to a project."""
  119. queue_item_ids: list[int]
  120. # Phase 7: BOM Schemas - Tracks sourced/purchased parts
  121. class BOMItemCreate(BaseModel):
  122. """Schema for creating a BOM item."""
  123. name: str
  124. quantity_needed: int = 1
  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 BOMItemUpdate(BaseModel):
  131. """Schema for updating a BOM item."""
  132. name: str | None = None
  133. quantity_needed: int | None = None
  134. quantity_acquired: int | None = None
  135. unit_price: float | None = None
  136. sourcing_url: str | None = None
  137. archive_id: int | None = None
  138. stl_filename: str | None = None
  139. remarks: str | None = None
  140. class BOMItemResponse(BaseModel):
  141. """Schema for BOM item response."""
  142. id: int
  143. project_id: int
  144. name: str
  145. quantity_needed: int
  146. quantity_acquired: int
  147. unit_price: float | None
  148. sourcing_url: str | None
  149. archive_id: int | None
  150. archive_name: str | None = None
  151. stl_filename: str | None
  152. remarks: str | None
  153. sort_order: int
  154. is_complete: bool = False
  155. created_at: datetime
  156. updated_at: datetime
  157. class Config:
  158. from_attributes = True
  159. # Phase 9: Timeline Schemas
  160. class TimelineEvent(BaseModel):
  161. """Schema for a timeline event."""
  162. event_type: str # archive_added, queue_started, queue_completed, status_changed, note_updated
  163. timestamp: datetime
  164. title: str
  165. description: str | None = None
  166. metadata: dict | None = None # Additional event-specific data
  167. # Phase 10: Import/Export Schemas
  168. class BOMItemExport(BaseModel):
  169. """Schema for exporting a BOM item."""
  170. name: str
  171. quantity_needed: int
  172. quantity_acquired: int
  173. unit_price: float | None
  174. sourcing_url: str | None
  175. stl_filename: str | None
  176. remarks: str | None
  177. class LinkedFolderExport(BaseModel):
  178. """Schema for exporting a linked library folder."""
  179. name: str
  180. class ProjectExport(BaseModel):
  181. """Schema for exporting a project."""
  182. name: str
  183. description: str | None
  184. color: str | None
  185. status: str
  186. target_count: int | None
  187. target_parts_count: int | None
  188. notes: str | None
  189. tags: str | None
  190. due_date: datetime | None
  191. priority: str
  192. budget: float | None
  193. bom_items: list[BOMItemExport] = []
  194. linked_folders: list[LinkedFolderExport] = []
  195. class ProjectImport(BaseModel):
  196. """Schema for importing a project."""
  197. name: str
  198. description: str | None = None
  199. color: str | None = None
  200. status: str = "active"
  201. target_count: int | None = None
  202. target_parts_count: int | None = None
  203. notes: str | None = None
  204. tags: str | None = None
  205. due_date: datetime | None = None
  206. priority: str = "normal"
  207. budget: float | None = None
  208. bom_items: list[BOMItemExport] = []
  209. linked_folders: list[LinkedFolderExport] = []