print_queue.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. from datetime import datetime
  2. from typing import Annotated, Literal
  3. from pydantic import BaseModel, PlainSerializer
  4. # Custom serializer to ensure UTC datetimes have Z suffix
  5. def serialize_utc_datetime(dt: datetime | None) -> str | None:
  6. if dt is None:
  7. return None
  8. # Add Z suffix to indicate UTC
  9. return dt.isoformat() + "Z"
  10. UTCDatetime = Annotated[datetime | None, PlainSerializer(serialize_utc_datetime)]
  11. class PrintQueueItemCreate(BaseModel):
  12. printer_id: int | None = None # None = unassigned, user assigns later
  13. target_model: str | None = None # Target printer model (mutually exclusive with printer_id)
  14. target_location: str | None = None # Target location filter (only used with target_model)
  15. required_filament_types: list[str] | None = None # Required filament types for model-based assignment
  16. filament_overrides: list[dict] | None = None # Filament overrides for model-based assignment
  17. # Either archive_id OR library_file_id must be provided
  18. archive_id: int | None = None
  19. library_file_id: int | None = None
  20. scheduled_time: datetime | None = None # None = ASAP (next when idle)
  21. require_previous_success: bool = False
  22. auto_off_after: bool = False # Power off printer after print completes
  23. manual_start: bool = False # Requires manual trigger to start (staged)
  24. # AMS mapping: list of global tray IDs for each filament slot
  25. # Format: [5, -1, 2, -1] where position = slot_id-1, value = global tray ID (-1 = unused)
  26. ams_mapping: list[int] | None = None
  27. # Plate ID for multi-plate 3MF files (1-indexed, None = auto-detect/plate 1)
  28. plate_id: int | None = None
  29. # Print options
  30. bed_levelling: bool = True
  31. flow_cali: bool = False
  32. vibration_cali: bool = True
  33. layer_inspect: bool = False
  34. timelapse: bool = False
  35. use_ams: bool = True
  36. # Auto-print G-code injection
  37. gcode_injection: bool = False
  38. # Batch: create multiple copies (creates a batch if > 1)
  39. quantity: int = 1
  40. # Project to associate the resulting archive with
  41. project_id: int | None = None
  42. class PrintQueueItemUpdate(BaseModel):
  43. printer_id: int | None = None
  44. target_model: str | None = None # Target printer model (mutually exclusive with printer_id)
  45. target_location: str | None = None # Target location filter (only used with target_model)
  46. filament_overrides: list[dict] | None = None # Filament overrides for model-based assignment
  47. position: int | None = None
  48. scheduled_time: datetime | None = None
  49. require_previous_success: bool | None = None
  50. auto_off_after: bool | None = None
  51. manual_start: bool | None = None
  52. ams_mapping: list[int] | None = None
  53. plate_id: int | None = None
  54. # Print options
  55. bed_levelling: bool | None = None
  56. flow_cali: bool | None = None
  57. vibration_cali: bool | None = None
  58. layer_inspect: bool | None = None
  59. timelapse: bool | None = None
  60. use_ams: bool | None = None
  61. # Auto-print G-code injection
  62. gcode_injection: bool | None = None
  63. class PrintQueueItemResponse(BaseModel):
  64. id: int
  65. printer_id: int | None # None = unassigned
  66. target_model: str | None = None # Target printer model for model-based assignment
  67. target_location: str | None = None # Target location filter for model-based assignment
  68. required_filament_types: list[str] | None = None # Required filament types for model-based assignment
  69. filament_overrides: list[dict] | None = None # Filament overrides for model-based assignment
  70. waiting_reason: str | None = None # Why a model-based job hasn't started yet
  71. archive_id: int | None # None if library_file_id is set (archive created at print start)
  72. library_file_id: int | None # For queue items from library files
  73. position: int
  74. scheduled_time: UTCDatetime
  75. require_previous_success: bool
  76. auto_off_after: bool
  77. manual_start: bool
  78. ams_mapping: list[int] | None = None
  79. plate_id: int | None = None # Plate ID for multi-plate 3MF files
  80. # Print options
  81. bed_levelling: bool = True
  82. flow_cali: bool = False
  83. vibration_cali: bool = True
  84. layer_inspect: bool = False
  85. timelapse: bool = False
  86. use_ams: bool = True
  87. status: Literal["pending", "printing", "completed", "failed", "skipped", "cancelled"]
  88. started_at: UTCDatetime
  89. completed_at: UTCDatetime
  90. error_message: str | None
  91. created_at: UTCDatetime
  92. # Nested info for UI (populated in route)
  93. archive_name: str | None = None
  94. archive_thumbnail: str | None = None
  95. library_file_name: str | None = None # Name of library file (if library_file_id is set)
  96. library_file_thumbnail: str | None = None # Thumbnail of library file
  97. printer_name: str | None = None
  98. print_time_seconds: int | None = None # Estimated print time from archive or library file
  99. filament_used_grams: float | None = None # Estimated print weight from archive or library file
  100. filament_type: str | None = None # e.g. "PLA", "PETG" (from archive/library file)
  101. filament_color: str | None = None # e.g. "#FFFFFF" (from archive/library file)
  102. layer_height: float | None = None # e.g. 0.2 (from archive/library file)
  103. nozzle_diameter: float | None = None # e.g. 0.4 (from archive/library file)
  104. sliced_for_model: str | None = None # e.g. "P1S" (from archive/library file)
  105. # User tracking (Issue #206)
  106. created_by_id: int | None = None
  107. created_by_username: str | None = None
  108. # Batch grouping
  109. batch_id: int | None = None
  110. batch_name: str | None = None
  111. # Shortest-job-first scheduling
  112. been_jumped: bool = False
  113. # Auto-print G-code injection
  114. gcode_injection: bool = False
  115. class Config:
  116. from_attributes = True
  117. class PrintQueueReorderItem(BaseModel):
  118. id: int
  119. position: int
  120. class PrintQueueReorder(BaseModel):
  121. items: list[PrintQueueReorderItem]
  122. class PrintQueueBulkUpdate(BaseModel):
  123. """Bulk update multiple queue items with the same values."""
  124. item_ids: list[int]
  125. # Fields to update (all optional - only set fields are applied)
  126. printer_id: int | None = None
  127. scheduled_time: datetime | None = None
  128. require_previous_success: bool | None = None
  129. auto_off_after: bool | None = None
  130. manual_start: bool | None = None
  131. # Print options
  132. bed_levelling: bool | None = None
  133. flow_cali: bool | None = None
  134. vibration_cali: bool | None = None
  135. layer_inspect: bool | None = None
  136. timelapse: bool | None = None
  137. use_ams: bool | None = None
  138. # Auto-print G-code injection
  139. gcode_injection: bool | None = None
  140. class PrintQueueBulkUpdateResponse(BaseModel):
  141. """Response for bulk update operation."""
  142. updated_count: int
  143. skipped_count: int # Items that were not pending
  144. message: str
  145. class PrintBatchResponse(BaseModel):
  146. """Response for a print batch with progress stats."""
  147. id: int
  148. name: str
  149. archive_id: int | None = None
  150. library_file_id: int | None = None
  151. quantity: int
  152. status: str
  153. created_at: UTCDatetime
  154. created_by_id: int | None = None
  155. created_by_username: str | None = None
  156. # Derived counts
  157. pending_count: int = 0
  158. printing_count: int = 0
  159. completed_count: int = 0
  160. failed_count: int = 0
  161. cancelled_count: int = 0
  162. class Config:
  163. from_attributes = True