# ============================================================ # M-A 黄金测试:通用 Excel 导入器(profile 配置化,康尼零硬编码) # ============================================================ from __future__ import annotations from pathlib import Path import pytest from server.aps_domain.kangni_intake import DEFAULT_ROUTE_XLSX, load_site_into_world from server.importers import list_profiles, load_profile from server.state.seed import seed_world ROUTE = Path(DEFAULT_ROUTE_XLSX) def test_kangni_profile_holds_site_constants(): """工厂命名/工时推断规则等在 profile 中维护,代码不再写死。""" prof = load_profile("kangni") assert prof["projectCode"] == "kangni" assert prof["factory"]["name"] == "城轨机构装配工厂" assert prof["inferStdMin"]["部装"] == 45.0 assert prof["inferStdMin"]["装配"] == 30.0 assert prof["stationCount"] == 4 assert any(p["profileId"] == "kangni" for p in list_profiles()) def test_missing_profile_returns_empty(): assert load_profile("no-such-customer") == {} @pytest.mark.skipif(not ROUTE.exists(), reason="现场 Excel 不在本机") def test_profile_overrides_flow_into_world(monkeypatch): """改 profile 的工厂名 → 导入结果跟着变(证明读配置而非硬编码)。""" world = seed_world() custom = dict(load_profile("kangni")) custom["factory"] = {"code": "X-F01", "name": "泛用机加工厂", "timezone": "Asia/Shanghai"} custom["inferStdMin"] = {"部装": 50.0, "装配": 30.0, "_default": 30.0} meta = load_site_into_world(world, route_path=ROUTE, clear_all=True, profile=custom) assert meta["primaryOrder"] == "102285668" assert world["factories"][0]["name"] == "泛用机加工厂" # 现场工时表是更高优先级证据;profile 推断值只在实测/工时表缺失时兜底。 assert all(r.get("stdTimeSource") == "工时表" for r in world["flexRoutings"]) assert any("工时.xlsx" in item for item in meta["inferences"]) @pytest.mark.skipif(not ROUTE.exists(), reason="现场 Excel 不在本机") def test_import_marks_std_time_source(monkeypatch): """导入后每条柔性路线都带可追溯工时来源标记。""" world = seed_world() load_site_into_world(world, route_path=ROUTE, clear_all=True) assert world["flexRoutings"] allowed_sources = {"实测", "推断", "工时表"} assert all(r.get("stdTimeSource") in allowed_sources for r in world["flexRoutings"]) assert all(s.get("stdTimeSource") in allowed_sources for s in world["routingSteps"])