- 수요: 사본 일위대가 자재 · 굳힌 사전조합 자재 코드도(Linked.used_keys) → 대가 재료 줄 단가가 MT 줄에서 남 - 두 번 셈(Router.compute_twice): 1차 셈 → 대가 · 산근 · 중기 재료 줄 · B08 줄 · 관급 · 별도 줄만 남김(Summary.used_materials) · 1차 역전개 총수량 = material_qty → 2차 셈 - 수량 원천: Calc_Base 짝 material_sheet 가 material_qty(없는 키 빈칸) · 없으면 입력 줄 수량(거울) - 화면: 비고 = 쓰는 곳(대가 · 산근 · 중기 n호표 · 내역 자재대) · 안내 글 - 실측 엄상준_검증: 141 → 24줄 · 목록 수량 = 재료비수량금액집계표 수량 · 목록표에 없음 0 - 시험: test_183_b09_material_list Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SE9MxeXTu2uaDZ55BJowAY
89 lines
4.5 KiB
Python
89 lines
4.5 KiB
Python
"""183-1 재료비목록표 = 연결된 일위대가 · 산근 · 중기가 쓰는 자재만 · 수량 · 단가 한 줄 · 쓰는 곳.
|
||
|
||
- 수요: 사본 일위대가 자재 · 굳힌 사전조합 자재 코드도 든다(`Linked.used_keys`)
|
||
- 거름: 대가 · 산근 · 중기 블록 재료 줄 · B08 줄 · 관급 · 별도 줄만 남김(`Summary.used_materials`)
|
||
- 수량 = 입력 `material_qty`(1차 역전개 총수량) — `Calc_Base` 짝 거울 · 두 번 셈(`Router.compute_twice`)
|
||
- 화면 비고 = 쓰는 곳(`UI_Tabs_Base.usesOf`)
|
||
"""
|
||
|
||
import json
|
||
from pathlib import Path
|
||
|
||
from B09_Estimation import B09_Estimation_Router as router_mod
|
||
from B09_Estimation.B09_Estimation_Calc_Base import compute_base
|
||
from B09_Estimation.B09_Estimation_Linked import used_keys
|
||
from B09_Estimation.B09_Estimation_Summary import used_materials
|
||
from resources.tester.test_144_b09_base_calc import _run_ts
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
|
||
MATERIALS = [
|
||
{"key": "MT1", "name": "쓰는 자재", "prices": {"물가자료": 1000}},
|
||
{"key": "MT2", "name": "고르기 후보", "prices": {"물가자료": 500}},
|
||
{"key": "MT3", "name": "관급 표시", "prices": {"물가자료": 300}},
|
||
{"key": "MO1", "name": "경유", "prices": {"유가": 1800}},
|
||
{"key": "b08:pipe_800", "name": "파형강관", "prices": {}, "qty": 8, "supply": "관급"},
|
||
]
|
||
USER = {"materials": {"MT3": {"supply": "관급"}}}
|
||
SG = [{"key": "SG1", "no": 1, "lines": [{"kind": "material", "ref": {"key": "MT1"}, "qty": 2}]}]
|
||
MACHINE = [{"key": "EQ1", "lines": [{"kind": "material", "ref": {"key": "MO1"}, "qty": None}]}]
|
||
|
||
|
||
def test_사본_일위대가_자재_사전조합_자재_코드도_수요(tmp_path):
|
||
labor = {
|
||
"줄": {"담은로직": [], "자재": [{"코드": "MT000053"}, {"코드": "PM000001"}]},
|
||
"참조사본": {"참조|system||SC-000001": {"담은로직": [], "자재": [{"코드": "MT000008"}]}},
|
||
}
|
||
(tmp_path / "일위대가.json").write_text(json.dumps(labor, ensure_ascii=False), "utf-8")
|
||
assert used_keys(tmp_path) == ["MT000053", "MT000008"] # 개인 자재(PM) = 원가 표 밖
|
||
|
||
|
||
def test_쓰는_자재만_남김():
|
||
sheets = {"sg": SG, "daega_blocks": [], "machine_blocks": MACHINE}
|
||
inputs = {"materials": MATERIALS}
|
||
assert used_materials(sheets, inputs, USER) == {"MT1", "MO1", "MT3", "b08:pipe_800"}
|
||
|
||
|
||
def test_수량_원천_material_qty_거울():
|
||
inputs = {"labor": [], "machines": [], "materials": MATERIALS}
|
||
old = {r["key"]: r["qty"] for r in compute_base(inputs, USER)["material"]}
|
||
assert old["b08:pipe_800"] == 8 and old["MT1"] is None # 없으면 입력 줄 수량(지금 길)
|
||
got = compute_base({**inputs, "material_qty": {"MT1": 6, "b08:pipe_800": 8}}, USER)
|
||
rows = {r["key"]: r for r in got["material"]}
|
||
assert (rows["MT1"]["qty"], rows["MT1"]["amount"]) == (6, 6000)
|
||
assert rows["MT2"]["qty"] is None and rows["MT2"]["amount"] is None # 없는 키 = 빈칸
|
||
for case in (inputs, {**inputs, "material_qty": {"MT1": 6}}):
|
||
assert _run_ts(case, USER) == compute_base(case, USER)
|
||
|
||
|
||
def test_두_번_셈_후보_줄_빠지고_수량_역전개(monkeypatch):
|
||
calls = []
|
||
|
||
def fake(root, inputs, user):
|
||
calls.append([m["key"] for m in inputs["materials"]])
|
||
base = compute_base(inputs, user)
|
||
bill = {"rows": [{"kind": "item", "qty": 3, "ref": {"tab": "sg", "key": "SG1"}}]}
|
||
return {**base, "sg": SG, "daega_blocks": [], "machine_blocks": MACHINE, "bill": bill}
|
||
|
||
monkeypatch.setattr(router_mod, "compute_sheets", fake)
|
||
inputs = {"labor": [], "machines": [], "materials": list(MATERIALS)}
|
||
sheets, summary = router_mod.compute_twice(Path("."), inputs, USER)
|
||
assert calls[0] == [m["key"] for m in MATERIALS]
|
||
assert calls[1] == ["MT1", "MT3", "MO1", "b08:pipe_800"] # 후보 MT2 뺌
|
||
assert inputs["material_qty"] == {"MT1": 6.0} # 설계내역서 3 × 호표 2
|
||
rows = {r["key"]: r for r in sheets["material"]}
|
||
assert (rows["MT1"]["qty"], rows["MT1"]["amount"]) == (6.0, 6000)
|
||
assert [r["qty"] for r in summary["sum_material"]] == [rows["MT1"]["qty"]] # 집계표와 같은 값
|
||
|
||
|
||
def test_화면_비고_쓰는_곳():
|
||
src = (ROOT / "B09_Estimation" / "B09_Estimation_UI_Tabs_Base.ts").read_text(encoding="utf-8")
|
||
for label in (
|
||
"`대가 ${b.no}호표`",
|
||
"`산근 ${b.no}호표`",
|
||
"`중기 ${n + 1}호표`",
|
||
'"내역 자재대"',
|
||
):
|
||
assert label in src
|
||
assert 'text("uses", "비고(쓰는 곳)"' in src and 'text("origin", "비고"' not in src
|