import json from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form from sqlalchemy.orm import Session from sqlalchemy import desc from typing import List, Optional from datetime import datetime from database import get_db import models from auth import require_admin, require_manufacturer, get_current_user from utils import save_upload router = APIRouter(prefix="/api/improvements", tags=["improvements"]) def _fmt(imp: models.Improvement): return { "id": imp.id, "title": imp.title, "category": imp.category, "description": imp.description, "priority": imp.priority, "part_name": imp.part_name, "status": imp.status, "manufacturer_id": imp.manufacturer_id, "manufacturer_name": imp.manufacturer.name if imp.manufacturer else None, "manufacturer_company": imp.manufacturer.company if imp.manufacturer else None, "created_by_name": imp.creator.name if imp.creator else None, "sw_deploy_target": str(imp.sw_deploy_target) if imp.sw_deploy_target else None, "sw_deployed_at": str(imp.sw_deployed_at) if imp.sw_deployed_at else None, "manufacturer_memo": imp.manufacturer_memo, "created_at": imp.created_at.isoformat(), "report_ids": [ir.report_id for ir in imp.report_links], "report_count": len(imp.report_links), "attachments": [{"path": a.file_path, "name": a.file_name} for a in imp.attachments], "logs": [{"old": l.old_status, "new": l.new_status, "memo": l.memo, "changed_at": l.changed_at.isoformat(), "by": l.changer.name if l.changer else None} for l in imp.logs], } @router.get("") def list_improvements( status: Optional[str] = None, manufacturer_id: Optional[int] = None, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user) ): q = db.query(models.Improvement).order_by(desc(models.Improvement.created_at)) if current_user.role == "manufacturer": q = q.filter(models.Improvement.manufacturer_id == current_user.id) if status: q = q.filter(models.Improvement.status == status) if manufacturer_id: q = q.filter(models.Improvement.manufacturer_id == manufacturer_id) return [_fmt(imp) for imp in q.all()] @router.get("/{imp_id}") def get_improvement(imp_id: int, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user)): imp = db.query(models.Improvement).filter_by(id=imp_id).first() if not imp: raise HTTPException(404) if current_user.role == "manufacturer" and imp.manufacturer_id != current_user.id: raise HTTPException(403) return _fmt(imp) @router.post("") async def create_improvement( title: str = Form(...), category: str = Form(...), description: str = Form(...), priority: str = Form("normal"), part_name: str = Form(""), manufacturer_id: int = Form(...), report_ids: str = Form("[]"), sw_deploy_target: Optional[str] = Form(None), attachments: List[UploadFile] = File(default=[]), db: Session = Depends(get_db), current_user: models.User = Depends(require_admin) ): imp = models.Improvement( title=title, category=category, description=description, priority=priority, part_name=part_name or None, manufacturer_id=manufacturer_id, created_by=current_user.id, sw_deploy_target=sw_deploy_target or None, ) db.add(imp); db.commit(); db.refresh(imp) for rid in json.loads(report_ids): db.add(models.ImprovementReport(improvement_id=imp.id, report_id=int(rid))) for f in attachments: if f.filename: path = save_upload(f, f"improvements/{imp.id}") db.add(models.ImprovementAttachment(improvement_id=imp.id, file_path=path, file_name=f.filename)) db.add(models.ImprovementLog(improvement_id=imp.id, changed_by=current_user.id, old_status=None, new_status="registered", memo="개선항목 등록")) db.commit() return {"id": imp.id} @router.patch("/{imp_id}/status") def update_status( imp_id: int, status: str = Form(...), memo: str = Form(""), sw_deployed_at: Optional[str] = Form(None), manufacturer_memo: str = Form(""), db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user) ): imp = db.query(models.Improvement).filter_by(id=imp_id).first() if not imp: raise HTTPException(404) if current_user.role == "manufacturer" and imp.manufacturer_id != current_user.id: raise HTTPException(403) old_status = imp.status imp.status = status if sw_deployed_at: imp.sw_deployed_at = sw_deployed_at if manufacturer_memo: imp.manufacturer_memo = manufacturer_memo db.add(models.ImprovementLog(improvement_id=imp.id, changed_by=current_user.id, old_status=old_status, new_status=status, memo=memo)) db.commit() return {"ok": True}