feat(z01): 공종 축 갈래마다 한 줄 — 교목굴취(나무높이) 9갈래가 한 줄에 뭉쳐 어느 높이 값인지 못 집던 것

- 줄 = 갈래(일위대가가 갈래마다 다름) · 산림 365공종 → 627줄 · 건설은 갈래 키가 비어 997 그대로
- 줄 열쇠 = 공종 열쇠#갈래 키(FW-00105#1.1∼1.5 · B08·B09 코드#갈래 꼴) · 갈래 키 글자는 마스터 것 그대로(조립 두 벌 금지)
- 공종 열쇠는 @key 로 함께 보냄 — 거르기(부문·줄 구실)와 stats.work_items 는 공종 단위
- 칸: 갈래 키 목록(variant_keys) → 갈래 하나(variant) · 이름표 공종 축 두 표의 열도 같이 바꿈(묵은 열 시험)
- 화면 코드는 그대로 — 산림 단추 627 · 교목굴취 찾기 10줄(9갈래 + 근원직경) · 2.6∼3.0 칸 집힘
- 시험: 교목굴취 9갈래 차례·열쇠 · 갈래 없는 공종은 # 없는 한 줄 · 갈래 이름으로 찾힘 · 앞 시험 수(365 → 627 · 발파암 3 → 5 · 가짜 자료 두 줄) 맞춤 · Z01·이름표 시험 105 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
This commit is contained in:
2026-09-17 16:52:56 +09:00
co-authored by Claude Opus 5
parent b4294e3483
commit 0ff186c194
3 changed files with 56 additions and 33 deletions
@@ -1389,10 +1389,11 @@
"note": "뿌리부터 전체 경로(「토공 › 토사깍기 › 기계」) — 잎 이름만으론 겹침."
},
{
"key": "variant_keys",
"name_ko": "갈래 키",
"key": "variant",
"name_ko": "갈래",
"unit": "",
"visible": true
"visible": true,
"note": "갈래마다 한 줄(일위대가가 갈래마다 다름) — 줄 열쇠는 공종 열쇠#갈래."
},
{
"key": "pum_tables",
@@ -1452,10 +1453,11 @@
"note": "부문부터 전체 경로(「공통부문 › 토공사 › 굴착 › 굴착(인력/토사)」) — 부문마다 장 번호가 1부터라 부문이 뿌리."
},
{
"key": "variant_keys",
"name_ko": "갈래 키",
"key": "variant",
"name_ko": "갈래",
"unit": "",
"visible": true
"visible": true,
"note": "갈래마다 한 줄(일위대가가 갈래마다 다름) — 줄 열쇠는 공종 열쇠#갈래."
},
{
"key": "pum_tables",
+24 -8
View File
@@ -38,15 +38,15 @@ def _get(client: TestClient, kind: str, **params) -> dict:
def test_산림_평평한_잎_목록과_계산_규칙(client: TestClient) -> None:
listed = client.get("/api/master-data/base-prices").json()["kinds"]
forest = next(i for i in listed if i["kind"] == "work_item_forest")
assert forest["group"] == "work_item" and forest["rows"] == 365
assert forest["group"] == "work_item" and forest["rows"] == 627 # 갈래마다 한 줄
table = _get(client, "work_item_forest", size=500, axis_role="") # 「전부」 — 총칙까지
assert table["total"] == 365 and table["stats"] == {"work_items": 365, "units": 627}
assert table["total"] == 627 and table["stats"] == {"work_items": 365, "units": 627}
assert table["editable"] == [] and set(table["locked"]) == set(table["sortable"])
rows = table["rows"]
assert len({r["@id"] for r in rows}) == 365
rows = table["rows"] + _get(client, "work_item_forest", size=500, page=2, axis_role="")["rows"]
assert len({r["@id"] for r in rows}) == 627
assert (
len({r["name"] for r in rows}) == 365
len({r["@key"] for r in rows}) == len({r["name"] for r in rows}) == 365
) # 잎 이름 겹침 — 경로로 풀림 · 목차 오기 바로잡아 358 → 360(12-17-2 · 12-24-1)
by_code = {r["work_item_code"]: r for r in rows}
assert by_code["FP-09-03-02"]["name"] == "토공 › 토사깍기 › 기계"
@@ -62,7 +62,7 @@ def test_산림_평평한_잎_목록과_계산_규칙(client: TestClient) -> Non
assert not any("불변 열쇠" in line for line in table["notice"])
found = _get(client, "work_item_forest", q="발파암 ›")
assert found["total"] == 3
assert found["total"] == 5 # 절취 · 깍기(연암·보통암·경암) · 집토
def test_건설_공종_축도_같은_길(client: TestClient) -> None:
@@ -101,7 +101,8 @@ def test_불변_열쇠가_오면_id_로_씀_자료_파일은_판_id_로_가림(
monkeypatch.setattr(work_items, "FOLDER", folder)
table = _get(client, "work_item_const")
assert [r["@id"] for r in table["rows"]] == ["CW-00002"]
assert [r["@id"] for r in table["rows"]] == ["CW-00002#갑", "CW-00002#을"] # 갈래마다 한 줄
assert {r["@key"] for r in table["rows"]} == {"CW-00002"}
assert table["rows"][0]["work_item_code"] == "CP-01-01" # 목차 코드는 칸으로 남음
assert table["rows"][0]["name"] == "토공 › 인력"
assert table["stats"] == {"work_items": 1, "units": 2}
@@ -109,7 +110,7 @@ def test_불변_열쇠가_오면_id_로_씀_자료_파일은_판_id_로_가림(
assert _get(client, "work_item_forest")["total"] == 0 # 산림 파일은 이 폴더에 없음
res = client.put(
"/api/master-data/base-prices/work_item_const/CW-00002",
"/api/master-data/base-prices/work_item_const/CW-00002%23갑",
json={"values": {"name": "바꿈"}},
)
assert res.status_code == 400 and "공종 축 뼈대" in res.json()["detail"]
@@ -151,6 +152,21 @@ def test_거르기는_자료에_있는_가름만_서버가_판정(client: TestCl
assert _get(client, "labor", size=1, division="토목부문")["total"] == 261 # 다른 표는 안 거름
def test_갈래마다_한_줄이라_편_하나를_집는다(client: TestClient) -> None:
"""2026-09-17 브레인 ③ — 일위대가는 갈래마다 다름. 교목굴취(나무높이) 한 줄이면 어느 높이 값인지 못 고름."""
rows = _get(client, "work_item_forest", size=50, q="교목굴취(나무높이)")["rows"]
assert [r["variant"] for r in rows] == [
"1.0 이하", "1.1∼1.5", "1.6∼2.0", "2.1∼2.5", "2.6∼3.0",
"3.1∼3.5", "3.6∼4.0", "4.1∼4.5", "4.6∼5.0",
] # fmt: skip
assert rows[1]["@id"] == "FW-00105#1.1∼1.5" and rows[1]["@key"] == "FW-00105"
# 갈래 없는 공종은 한 줄 · 열쇠에 # 없음
plain = _get(client, "work_item_forest", q="교목굴취(근원직경)")["rows"]
assert [(r["@id"], r["variant"]) for r in plain] == [("FW-00106", None)]
# 갈래 이름으로도 찾힘
assert _get(client, "work_item_forest", q="2.1∼2.5")["total"] >= 1
def test_총칙_줄은_기본_감춤_전부를_고르면_보임(client: TestClient) -> None:
"""2026-09-17 브레인 — 값을 안 보내면 상자 기본값(공종)으로 거름 · 화면은 그 기본값을 상자에 보임."""
for kind in ("work_item_forest", "work_item_const"):