warehouse.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. from fastapi import APIRouter, Depends, HTTPException, Query, Request
  2. from typing import List, Optional
  3. import db
  4. import schemas
  5. from dependencies import require_admin
  6. import services.event_hooks as event_hooks
  7. from services.audit_service import audit_service
  8. from services.warehouse_report_service import warehouse_report_service
  9. router = APIRouter(prefix="/admin/warehouse", tags=["warehouse"])
  10. @router.get("/report")
  11. async def generate_stock_report(
  12. admin: dict = Depends(require_admin)
  13. ):
  14. url = warehouse_report_service.generate_report()
  15. return {"url": url}
  16. @router.get("/stock", response_model=dict)
  17. async def get_warehouse_stock(
  18. page: int = Query(1, ge=1),
  19. size: int = Query(50, ge=1, le=100),
  20. material_id: Optional[int] = None,
  21. admin: dict = Depends(require_admin)
  22. ):
  23. offset = (page - 1) * size
  24. query = """
  25. SELECT w.*, m.name_en as material_name_en
  26. FROM warehouse_stock w
  27. JOIN materials m ON w.material_id = m.id
  28. """
  29. params = []
  30. if material_id:
  31. query += " WHERE w.material_id = %s"
  32. params.append(material_id)
  33. query += " ORDER BY w.created_at DESC LIMIT %s OFFSET %s"
  34. params.extend([size, offset])
  35. stock = db.execute_query(query, tuple(params))
  36. count_query = "SELECT COUNT(*) as total FROM warehouse_stock"
  37. if material_id:
  38. count_query += " WHERE material_id = %s"
  39. total_res = db.execute_query(count_query, (material_id,))
  40. else:
  41. total_res = db.execute_query(count_query)
  42. return {
  43. "stock": stock,
  44. "total": total_res[0]['total'] if total_res else 0,
  45. "page": page,
  46. "size": size
  47. }
  48. @router.post("/stock", response_model=dict)
  49. async def add_stock_item(
  50. request: Request,
  51. data: schemas.WarehouseItemCreate,
  52. admin: dict = Depends(require_admin)
  53. ):
  54. query = """
  55. INSERT INTO warehouse_stock (material_id, color_name, quantity, unit_mass, units_count, notes, is_active)
  56. VALUES (%s, %s, %s, %s, %s, %s, %s)
  57. """
  58. params = (data.material_id, data.color_name, data.quantity, data.unit_mass, data.units_count, data.notes, data.is_active)
  59. item_id = db.execute_commit(query, params)
  60. if not item_id:
  61. raise HTTPException(status_code=500, detail="Failed to add stock item")
  62. await audit_service.log(
  63. user_id=admin['id'],
  64. action="warehouse_add_item",
  65. target_type="warehouse_stock",
  66. target_id=item_id,
  67. details={
  68. "material_id": data.material_id,
  69. "color": data.color_name,
  70. "quantity": data.quantity,
  71. "units_count": data.units_count
  72. },
  73. request=request
  74. )
  75. return {"id": item_id, "message": "Stock item added successfully"}
  76. @router.patch("/stock/{item_id}", response_model=dict)
  77. async def update_stock_item(
  78. item_id: int,
  79. request: Request,
  80. data: schemas.WarehouseItemUpdate,
  81. admin: dict = Depends(require_admin)
  82. ):
  83. update_fields = []
  84. params = []
  85. if data.quantity is not None:
  86. update_fields.append("quantity = %s")
  87. params.append(data.quantity)
  88. if data.unit_mass is not None:
  89. update_fields.append("unit_mass = %s")
  90. params.append(data.unit_mass)
  91. if data.units_count is not None:
  92. update_fields.append("units_count = %s")
  93. params.append(data.units_count)
  94. if data.notes is not None:
  95. update_fields.append("notes = %s")
  96. params.append(data.notes)
  97. if data.is_active is not None:
  98. update_fields.append("is_active = %s")
  99. params.append(data.is_active)
  100. if not update_fields:
  101. raise HTTPException(status_code=400, detail="No fields to update")
  102. query = f"UPDATE warehouse_stock SET {', '.join(update_fields)} WHERE id = %s"
  103. params.append(item_id)
  104. db.execute_commit(query, tuple(params))
  105. await audit_service.log(
  106. user_id=admin['id'],
  107. action="warehouse_update_item",
  108. target_type="warehouse_stock",
  109. target_id=item_id,
  110. details=data.model_dump(exclude_unset=True),
  111. request=request
  112. )
  113. return {"message": "Stock item updated successfully"}
  114. @router.delete("/stock/{item_id}", response_model=dict)
  115. async def delete_stock_item(
  116. item_id: int,
  117. request: Request,
  118. admin: dict = Depends(require_admin)
  119. ):
  120. # Fetch item before deleting for logs
  121. item = db.execute_query("SELECT material_id, color_name FROM warehouse_stock WHERE id = %s", (item_id,))
  122. query = "DELETE FROM warehouse_stock WHERE id = %s"
  123. db.execute_commit(query, (item_id,))
  124. if item:
  125. await audit_service.log(
  126. user_id=admin['id'],
  127. action="warehouse_delete_item",
  128. target_type="warehouse_stock",
  129. target_id=item_id,
  130. details=item[0],
  131. request=request
  132. )
  133. return {"message": "Stock item deleted successfully"}