from fastapi import APIRouter, Depends, HTTPException, Request from typing import List, Optional import db import schemas import auth_utils import json from dependencies import require_admin from services.audit_service import audit_service router = APIRouter(tags=["catalog"]) @router.get("/materials", response_model=List[schemas.MaterialBase]) async def get_materials(): # Get active materials materials = db.execute_query("SELECT * FROM materials WHERE is_active = TRUE") # Get active stock stock = db.execute_query("SELECT material_id, color_name FROM warehouse_stock WHERE is_active = TRUE") # Map colors to materials color_map = {} for s in stock: m_id = s['material_id'] if m_id not in color_map: color_map[m_id] = [] color_map[m_id].append(s['color_name']) # Filter and attach colors result = [] for m in materials: m['available_colors'] = color_map.get(m['id'], []) # Only show on site if there are available colors in warehouse if m['available_colors']: result.append(m) return result @router.get("/services", response_model=List[schemas.ServiceBase]) async def get_services(): return db.execute_query("SELECT * FROM services WHERE is_active = TRUE") @router.get("/admin/materials", response_model=List[schemas.MaterialBase]) async def admin_get_materials(admin: dict = Depends(require_admin)): # Get all materials materials = db.execute_query("SELECT * FROM materials ORDER BY id DESC") # Get stock (including inactive for admin) stock = db.execute_query("SELECT material_id, color_name FROM warehouse_stock") color_map = {} for s in stock: m_id = s['material_id'] if m_id not in color_map: color_map[m_id] = [] color_map[m_id].append(s['color_name']) for m in materials: # Merge warehouse colors with any legacy colors in available_colors legacy_colors = [] if m.get('available_colors') and isinstance(m['available_colors'], str): try: legacy_colors = json.loads(m['available_colors']) except: pass # Priority to warehouse colors warehouse_colors = color_map.get(m['id'], []) # Combine them (unique) m['available_colors'] = list(set(warehouse_colors + (legacy_colors or []))) return materials @router.post("/admin/materials") async def admin_create_material(request: Request, data: schemas.MaterialCreate, admin: dict = Depends(require_admin)): colors_json = json.dumps(data.available_colors) if data.available_colors else None 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)" 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) mat_id = db.execute_commit(query, params) await audit_service.log( user_id=admin.get("id"), action="create_material", target_type="material", target_id=mat_id, details=data.dict(), request=request ) return {"id": mat_id} @router.patch("/admin/materials/{mat_id}") async def admin_update_material(request: Request, mat_id: int, data: schemas.MaterialUpdate, admin: dict = Depends(require_admin)): update_fields = [] params = [] for field, value in data.dict(exclude_unset=True).items(): update_fields.append(f"{field} = %s") if isinstance(value, list): params.append(json.dumps(value)) else: params.append(value) if update_fields: query = f"UPDATE materials SET {', '.join(update_fields)} WHERE id = %s" params.append(mat_id) db.execute_commit(query, tuple(params)) await audit_service.log( user_id=admin.get("id"), action="update_material", target_type="material", target_id=mat_id, details={"updated_fields": data.dict(exclude_unset=True)}, request=request ) return {"id": mat_id} @router.get("/admin/services", response_model=List[schemas.ServiceBase]) async def admin_get_services(admin: dict = Depends(require_admin)): return db.execute_query("SELECT * FROM services ORDER BY id DESC") @router.post("/admin/services") async def admin_create_service(request: Request, data: schemas.ServiceCreate, admin: dict = Depends(require_admin)): 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)" 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)) await audit_service.log( user_id=admin.get("id"), action="create_service", target_type="service", target_id=srv_id, details=data.dict(), request=request ) return {"id": srv_id} @router.patch("/admin/services/{srv_id}") async def admin_update_service(request: Request, srv_id: int, data: schemas.ServiceUpdate, admin: dict = Depends(require_admin)): update_fields = [] params = [] for field, value in data.dict(exclude_unset=True).items(): update_fields.append(f"{field} = %s") if isinstance(value, list): params.append(json.dumps(value)) else: params.append(value) if update_fields: query = f"UPDATE services SET {', '.join(update_fields)} WHERE id = %s" params.append(srv_id) db.execute_commit(query, tuple(params)) await audit_service.log( user_id=admin.get("id"), action="update_service", target_type="service", target_id=srv_id, details={"updated_fields": data.dict(exclude_unset=True)}, request=request ) return {"id": srv_id} @router.delete("/admin/materials/{mat_id}") async def admin_delete_material(request: Request, mat_id: int, admin: dict = Depends(require_admin)): db.execute_commit("DELETE FROM materials WHERE id = %s", (mat_id,)) await audit_service.log( user_id=admin.get("id"), action="delete_material", target_type="material", target_id=mat_id, request=request ) return {"id": mat_id, "status": "deleted"} @router.delete("/admin/services/{srv_id}") async def admin_delete_service(request: Request, srv_id: int, admin: dict = Depends(require_admin)): db.execute_commit("DELETE FROM services WHERE id = %s", (srv_id,)) await audit_service.log( user_id=admin.get("id"), action="delete_service", target_type="service", target_id=srv_id, request=request ) return {"id": srv_id, "status": "deleted"}