Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018jonfdxn1Xit9bdkNJpE4G
98 lines
3.8 KiB
Python
98 lines
3.8 KiB
Python
"""166-6 일위대가목록표 블록 합 — 빈 줄 있는 블록 = 아는 줄 합 + 「빈 줄 n」 · 내역 단가엔 안 넘김.
|
||
|
||
견본 = 대가 A(노무 아는 줄 · 자재 단가 없음 줄) · 대가 B(A 를 부름 → 그 줄도 빈 줄) · 대가 C(빈 줄 없음).
|
||
파이썬 `B09_Estimation_Calc_Labor` ↔ TS 짝 거울 + 목록표 화면 「빈 줄 n」 · 풍선(Node 타입 지움).
|
||
"""
|
||
|
||
import json
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
if str(ROOT) not in sys.path:
|
||
sys.path.insert(0, str(ROOT))
|
||
|
||
from B09_Estimation.B09_Estimation_Calc_Labor import compute_labor, daega_price # noqa: E402
|
||
from test_145_2_b09_labor_calc import _same, _ts # noqa: E402
|
||
from test_155_b09_tabs import _node # noqa: E402
|
||
|
||
SHEETS = {
|
||
"labor": [{"key": "L1", "price": 165545}],
|
||
"material": [{"key": "M1", "price": None}],
|
||
"machine": [],
|
||
"gaps": [],
|
||
}
|
||
|
||
|
||
def _b(bid, name, lines):
|
||
return {
|
||
"id": bid,
|
||
"kind": "조합",
|
||
"name": name,
|
||
"spec": "",
|
||
"unit": "m",
|
||
"cite": "",
|
||
"lines": lines,
|
||
}
|
||
|
||
|
||
DAEGA = {
|
||
"blocks": [
|
||
_b("A", "기슭막이", [
|
||
{"kind": "labor", "key": "L1", "qty": 0.5, "name": "보통인부"},
|
||
{"kind": "material", "key": "M1", "qty": 2, "name": "토목용부직포"},
|
||
]),
|
||
_b("B", "겹 대가", [
|
||
{"kind": "labor", "key": "L1", "qty": 0.1, "name": "보통인부"},
|
||
{"kind": "daega", "key": "A", "qty": 1, "name": "기슭막이"},
|
||
]),
|
||
_b("C", "아는 줄만", [{"kind": "labor", "key": "L1", "qty": 1, "name": "보통인부"}]),
|
||
],
|
||
"owners": {"pipe@100.0": "A", "pipe@200.0": "C"},
|
||
} # fmt: skip
|
||
|
||
|
||
def test_아는_줄_합_빈_줄_n():
|
||
out = compute_labor(DAEGA, SHEETS)
|
||
rows = {r["key"]: r for r in out["daega"]}
|
||
# 165,545 × 0.5 = 82,772.5 → 블록 ROUNDDOWN 0 · 자재 줄은 빈 줄
|
||
assert (rows["A"]["sum"], rows["A"]["labor"], rows["A"]["material"]) == (82772, 82772, 0)
|
||
assert (rows["A"]["blank"], rows["A"]["blank_names"]) == (1, ["토목용부직포"])
|
||
# 부른 대가에 빈 줄 → 그 줄도 빈 줄(아는 줄 합을 위로 안 넘김)
|
||
assert (rows["B"]["sum"], rows["B"]["blank"], rows["B"]["blank_names"]) == (
|
||
16554,
|
||
1,
|
||
["기슭막이"],
|
||
)
|
||
assert (rows["C"]["sum"], rows["C"]["blank"]) == (165545, 0)
|
||
# 목록표 = 블록 합계 그대로(같은 셈 한 벌)
|
||
for b in out["daega_blocks"]:
|
||
assert _same(
|
||
{k: rows[b["key"]][k] for k in ("sum", "blank")}, {"sum": b["sum"], "blank": b["blank"]}
|
||
)
|
||
# 내역 단가 = 빈 줄 블록은 빈칸 · 없는 블록은 그대로
|
||
assert daega_price(out, "pipe@100.0")["sum"] is None
|
||
assert daega_price(out, "pipe@100.0")["labor"] is None
|
||
assert daega_price(out, "pipe@200.0")["sum"] == 165545
|
||
|
||
|
||
def test_거울_파이썬_TS():
|
||
py = json.loads(json.dumps(compute_labor(DAEGA, SHEETS), ensure_ascii=False))
|
||
ts = _ts(DAEGA, SHEETS, {})
|
||
assert _same(py, ts["out"])
|
||
assert _same(daega_price(py, "pipe@100.0"), ts["price"])
|
||
|
||
|
||
def test_목록표_빈_줄_글_풍선():
|
||
sheets = json.dumps(compute_labor(DAEGA, SHEETS), ensure_ascii=False)
|
||
out = _node(
|
||
f"\nconst t = buildDaegaList({{ sheets: {sheets} }});"
|
||
"\nconsole.log(JSON.stringify({ notes: t.rows.map((r) => r.blank_note),"
|
||
" sums: t.rows.map((r) => r.sum), cols: t.columns.map((c) => c.key),"
|
||
" tips: t.rows.map((_, i) => t.tip(i, 'blank_note') ?? null) }));"
|
||
)
|
||
assert out["cols"][5:7] == ["sum", "blank_note"] # 합계 바로 옆
|
||
assert out["notes"] == ["빈 줄 1", "빈 줄 1", ""]
|
||
assert out["sums"] == [82772, 16554, 165545]
|
||
assert out["tips"] == ["빈 줄 — 토목용부직포", "빈 줄 — 기슭막이", None]
|