Add order editing and qualified downtime history

This commit is contained in:
masterdev
2026-06-17 02:45:05 +01:00
parent 565e5ca4cb
commit 7dd7652ea7
5 changed files with 321 additions and 24 deletions

View File

@@ -18,6 +18,7 @@ from .schemas import (
MachineConfigUpdate,
MachineEventIn,
ProductionOrderCreate,
ProductionOrderUpdate,
ScrapCreate,
SimulatorEventCreate,
SimulatorScenarioCreate,
@@ -466,24 +467,27 @@ def get_machine_downtimes(machine_id: int, limit: int = Query(default=100, le=50
@app.get("/api/production-orders")
def list_production_orders(db: Session = Depends(get_db)) -> list[dict]:
rows = db.execute(select(ProductionOrder).order_by(ProductionOrder.created_at.desc())).scalars()
return [
{
"id": row.id,
"order_number": row.order_number,
"machine_id": row.machine_id,
"article_ref": row.article_ref,
"article_name": row.article_name,
"mold_ref": row.mold_ref,
"material_ref": row.material_ref,
"planned_qty": row.planned_qty,
"cavities": row.cavities,
"theoretical_cycle_time_sec": row.theoretical_cycle_time_sec,
"status": row.status,
"started_at": row.started_at.isoformat() if row.started_at else None,
"ended_at": row.ended_at.isoformat() if row.ended_at else None,
}
for row in rows
]
return [_serialize_production_order(db, row) for row in rows]
def _serialize_production_order(db: Session, row: ProductionOrder) -> dict:
machine = db.get(Machine, row.machine_id)
return {
"id": row.id,
"order_number": row.order_number,
"machine_id": row.machine_id,
"machine_code": machine.code if machine else None,
"article_ref": row.article_ref,
"article_name": row.article_name,
"mold_ref": row.mold_ref,
"material_ref": row.material_ref,
"planned_qty": row.planned_qty,
"cavities": row.cavities,
"theoretical_cycle_time_sec": row.theoretical_cycle_time_sec,
"status": row.status,
"started_at": row.started_at.isoformat() if row.started_at else None,
"ended_at": row.ended_at.isoformat() if row.ended_at else None,
}
@app.post("/api/production-orders")
@@ -503,6 +507,36 @@ def _find_order_or_404(db: Session, order_id: int) -> ProductionOrder:
return order
@app.patch("/api/production-orders/{order_id}")
def update_production_order(order_id: int, payload: ProductionOrderUpdate, db: Session = Depends(get_db)) -> dict:
order = _find_order_or_404(db, order_id)
updates = payload.model_dump(exclude_unset=True)
if not updates:
return _serialize_production_order(db, order)
if "order_number" in updates and updates["order_number"] != order.order_number:
existing = db.execute(select(ProductionOrder).where(ProductionOrder.order_number == updates["order_number"])).scalar_one_or_none()
if existing is not None:
raise HTTPException(status_code=400, detail="Production order number already exists")
if "machine_id" in updates and updates["machine_id"] != order.machine_id:
target_machine = db.get(Machine, updates["machine_id"])
if target_machine is None:
raise HTTPException(status_code=404, detail="Machine not found")
if order.status == "running":
running_order = get_running_order(db, updates["machine_id"])
if running_order and running_order.id != order.id:
raise HTTPException(status_code=400, detail="Another order is already running on the target machine")
for field, value in updates.items():
setattr(order, field, value)
db.commit()
db.refresh(order)
hub.notify({"type": "refresh", "source": "api", "machine_id": order.machine_id, "event_type": "production_order_updated"})
return _serialize_production_order(db, order)
@app.post("/api/production-orders/{order_id}/start")
def start_production_order(order_id: int, db: Session = Depends(get_db)) -> dict:
order = _find_order_or_404(db, order_id)
@@ -565,6 +599,14 @@ def get_unqualified_downtimes(db: Session = Depends(get_db)) -> list[dict]:
return [_serialize_downtime_for_qualification(db, row) for row in rows]
@app.get("/api/downtimes/qualified")
def get_qualified_downtimes(limit: int = Query(default=200, le=500), db: Session = Depends(get_db)) -> list[dict]:
rows = db.execute(
select(Downtime).where(Downtime.reason_code.is_not(None)).order_by(Downtime.start_time.desc()).limit(limit)
).scalars()
return [_serialize_downtime_for_qualification(db, row) for row in rows]
def _serialize_downtime_for_qualification(db: Session, row: Downtime) -> dict:
machine = db.get(Machine, row.machine_id)
order = db.get(ProductionOrder, row.production_order_id) if row.production_order_id else None

View File

@@ -27,6 +27,18 @@ class ProductionOrderCreate(BaseModel):
theoretical_cycle_time_sec: float = Field(gt=0)
class ProductionOrderUpdate(BaseModel):
order_number: str | None = None
machine_id: int | None = None
article_ref: str | None = None
article_name: str | None = None
mold_ref: str | None = None
material_ref: str | None = None
planned_qty: int | None = Field(default=None, gt=0)
cavities: int | None = Field(default=None, gt=0)
theoretical_cycle_time_sec: float | None = Field(default=None, gt=0)
class DowntimeQualify(BaseModel):
reason_code: str
comment: str | None = None