Files
2026-07-15 18:37:19 +09:00

163 lines
5.7 KiB
Python

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"}