- 사이클시간 입력 · 8-2-8 표 고르기 칸 없앰 · 사이클 = 8-2-8 기본값(계산 절차에만) - 거리 칸(운반거리 · Cm · 사이클시간 · t2) = 거리에서 · 손 값 이김 · 거리 칸 없는 항목 = 사이클 줄 없음 - [변경] = 단가연결 한 목록(onPick) · [다른 종류] 없앰 · 조합 = [적용] 때 사본 들여옴 · 호표 = 그대로 연결 - 옛 cycle = 서버 읽기 그대로 · [적용]하면 지움 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JywHxQuWPk6UYXTebyrBoU
145 lines
7.7 KiB
Python
145 lines
7.7 KiB
Python
"""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 # 틀 높이 바뀜 = 다시 그림(아래 잘림 없음)
|