"""PLAN 251-1 — 총괄자재표 → 운반 묶음(거리이정표 행 · B09 운반공 줄 한 원천).""" import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT)) from B08_Quantity.B08_Quantity_Haul import bill_key, haul_groups # noqa: E402 from B09_Estimation.B09_Estimation_Bill_Items import haul_items # noqa: E402 def _mats(rows): return {"material": {"rows": rows}} ROWS = [ {"key": "sand", "group": "골재", "spec": "모래", "unit": "㎥", "amount": 16}, {"key": "gravel", "group": "골재", "spec": "자갈", "unit": "㎥", "amount": None}, {"key": "mixed_aggregate", "group": "골재", "spec": "혼합석", "unit": "㎥", "amount": 3.5}, {"key": "remicon_25_24_15", "group": "레미콘", "spec": "25-24-15", "unit": "㎥", "amount": 2}, {"key": "remicon_25_21_80", "group": "레미콘", "spec": "25-21-80", "unit": "㎥", "amount": 1}, {"key": "rebar_d13", "group": "이형철근", "spec": "D13mm", "unit": "ton", "amount": 0.5}, {"key": "rebar_d16", "group": "이형철근", "spec": "D16mm", "unit": "ton", "amount": 0.25}, {"key": "cement", "group": "시멘트", "spec": "40kg/대", "unit": "대", "amount": None}, {"key": "pipe_600", "group": "파형강관", "spec": "Φ600mm", "unit": "m", "amount": 12}, {"key": "picked_deduct", "group": "채집석 공제", "unit": "㎥", "amount": 4}, {"key": "MT000777", "group": "앵커볼트", "spec": "M16", "unit": "EA", "amount": 8}, {"key": "sod", "group": "떼", "unit": "㎡", "amount": 0}, ] def test_묶음_장비_옛_여섯_늘_수량_없는_새_묶음_없음(): got = {g["key"]: (g["name"], g["unit"], g["qty"]) for g in haul_groups(_mats(ROWS))} assert list(got)[:2] == ["equip_heavy", "equip_machine"] # 장비 둘 맨 앞 assert got["sand"] == ("모래", "㎥", 16) and got["gravel"] == ("자갈", "㎥", None) assert got["mixed_aggregate"] == ("혼합석", "㎥", 3.5) assert got["remicon"] == ("레미콘", "㎥", 3) and got["rebar"] == ("철근", "ton", 0.75) assert got["cement"] == ("시멘트", "대", None) # 옛 여섯 = 수량 없어도 늘 assert got["pipe"] == ("파형강관", "m", 12) and got["MT000777"] == ("앵커볼트", "EA", 8) assert "picked_deduct" not in got and "sod" not in got # 공제 · 수량 0 새 묶음 = 행 없음 def test_B09_운반_줄_옛_키_그대로_새_묶음_키(): items = {i["key"]: i for i in haul_items(_mats(ROWS))} assert [bill_key(k) for k in ("equip_heavy", "sand", "rebar")] == ["haul:1", "haul:3", "haul:6"] assert items["haul:3"]["name"] == "모래" and items["haul:3"]["qty"] == 16 assert items["haul:remicon"]["name"] == "레미콘" and items["haul:remicon"]["unit"] == "㎥" assert all(i["section"] == "3" for i in items.values()) assert {"haul:1", "haul:2", "haul:3", "haul:4", "haul:5", "haul:6"} <= set(items) def test_251_2_거리이정표_운반_상자_자동(): from B08_Quantity.B08_Quantity_Haul import with_haul_routes groups = haul_groups(_mats(ROWS)) data = {"site": {}, "base": {"enabled": False}, "routes": [ {"id": "h-sand", "name": "골재상", "haul": "sand", "rows": [{"item": "모래"}]}, {"id": "u1", "name": "내 상자", "rows": []}, ]} # fmt: skip out = with_haul_routes(data, groups) by = {r["id"]: r for r in out["routes"]} assert by["h-sand"]["name"] == "골재상" # 있는 상자 그대로 assert "u1" in by # 사용자 상자 그대로 new = by["h-remicon"] assert (new["name"], new["address"], new["linked"], new["haul"]) == ("", "", False, "remicon") assert new["rows"] == [{"item": "레미콘", "dest": "start", "note": ""}] assert len([r for r in out["routes"] if r.get("haul")]) == len(groups) assert data["routes"][0] is out["routes"][0] and len(data["routes"]) == 2 # 원본 안 바뀜 def test_251_2_서버_모델_읽기_길(): from B08_Quantity.B08_Quantity_Router_Milestone import Route r = Route(id="h-sand", haul="sand", ref={"tab": "logic", "code": "GF000284"}) assert r.haul == "sand" and r.ref == {"tab": "logic", "code": "GF000284"} src = (ROOT / "B08_Quantity" / "B08_Quantity_Router_Milestone.py").read_text(encoding="utf-8") assert "with_haul_routes(read_data(root), groups)" in src def test_251_5_B09_운반_줄_연결_거리이정표(): from B09_Estimation.B09_Estimation_Bill_Library import used_folders from B09_Estimation.B09_Estimation_Sangeun import hand_sources from B09_Estimation.B09_Estimation_Store import ref_rows logic = {"tab": "logic", "code": "GF000284", "name": "덤프 운반", "given": {"L": 5}} lib = {"tab": "dg", "key": "DG:x", "lib": "precombo@system@-@SC-1"} items = {i["key"]: i for i in haul_items(_mats(ROWS), {"haul:3": logic, "haul:remicon": lib})} assert items["haul:3"]["ref"] == logic and items["haul:3"]["why"].startswith("새 산근") assert items["haul:remicon"]["ref"] == lib and items["haul:6"]["ref"] is None # 셈 · 수요 · 사본 정리 = 설계내역서 덮개 + 운반 연결 · 같은 줄 덮개 연결이 이김 user = {"bill": {"v": 2, "rows": [{"key": "haul:remicon", "ref": None}]}, "haul_refs": {"haul:3": logic, "haul:remicon": lib}} # fmt: skip assert [r["key"] for r in ref_rows(user)] == ["haul:remicon", "haul:3"] assert [k for k, _u, _s in hand_sources(user)] == ["haul:3"] assert used_folders(user) == set() # 덮개가 연결 풀었음 = 사본 안 지킴 assert used_folders({"haul_refs": {"haul:remicon": lib}}) == {"precombo@system@-@SC-1"} def test_251_5_자동_줄_단가_줄_키_짝(): from B09_Estimation.B09_Estimation_Calc_Bill import ref_price books = {"sg_list": [{"key": "SG:9", "no": 9, "sum": 100}], "sg_hand": {"haul:3": "SG:9"}} got = ref_price({"tab": "logic", "code": "GF000284"}, books, {}, "haul:3") assert got and got["key"] == "SG:9" and got["no"] == "산근 9호표" py = (ROOT / "B09_Estimation" / "B09_Estimation_Calc_Bill.py").read_text(encoding="utf-8") ts = (ROOT / "B09_Estimation" / "B09_Estimation_Calc_Bill.ts").read_text(encoding="utf-8") assert 'ref_price(item.get("ref"), books, hopyo, item["key"])' in py assert "refPrice(item.ref ?? null, book, hopyo, item.key)" in ts def test_251_4_거리이정표_램프_우클릭_단가연결(): import json import subprocess src = (ROOT / "B08_Quantity" / "B08_Quantity_UI_Milestone.ts").read_text(encoding="utf-8") fn = ( "export function refText" + src.split("export function refText")[1].split("\n}\n")[0] + "\n}\n" ) js = ( fn + """ console.log(JSON.stringify([refText(null), refText({ tab: "logic", code: "GF000134", name: "골재운반 모래" }), refText({ tab: "dg", key: "DG:x", name: "회사 조합" })])); """ ) run = subprocess.run( ["node", "--experimental-strip-types", "--no-warnings", "--input-type=module-typescript"], input=js, capture_output=True, text=True, encoding="utf-8", timeout=60, ) # fmt: skip assert run.returncode == 0, run.stderr assert json.loads(run.stdout) == [ "단가연결 없음 — 줄 우클릭 [단가연결]", "단가연결 — 단가산출 GF000134 골재운반 모래", "단가연결 — 일위대가 회사 조합", ] # 램프 = 항목 칸 · 우클릭 = [단가연결] · 연결 있으면 [단가연결 풀기] · 창 = B09 와 같은 것 assert 'key !== "item" ? null : routeAt(i)?.ref ? `${LAMP} is-linked` : LAMP' in src assert "openHaulModal({" in src and '"단가연결 풀기"' in src # 263-1 = 운반 단가 모달 하나 diagram = (ROOT / "B08_Quantity" / "B08_Quantity_UI_Milestone_Diagram.ts").read_text("utf-8") assert "Math.abs(h - lastH) > 1" in diagram # 틀 높이 바뀜 = 다시 그림(아래 잘림 없음)