81 lines
3.0 KiB
Python
81 lines
3.0 KiB
Python
# ============================================================
|
|
# 现场完整生产路线导入黄金测试
|
|
# ============================================================
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from server.aps_domain.kangni_intake import (
|
|
DEFAULT_ROUTE_XLSX,
|
|
build_flex_bundle,
|
|
load_site_into_world,
|
|
parse_complete_route_xlsx,
|
|
)
|
|
from server.engines import PoolEngine
|
|
from server.state.seed import seed_world
|
|
|
|
|
|
ROUTE = Path(DEFAULT_ROUTE_XLSX)
|
|
|
|
|
|
@pytest.mark.skipif(not ROUTE.exists(), reason="现场 Excel 不在本机")
|
|
def test_parse_complete_route_order_102285668():
|
|
pkg = parse_complete_route_xlsx(ROUTE)
|
|
assert pkg["orderNo"] == "102285668"
|
|
assert pkg["productCode"] == "28200003654300"
|
|
assert len(pkg["operations"]) == 10
|
|
assert pkg["operations"][0]["operationCode"] == "0503727Z1M"
|
|
assert len(pkg["bom"]) >= 15
|
|
assert all(op["stdTimePerUnit"] > 0 for op in pkg["operations"])
|
|
assert any(op["stdTimeInferred"] for op in pkg["operations"])
|
|
|
|
|
|
@pytest.mark.skipif(not ROUTE.exists(), reason="现场 Excel 不在本机")
|
|
def test_load_site_writes_master_and_orders_and_schedules():
|
|
world = seed_world()
|
|
assert any(m["code"].startswith("CTRL-") for m in world["materials"])
|
|
assert any(o["orderNo"].startswith("SO") for o in world["salesOrders"])
|
|
|
|
meta = load_site_into_world(world, route_path=ROUTE, include_sibling_orders=False, clear_all=True)
|
|
assert meta["primaryOrder"] == "102285668"
|
|
assert meta.get("clearedDemo") is True
|
|
|
|
# 演示垃圾已清
|
|
assert not any(m["code"].startswith("CTRL-") for m in world["materials"])
|
|
assert not any(o["orderNo"].startswith("FO-") for o in world["flexOrders"])
|
|
assert not any(o["orderNo"].startswith("SO20") for o in world["salesOrders"])
|
|
|
|
# 主数据页可读
|
|
assert world["factories"][0]["name"] == "城轨机构装配工厂"
|
|
assert len(world["operations"]) == 10
|
|
assert any(m["code"] == "28200003654300" for m in world["materials"])
|
|
assert len(world["bomItems"]) >= 15
|
|
assert len(world["routingSteps"]) == 10
|
|
assert world["salesOrders"][0]["orderNo"] == "102285668"
|
|
assert world["salesOrders"][0]["status"] == "APPROVED"
|
|
|
|
# 柔性轨
|
|
assert world["flexOrders"][0]["orderNo"] == "102285668"
|
|
assert world["flexEquipment"]
|
|
assert world["flexParams"].get("fixedMasterSynced") is True
|
|
|
|
counters: dict[str, int] = {}
|
|
|
|
def nid(k: str) -> int:
|
|
counters[k] = counters.get(k, 0) + 1
|
|
return counters[k]
|
|
|
|
result = PoolEngine().solve(world, nid, sort_mode="BOTTLENECK", start_date="2026-06-26")
|
|
assert result["orderCount"] == 1
|
|
assert result["vlCount"] == 1
|
|
assert result["woCount"] == 10
|
|
|
|
|
|
@pytest.mark.skipif(not ROUTE.exists(), reason="现场 Excel 不在本机")
|
|
def test_bundle_meta_has_inferences():
|
|
bundle = build_flex_bundle(ROUTE, include_sibling_orders=False)
|
|
assert bundle["_meta"]["inferences"]
|
|
assert any("工时" in x or "工位" in x for x in bundle["_meta"]["inferences"])
|