Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
130 lines
6.0 KiB
Python
130 lines
6.0 KiB
Python
"""157-2 B09 단가산출근거 탭 보기 둘 · 157-3 산근 규격 칸 「이름 규격」.
|
|
|
|
- 157-2 보기 B(호표별 카드) = 보기 A(표) 줄 그대로 호표마다 묶음 — 같은 값 · 같은 차례(171-3 공용 묶음 카드로 갈음)
|
|
- 단추 = 보기 바꿈(글 「박스보기」 ↔ 「표로 보기」 · 181-2) · 기억 못 읽음 · 모르는 값 = 카드(171-3 컨테이너 기본)
|
|
- 157-3 규격 = 기계 · 직종 원문번호 → 「이름 규격」(M02 85-1 도우미) · 번호는 풍선(tip)
|
|
"""
|
|
|
|
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_Sangeun import spec_text # noqa: E402
|
|
from resources.tester.helper_b09_group_cards import COMMON, GROUPS, TABS, run # noqa: E402
|
|
|
|
B09 = ROOT / "B09_Estimation"
|
|
|
|
|
|
def _node(js_body):
|
|
return run([COMMON, TABS, "B09_Estimation/B09_Estimation_UI_Tabs_Sangeun.ts", GROUPS], js_body)
|
|
|
|
|
|
def _block(key, no, spec="", spec_raw=""):
|
|
return {
|
|
"key": key, "no": no, "name": f"산근{no}", "unit": "m3", "spec": spec, "spec_raw": spec_raw,
|
|
"head": [f"산근{no} / m3", "산림품셈 적용"],
|
|
"lines": [
|
|
{"kind": "labor", "name": "보통인부", "ref": {"tab": "labor", "key": "LB2"},
|
|
"why": None, "labor": 2979.8, "material": 0.0, "expense": 0.0,
|
|
"text": ["보통인부 : 165,545 * 0.018 = 2,979.8 (긴 함수 " +"가" * 200 + ")"]},
|
|
{"kind": "machine", "name": "굴착기", "ref": {"tab": "machine", "key": "EQ1"},
|
|
"why": None, "labor": 3899.0, "material": 538.6, "expense": 912.8,
|
|
"text": ["굴착기 노무비", "굴착기 재료비", "굴착기 경비"]},
|
|
],
|
|
"labor": 6878, "material": 538, "expense": 912, "sum": 8328, "why": None,
|
|
"foot": "계 : 8,328",
|
|
} # fmt: skip
|
|
|
|
|
|
SHEETS = {"sg": [_block("SG:A", 1), _block("SG:B", 2)]}
|
|
|
|
|
|
def test_157_2_두_보기_같은_값():
|
|
out = _node(
|
|
f"\nconst t = buildSg({{ sheets: {json.dumps(SHEETS, ensure_ascii=False)} }});"
|
|
"\nconst cards = tabGroups('sg', t);"
|
|
"\nconst ats = cards.flatMap((c) => [c.at, ...c.lines.map((l) => l.at), c.foot.at]);"
|
|
"\nconsole.log(JSON.stringify({ n: t.rows.length, keys: cards.map((c) => c.key), ats,"
|
|
" sums: cards.flatMap((c) => c.lines.map((l) => [l.sum, t.rows[l.at].sum])),"
|
|
" heads: cards.map((c) => [c.no, c.name, c.unit, c.sum]),"
|
|
" links: cards.map((c) => c.lines.map((l) => (l.link ? t.link(l.at, 'kind').key : null))) }));"
|
|
)
|
|
assert out["keys"] == ["SG:A", "SG:B"]
|
|
assert out["ats"] == list(range(out["n"])) # 카드 줄 = 표 줄 번호 그대로 · 같은 차례
|
|
assert all(a == b for a, b in out["sums"])
|
|
assert out["heads"] == [["제 1 호표", "산근1", "m3", 8328], ["제 2 호표", "산근2", "m3", 8328]]
|
|
# 머리 줄 1 · 노무 1 · 중기 3 — 줄 누름 이동은 표와 같은 link
|
|
assert out["links"][0] == [None, "LB2", "EQ1", "EQ1", "EQ1"]
|
|
|
|
|
|
def test_157_2_단추_바꿈():
|
|
out = _node("\nconsole.log(JSON.stringify([viewLabel('table'), viewLabel('cards')]));")
|
|
assert out == ["호표보기", "박스보기"] # 304-1 단추 글 = 그 보기 이름
|
|
|
|
|
|
def test_157_2_기억_실패_때_카드():
|
|
out = _node(
|
|
"\nconst a = [readGroupView(null), readGroupView({ sg: 'x' }), readGroupView({ dg: 'table' }),"
|
|
" readGroupView({ sg: 'table' }), readGroupView('table'), readGroupView('x'),"
|
|
" readGroupView({ dg: 'cards', sg: 'table' })];"
|
|
"\nconsole.log(JSON.stringify(a));"
|
|
)
|
|
# 304-1 한 값 · 옛 탭별 값 = dg 먼저 · 없으면 다른 탭 · 모르는 값 = 카드
|
|
assert out == ["cards", "cards", "table", "table", "table", "cards", "cards"]
|
|
|
|
|
|
def test_157_2_화면_잇기():
|
|
shell = (B09 / "B09_Estimation_UI_Shell.ts").read_text("utf-8")
|
|
assert "isGroupTab(tab)" in shell and "renderGroupPanel(" in shell
|
|
assert not (
|
|
B09 / "B09_Estimation_UI_Tabs_Sangeun_Cards.ts"
|
|
).exists() # 171-2 공용 양식으로 갈음
|
|
css = (ROOT / "ui_template" / "ui_template_group_cards.css").read_text("utf-8")
|
|
assert "white-space: pre-wrap" in css # 긴 산출내역 글 = 카드 안 줄바꿈
|
|
|
|
|
|
class _Whole:
|
|
numbers = {
|
|
"EQ": {"0201-0070": {"이름": "굴착기(무한궤도)", "규격": "0.6㎥"}},
|
|
"LB": {"1001": {"이름": "보통인부"}},
|
|
}
|
|
|
|
|
|
def test_157_3_규격_이름_규격():
|
|
given = {"기계": "0201-0070", "직종": "1001", "규격": 150, "모름": "9999-9999"}
|
|
shown, raw = spec_text(_Whole(), given)
|
|
assert shown == "기계=굴착기(무한궤도) 0.6㎥, 직종=보통인부, 규격=150, 모름=9999-9999"
|
|
assert raw == "기계=0201-0070, 직종=1001, 규격=150, 모름=9999-9999"
|
|
|
|
|
|
def test_157_3_번호는_풍선():
|
|
block = _block("SG:A", 1, "기계=굴착기(무한궤도) 0.6㎥", "기계=0201-0070")
|
|
plain = _block("SG:B", 2, "규격=150", "규격=150")
|
|
listing = [{k: b[k] for k in ("key", "no", "name", "spec", "spec_raw", "unit")}
|
|
for b in (block, plain)] # fmt: skip
|
|
sg_json = json.dumps([block, plain], ensure_ascii=False)
|
|
ls_json = json.dumps(listing, ensure_ascii=False)
|
|
out = _node(
|
|
f"\nconst sg = buildSg({{ sheets: {{ sg: {sg_json} }} }});"
|
|
f"\nconst ls = buildSgList({{ sheets: {{ sg_list: {ls_json} }} }});"
|
|
"\nconst heads = sg.rows.map((r, i) => [r, i])"
|
|
".filter(([r]) => !String(r.key).includes('|'));"
|
|
"\nconsole.log(JSON.stringify({"
|
|
" sg: heads.map(([r, i]) => [r.note, sg.tip(i, 'note') ?? null]),"
|
|
" ls: [0, 1].map((i) => [ls.rows[i].spec, ls.tip(i, 'spec') ?? null]),"
|
|
" other: ls.tip(0, 'name') ?? null }));"
|
|
)
|
|
assert out["sg"] == [
|
|
["기계=굴착기(무한궤도) 0.6㎥", "원문번호 기계=0201-0070"],
|
|
["규격=150", None],
|
|
]
|
|
assert out["ls"] == [
|
|
["기계=굴착기(무한궤도) 0.6㎥", "원문번호 기계=0201-0070"],
|
|
["규격=150", None],
|
|
]
|
|
assert out["other"] is None
|