from fastapi import APIRouter, HTTPException from pydantic import BaseModel from typing import List, Dict, Any, Optional from .db_manager import ( add_production_plan, add_equipment_assignments_to_plan, get_all_production_plans, find_available_equipment, update_plan_assignment, delete_production_plan, adjust_and_distribute_assignments, update_production_plan ) from .helper import calculate_end_date router = APIRouter(prefix="/plans", tags=["plans"]) # --- Pydantic Schemas --- class PlanAssignmentSchema(BaseModel): assignment_id: Optional[int] = None plan_id: Optional[int] = None equipment_id: int start_date: str end_date: str works_on_saturday: bool works_on_sunday: bool class PlanSchema(BaseModel): plan_id: Optional[int] = None plan_name: str customer_name: Optional[str] = None customer_id: Optional[int] = None yarn_name: Optional[str] = None yarn_inventory_id: int bond_name: Optional[str] = None bond_inventory_id: Optional[int] = None requested_quantity_kg: float start_date: str end_date: Optional[str] = None production_days: float status: Optional[str] = "Scheduled" # Cost & Margin properties hourly_net_cost_per_machine: float hourly_profit_per_machine: float plan_total_material_cost: float yarn_diameter: float yarn_k: float ports: float cycle_time: float cut_length: float work_hours_day: float work_days_month: float num_machines: float plan_net_processing_cost: float plan_company_margin: float plan_processing_fee: float plan_yarn_cost: float plan_bond_cost: float plan_estimated_sales: float # Machine allocations equipment_ids: List[int] works_on_saturday: Optional[bool] = False works_on_sunday: Optional[bool] = False class AssignmentUpdatePayload(BaseModel): assignment_id: int start_date: str end_date: str works_on_saturday: bool works_on_sunday: bool class RedistributionPayload(BaseModel): source_assignment: Dict[str, Any] distribution: Dict[str, int] # --- Plan APIs --- @router.post("/", response_model=dict) def create_production_plan(plan: PlanSchema): plan_data = plan.dict() assigned_machine_ids = plan.equipment_ids start_date_str = plan.start_date required_days = plan.production_days works_on_saturday = plan.works_on_saturday works_on_sunday = plan.works_on_sunday if not assigned_machine_ids or not start_date_str or required_days is None: raise HTTPException(status_code=400, detail="Missing required parameters: equipment_ids, start_date, production_days") # 주말 가동 플래그를 고려하여 가용 완료 날짜 계산 end_date_str = calculate_end_date(start_date_str, required_days, works_on_saturday, works_on_sunday) plan_data["end_date"] = end_date_str plan_id = add_production_plan(plan_data) if not plan_id: raise HTTPException(status_code=500, detail="Failed to add production plan to DB") # 설비 할당 정보 생성 assignments = [ { 'equipment_id': eq_id, 'start_date': start_date_str, 'end_date': end_date_str, 'works_on_saturday': works_on_saturday, 'works_on_sunday': works_on_sunday } for eq_id in assigned_machine_ids ] assign_success = add_equipment_assignments_to_plan(plan_id, assignments) if not assign_success: raise HTTPException(status_code=500, detail="Plan was created but equipment assignments failed.") return {"plan_id": plan_id, "status": "success"} @router.put("/{plan_id}", response_model=dict) def edit_production_plan(plan_id: int, plan: PlanSchema): plan_data = plan.dict() assigned_machine_ids = plan.equipment_ids start_date_str = plan.start_date required_days = plan.production_days works_on_saturday = plan.works_on_saturday works_on_sunday = plan.works_on_sunday end_date_str = calculate_end_date(start_date_str, required_days, works_on_saturday, works_on_sunday) plan_data["end_date"] = end_date_str success = update_production_plan(plan_id, plan_data, assigned_machine_ids) if not success: raise HTTPException(status_code=500, detail="Failed to update production plan") return {"status": "success"} @router.delete("/{plan_id}", response_model=dict) def delete_plan(plan_id: int): success = delete_production_plan(plan_id) if not success: raise HTTPException(status_code=500, detail="Failed to delete production plan") return {"status": "success"} @router.get("/", response_model=List[dict]) def list_production_plans(): return get_all_production_plans() @router.get("/find-available-equipment", response_model=List[dict]) def get_available_equipment(start_date: str, end_date: str, works_on_saturday: bool = False, works_on_sunday: bool = False): return find_available_equipment(start_date, end_date, works_on_saturday, works_on_sunday) @router.put("/{plan_id}/assignments", response_model=dict) def update_assignment(plan_id: int, payload: AssignmentUpdatePayload): success = update_plan_assignment(plan_id, payload.dict()) if not success: raise HTTPException(status_code=500, detail="Failed to update assignment") return {"status": "success"} @router.post("/{plan_id}/assignments/redistribute", response_model=dict) def redistribute_assignments(plan_id: int, payload: RedistributionPayload): success = adjust_and_distribute_assignments(plan_id, payload.source_assignment, payload.distribution) if not success: raise HTTPException(status_code=500, detail="Failed to redistribute assignments") return {"status": "success"}