filaments.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. from fastapi import APIRouter, Depends, HTTPException
  2. from sqlalchemy import select
  3. from sqlalchemy.ext.asyncio import AsyncSession
  4. from backend.app.core.auth import RequirePermissionIfAuthEnabled
  5. from backend.app.core.database import get_db
  6. from backend.app.core.permissions import Permission
  7. from backend.app.models.filament import Filament
  8. from backend.app.models.user import User
  9. from backend.app.schemas.filament import (
  10. FilamentCostCalculation,
  11. FilamentCreate,
  12. FilamentResponse,
  13. FilamentUpdate,
  14. )
  15. router = APIRouter(prefix="/filament-catalog", tags=["filament-catalog"])
  16. @router.get("/", response_model=list[FilamentResponse])
  17. async def list_filaments(
  18. db: AsyncSession = Depends(get_db),
  19. _: User | None = RequirePermissionIfAuthEnabled(Permission.FILAMENTS_READ),
  20. ):
  21. """List all filaments."""
  22. result = await db.execute(select(Filament).order_by(Filament.type, Filament.name))
  23. return list(result.scalars().all())
  24. @router.post("/", response_model=FilamentResponse)
  25. async def create_filament(
  26. filament_data: FilamentCreate,
  27. db: AsyncSession = Depends(get_db),
  28. _: User | None = RequirePermissionIfAuthEnabled(Permission.FILAMENTS_CREATE),
  29. ):
  30. """Create a new filament entry."""
  31. filament = Filament(**filament_data.model_dump())
  32. db.add(filament)
  33. await db.commit()
  34. await db.refresh(filament)
  35. return filament
  36. @router.get("/{filament_id}", response_model=FilamentResponse)
  37. async def get_filament(
  38. filament_id: int,
  39. db: AsyncSession = Depends(get_db),
  40. _: User | None = RequirePermissionIfAuthEnabled(Permission.FILAMENTS_READ),
  41. ):
  42. """Get a specific filament."""
  43. result = await db.execute(select(Filament).where(Filament.id == filament_id))
  44. filament = result.scalar_one_or_none()
  45. if not filament:
  46. raise HTTPException(404, "Filament not found")
  47. return filament
  48. @router.patch("/{filament_id}", response_model=FilamentResponse)
  49. async def update_filament(
  50. filament_id: int,
  51. filament_data: FilamentUpdate,
  52. db: AsyncSession = Depends(get_db),
  53. _: User | None = RequirePermissionIfAuthEnabled(Permission.FILAMENTS_UPDATE),
  54. ):
  55. """Update a filament."""
  56. result = await db.execute(select(Filament).where(Filament.id == filament_id))
  57. filament = result.scalar_one_or_none()
  58. if not filament:
  59. raise HTTPException(404, "Filament not found")
  60. for field, value in filament_data.model_dump(exclude_unset=True).items():
  61. setattr(filament, field, value)
  62. await db.commit()
  63. await db.refresh(filament)
  64. return filament
  65. @router.delete("/{filament_id}")
  66. async def delete_filament(
  67. filament_id: int,
  68. db: AsyncSession = Depends(get_db),
  69. _: User | None = RequirePermissionIfAuthEnabled(Permission.FILAMENTS_DELETE),
  70. ):
  71. """Delete a filament."""
  72. result = await db.execute(select(Filament).where(Filament.id == filament_id))
  73. filament = result.scalar_one_or_none()
  74. if not filament:
  75. raise HTTPException(404, "Filament not found")
  76. await db.delete(filament)
  77. await db.commit()
  78. return {"status": "deleted"}
  79. @router.post("/calculate-cost", response_model=FilamentCostCalculation)
  80. async def calculate_cost(
  81. filament_id: int,
  82. weight_grams: float,
  83. db: AsyncSession = Depends(get_db),
  84. _: User | None = RequirePermissionIfAuthEnabled(Permission.FILAMENTS_READ),
  85. ):
  86. """Calculate the cost for a given weight of filament."""
  87. result = await db.execute(select(Filament).where(Filament.id == filament_id))
  88. filament = result.scalar_one_or_none()
  89. if not filament:
  90. raise HTTPException(404, "Filament not found")
  91. cost = (weight_grams / 1000) * filament.cost_per_kg
  92. return FilamentCostCalculation(
  93. filament_id=filament.id,
  94. filament_name=filament.name,
  95. weight_grams=weight_grams,
  96. cost=round(cost, 2),
  97. currency=filament.currency,
  98. )
  99. @router.get("/by-type/{filament_type}", response_model=list[FilamentResponse])
  100. async def get_filaments_by_type(
  101. filament_type: str,
  102. db: AsyncSession = Depends(get_db),
  103. _: User | None = RequirePermissionIfAuthEnabled(Permission.FILAMENTS_READ),
  104. ):
  105. """Get all filaments of a specific type."""
  106. result = await db.execute(select(Filament).where(Filament.type.ilike(f"%{filament_type}%")).order_by(Filament.name))
  107. return list(result.scalars().all())
  108. @router.post("/seed-defaults")
  109. async def seed_default_filaments(
  110. db: AsyncSession = Depends(get_db),
  111. _: User | None = RequirePermissionIfAuthEnabled(Permission.FILAMENTS_CREATE),
  112. ):
  113. """Seed the database with common filament types."""
  114. defaults = [
  115. {
  116. "name": "Generic PLA",
  117. "type": "PLA",
  118. "cost_per_kg": 20.0,
  119. "print_temp_min": 190,
  120. "print_temp_max": 220,
  121. "bed_temp_min": 50,
  122. "bed_temp_max": 60,
  123. "density": 1.24,
  124. },
  125. {
  126. "name": "Generic PETG",
  127. "type": "PETG",
  128. "cost_per_kg": 25.0,
  129. "print_temp_min": 230,
  130. "print_temp_max": 250,
  131. "bed_temp_min": 70,
  132. "bed_temp_max": 80,
  133. "density": 1.27,
  134. },
  135. {
  136. "name": "Generic ABS",
  137. "type": "ABS",
  138. "cost_per_kg": 22.0,
  139. "print_temp_min": 230,
  140. "print_temp_max": 260,
  141. "bed_temp_min": 90,
  142. "bed_temp_max": 110,
  143. "density": 1.04,
  144. },
  145. {
  146. "name": "Generic TPU",
  147. "type": "TPU",
  148. "cost_per_kg": 35.0,
  149. "print_temp_min": 220,
  150. "print_temp_max": 250,
  151. "bed_temp_min": 40,
  152. "bed_temp_max": 60,
  153. "density": 1.21,
  154. },
  155. {
  156. "name": "Generic ASA",
  157. "type": "ASA",
  158. "cost_per_kg": 28.0,
  159. "print_temp_min": 240,
  160. "print_temp_max": 260,
  161. "bed_temp_min": 90,
  162. "bed_temp_max": 110,
  163. "density": 1.07,
  164. },
  165. {
  166. "name": "Bambu PLA Basic",
  167. "type": "PLA",
  168. "brand": "Bambu Lab",
  169. "cost_per_kg": 20.0,
  170. "print_temp_min": 190,
  171. "print_temp_max": 220,
  172. "bed_temp_min": 35,
  173. "bed_temp_max": 55,
  174. "density": 1.24,
  175. },
  176. {
  177. "name": "Bambu PLA Matte",
  178. "type": "PLA",
  179. "brand": "Bambu Lab",
  180. "cost_per_kg": 25.0,
  181. "print_temp_min": 190,
  182. "print_temp_max": 220,
  183. "bed_temp_min": 35,
  184. "bed_temp_max": 55,
  185. "density": 1.24,
  186. },
  187. {
  188. "name": "Bambu PETG Basic",
  189. "type": "PETG",
  190. "brand": "Bambu Lab",
  191. "cost_per_kg": 25.0,
  192. "print_temp_min": 250,
  193. "print_temp_max": 270,
  194. "bed_temp_min": 70,
  195. "bed_temp_max": 80,
  196. "density": 1.27,
  197. },
  198. {
  199. "name": "Bambu ABS",
  200. "type": "ABS",
  201. "brand": "Bambu Lab",
  202. "cost_per_kg": 30.0,
  203. "print_temp_min": 260,
  204. "print_temp_max": 280,
  205. "bed_temp_min": 90,
  206. "bed_temp_max": 100,
  207. "density": 1.04,
  208. },
  209. ]
  210. created = 0
  211. for filament_data in defaults:
  212. # Check if already exists
  213. result = await db.execute(
  214. select(Filament).where(
  215. Filament.name == filament_data["name"],
  216. Filament.type == filament_data["type"],
  217. )
  218. )
  219. if result.scalar_one_or_none():
  220. continue
  221. filament = Filament(**filament_data)
  222. db.add(filament)
  223. created += 1
  224. await db.commit()
  225. return {"created": created, "message": f"Created {created} default filaments"}