from fastapi import APIRouter, HTTPException from pydantic import BaseModel, Field from typing import List, Optional from .db_manager import ( add_material_property, update_material_property, delete_material_property, get_all_material_properties, get_material_property_by_id, add_inventory_to_db, update_inventory_in_db, deplete_inventory_in_db, get_all_inventory_from_db, get_inventory_details_from_db ) from .analysis import calculate_cost_analysis router = APIRouter(prefix="/inventory", tags=["inventory"]) # --- Pydantic Schemas --- class MaterialPropertySchema(BaseModel): id: Optional[int] = None material_code: str material_name: str material_type: str density: float remarks: Optional[str] = None class InventorySchema(BaseModel): id: Optional[int] = None material_id: int receipt_date: str # YYYY-MM-DD receipt_quantity: float usage_quantity: Optional[float] = 0.0 stock: Optional[float] = None unit_cost: float remarks: Optional[str] = None is_depleted: Optional[int] = 0 supplier_id: Optional[int] = None item_name: Optional[str] = None item_number: Optional[str] = None class AnalysisInputSchema(BaseModel): yarn_inventory_id: int bond_inventory_id: Optional[int] = None yarn_diameter_micron: Optional[float] = 7.0 yarn_k: Optional[float] = 12.0 ports: Optional[float] = 40.0 cycle_time_hz: Optional[float] = 8.0 cut_length_mm: Optional[float] = 6.0 work_hours_day: Optional[float] = 16.0 work_days_month: Optional[float] = 20.0 num_machines: Optional[float] = 2.0 bond_percentage: Optional[float] = 3.0 class CostAnalysisRequestSchema(BaseModel): inputs: AnalysisInputSchema targetProductionQuantity: Optional[float] = None # --- Material Properties APIs --- @router.post("/materials", response_model=dict) def create_material_property(material: MaterialPropertySchema): result = add_material_property(material.dict()) if result is None: raise HTTPException(status_code=500, detail="Failed to create material property") return {"id": result, "status": "success"} @router.put("/materials/{material_id}", response_model=dict) def update_material(material_id: int, material: MaterialPropertySchema): data = material.dict() data['id'] = material_id success = update_material_property(data) if not success: raise HTTPException(status_code=500, detail="Failed to update material property") return {"status": "success"} @router.delete("/materials/{material_id}", response_model=dict) def delete_material(material_id: int): success = delete_material_property(material_id) if not success: raise HTTPException(status_code=400, detail="Failed to delete material property. Check if it's in use.") return {"status": "success"} @router.get("/materials", response_model=List[MaterialPropertySchema]) def list_material_properties(): return get_all_material_properties() @router.get("/materials/{material_id}", response_model=MaterialPropertySchema) def get_material_property(material_id: int): material = get_material_property_by_id(material_id) if not material: raise HTTPException(status_code=404, detail="Material property not found") return material # --- Inventory APIs --- @router.post("/", response_model=dict) def create_inventory(inventory: InventorySchema): result = add_inventory_to_db(inventory.dict()) if result is None: raise HTTPException(status_code=500, detail="Failed to create inventory record") return {"id": result, "status": "success"} @router.put("/{inventory_id}", response_model=dict) def update_inventory(inventory_id: int, inventory: InventorySchema): data = inventory.dict() data['id'] = inventory_id success = update_inventory_in_db(data) if not success: raise HTTPException(status_code=500, detail="Failed to update inventory record") return {"status": "success"} @router.put("/{inventory_id}/deplete", response_model=dict) def deplete_inventory(inventory_id: int): success = deplete_inventory_in_db(inventory_id) if not success: raise HTTPException(status_code=500, detail="Failed to deplete inventory") return {"status": "success"} @router.get("/", response_model=List[dict]) def list_inventory(): return get_all_inventory_from_db() @router.get("/{inventory_id}", response_model=dict) def get_inventory_details(inventory_id: int): details = get_inventory_details_from_db(inventory_id) if not details: raise HTTPException(status_code=404, detail="Inventory details not found") return details # --- Cost Analysis APIs --- @router.post("/analysis/calculate", response_model=dict) def cost_analysis(request_data: CostAnalysisRequestSchema): try: inputs_dict = request_data.inputs.dict() # Null 문자열 파라미터 방어용 가공 if not inputs_dict.get("bond_inventory_id"): inputs_dict["bond_inventory_id"] = "null" result = calculate_cost_analysis(inputs_dict, request_data.targetProductionQuantity) return result except ValueError as val_err: raise HTTPException(status_code=400, detail=str(val_err)) except Exception as exc: raise HTTPException(status_code=500, detail=f"Internal calculations failed: {exc}")