# ============================================================ # EX-05 / EX-09 MES 下发与报工黄金测试 # ============================================================ from __future__ import annotations from pathlib import Path from server.agent_core.intent import parse_fast from server.aps_domain.flex import run_flex_schedule from server.aps_domain.mes import apply_dispatch, apply_report, list_execution, preview_dispatch from server.integrations.mes_stub import reset_mes_client from server.state.seed import seed_world class _MemStore: def __init__(self, data): self.data = data def next_id(self, kind: str) -> int: key = f"_c_{kind}" self.data[key] = self.data.get(key, 4000) + 1 return self.data[key] def save(self): pass def test_dispatch_idempotent(tmp_path: Path): reset_mes_client(tmp_path / "mes_mirror.json") store = _MemStore(seed_world()) run_flex_schedule(store, sort_mode="BOTTLENECK", actor="test") prev = preview_dispatch(store.data, "flex") assert prev["newCount"] >= 1 r1 = apply_dispatch(store, track="flex", actor="test") assert r1["created"] assert len(r1["duplicates"]) == 0 w = next(w for w in store.data["flexWorkOrders"] if w.get("mesExternalId")) assert w["mesExternalId"].startswith("MES-WO-") ver = store.data["flexScheduleVersions"][-1] assert ver["status"] == "DISPATCHED" r2 = apply_dispatch(store, track="flex", actor="test") assert len(r2["created"]) == 0 assert len(r2["duplicates"]) >= len(r1["created"]) def test_report_progress_and_order_complete(tmp_path: Path): reset_mes_client(tmp_path / "mes_mirror.json") store = _MemStore(seed_world()) run_flex_schedule(store, sort_mode="BOTTLENECK", actor="test") apply_dispatch(store, track="flex", actor="test") ex = list_execution(store.data, "flex") assert ex["total"] >= 1 row = ex["rows"][0] r = apply_report(store, row["woId"], track="flex", progress_pct=50, actor="test") assert r["progressPct"] == 50 wo = next(w for w in store.data["flexWorkOrders"] if w["id"] == row["woId"]) assert wo["status"] == "RUNNING" # 同订单全部完工 order_no = row["orderNo"] vid = store.data["flexScheduleVersions"][-1]["id"] sibs = [w for w in store.data["flexWorkOrders"] if w.get("flexOrderNo") == order_no and w.get("versionId") == vid] for s in sibs: apply_report(store, s["id"], track="flex", finish=True, actor="test") fo = next(o for o in store.data["flexOrders"] if o["orderNo"] == order_no) assert fo["status"] == "COMPLETED" def test_intent_mes_phrases(): world = seed_world() assert parse_fast("下发MES", world).intent == "mes.dispatch" assert parse_fast("MES状态", world).intent == "mes.status" assert parse_fast("模拟报工", world).intent == "mes.report" assert parse_fast("一键模拟报工完工", world).params.get("finishAll") is True