145 lines
5.3 KiB
Python
145 lines
5.3 KiB
Python
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}")
|