catalog.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. from fastapi import APIRouter, Depends, HTTPException, Request
  2. from typing import List, Optional
  3. import db
  4. import schemas
  5. import auth_utils
  6. import json
  7. from dependencies import require_admin
  8. from services.audit_service import audit_service
  9. router = APIRouter(tags=["catalog"])
  10. @router.get("/materials", response_model=List[schemas.MaterialBase])
  11. async def get_materials():
  12. # Get active materials
  13. materials = db.execute_query("SELECT * FROM materials WHERE is_active = TRUE")
  14. # Get active stock
  15. stock = db.execute_query("SELECT material_id, color_name FROM warehouse_stock WHERE is_active = TRUE")
  16. # Map colors to materials
  17. color_map = {}
  18. for s in stock:
  19. m_id = s['material_id']
  20. if m_id not in color_map:
  21. color_map[m_id] = []
  22. color_map[m_id].append(s['color_name'])
  23. # Filter and attach colors
  24. result = []
  25. for m in materials:
  26. m['available_colors'] = color_map.get(m['id'], [])
  27. # Only show on site if there are available colors in warehouse
  28. if m['available_colors']:
  29. result.append(m)
  30. return result
  31. @router.get("/services", response_model=List[schemas.ServiceBase])
  32. async def get_services():
  33. return db.execute_query("SELECT * FROM services WHERE is_active = TRUE")
  34. @router.get("/admin/materials", response_model=List[schemas.MaterialBase])
  35. async def admin_get_materials(admin: dict = Depends(require_admin)):
  36. # Get all materials
  37. materials = db.execute_query("SELECT * FROM materials ORDER BY id DESC")
  38. # Get stock (including inactive for admin)
  39. stock = db.execute_query("SELECT material_id, color_name FROM warehouse_stock")
  40. color_map = {}
  41. for s in stock:
  42. m_id = s['material_id']
  43. if m_id not in color_map:
  44. color_map[m_id] = []
  45. color_map[m_id].append(s['color_name'])
  46. for m in materials:
  47. # Merge warehouse colors with any legacy colors in available_colors
  48. legacy_colors = []
  49. if m.get('available_colors') and isinstance(m['available_colors'], str):
  50. try: legacy_colors = json.loads(m['available_colors'])
  51. except: pass
  52. # Priority to warehouse colors
  53. warehouse_colors = color_map.get(m['id'], [])
  54. # Combine them (unique)
  55. m['available_colors'] = list(set(warehouse_colors + (legacy_colors or [])))
  56. return materials
  57. @router.post("/admin/materials")
  58. async def admin_create_material(request: Request, data: schemas.MaterialCreate, admin: dict = Depends(require_admin)):
  59. colors_json = json.dumps(data.available_colors) if data.available_colors else None
  60. query = "INSERT INTO materials (name_en, name_ru, name_ua, name_me, desc_en, desc_ru, desc_ua, desc_me, long_desc_en, long_desc_ru, long_desc_ua, long_desc_me, price_per_cm3, available_colors, is_active) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
  61. params = (data.name_en, data.name_ru, data.name_ua, data.name_me, data.desc_en, data.desc_ru, data.desc_ua, data.desc_me, data.long_desc_en, data.long_desc_ru, data.long_desc_ua, data.long_desc_me, data.price_per_cm3, colors_json, data.is_active)
  62. mat_id = db.execute_commit(query, params)
  63. await audit_service.log(
  64. user_id=admin.get("id"),
  65. action="create_material",
  66. target_type="material",
  67. target_id=mat_id,
  68. details=data.dict(),
  69. request=request
  70. )
  71. return {"id": mat_id}
  72. @router.patch("/admin/materials/{mat_id}")
  73. async def admin_update_material(request: Request, mat_id: int, data: schemas.MaterialUpdate, admin: dict = Depends(require_admin)):
  74. update_fields = []
  75. params = []
  76. for field, value in data.dict(exclude_unset=True).items():
  77. update_fields.append(f"{field} = %s")
  78. if isinstance(value, list):
  79. params.append(json.dumps(value))
  80. else:
  81. params.append(value)
  82. if update_fields:
  83. query = f"UPDATE materials SET {', '.join(update_fields)} WHERE id = %s"
  84. params.append(mat_id)
  85. db.execute_commit(query, tuple(params))
  86. await audit_service.log(
  87. user_id=admin.get("id"),
  88. action="update_material",
  89. target_type="material",
  90. target_id=mat_id,
  91. details={"updated_fields": data.dict(exclude_unset=True)},
  92. request=request
  93. )
  94. return {"id": mat_id}
  95. @router.get("/admin/services", response_model=List[schemas.ServiceBase])
  96. async def admin_get_services(admin: dict = Depends(require_admin)):
  97. return db.execute_query("SELECT * FROM services ORDER BY id DESC")
  98. @router.post("/admin/services")
  99. async def admin_create_service(request: Request, data: schemas.ServiceCreate, admin: dict = Depends(require_admin)):
  100. query = "INSERT INTO services (name_en, name_ru, name_ua, name_me, desc_en, desc_ru, desc_ua, desc_me, tech_type, is_active) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
  101. srv_id = db.execute_commit(query, (data.name_en, data.name_ru, data.name_ua, data.name_me, data.desc_en, data.desc_ru, data.desc_ua, data.desc_me, data.tech_type, data.is_active))
  102. await audit_service.log(
  103. user_id=admin.get("id"),
  104. action="create_service",
  105. target_type="service",
  106. target_id=srv_id,
  107. details=data.dict(),
  108. request=request
  109. )
  110. return {"id": srv_id}
  111. @router.patch("/admin/services/{srv_id}")
  112. async def admin_update_service(request: Request, srv_id: int, data: schemas.ServiceUpdate, admin: dict = Depends(require_admin)):
  113. update_fields = []
  114. params = []
  115. for field, value in data.dict(exclude_unset=True).items():
  116. update_fields.append(f"{field} = %s")
  117. if isinstance(value, list):
  118. params.append(json.dumps(value))
  119. else:
  120. params.append(value)
  121. if update_fields:
  122. query = f"UPDATE services SET {', '.join(update_fields)} WHERE id = %s"
  123. params.append(srv_id)
  124. db.execute_commit(query, tuple(params))
  125. await audit_service.log(
  126. user_id=admin.get("id"),
  127. action="update_service",
  128. target_type="service",
  129. target_id=srv_id,
  130. details={"updated_fields": data.dict(exclude_unset=True)},
  131. request=request
  132. )
  133. return {"id": srv_id}
  134. @router.delete("/admin/materials/{mat_id}")
  135. async def admin_delete_material(request: Request, mat_id: int, admin: dict = Depends(require_admin)):
  136. db.execute_commit("DELETE FROM materials WHERE id = %s", (mat_id,))
  137. await audit_service.log(
  138. user_id=admin.get("id"),
  139. action="delete_material",
  140. target_type="material",
  141. target_id=mat_id,
  142. request=request
  143. )
  144. return {"id": mat_id, "status": "deleted"}
  145. @router.delete("/admin/services/{srv_id}")
  146. async def admin_delete_service(request: Request, srv_id: int, admin: dict = Depends(require_admin)):
  147. db.execute_commit("DELETE FROM services WHERE id = %s", (srv_id,))
  148. await audit_service.log(
  149. user_id=admin.get("id"),
  150. action="delete_service",
  151. target_type="service",
  152. target_id=srv_id,
  153. request=request
  154. )
  155. return {"id": srv_id, "status": "deleted"}