wip(z01): 총칙 기본 감춤 잣대화 — 병합 전 임시 보관

This commit is contained in:
2026-09-17 16:58:05 +09:00
parent c044726d41
commit 6680cb0ff3
4 changed files with 89 additions and 26 deletions
+33 -10
View File
@@ -156,17 +156,33 @@ def _facets(kind: str) -> dict[str, dict[str, str]]:
return {_key(i): {key: str(i.get(key) or "") for key in FILTER_KEYS} for i in items}
def _role_names() -> dict[str, str]:
"""줄 구실 이름 — `axis_policy.json`(데스크탑 서브 잣대) 한 곳에서."""
def _policy() -> dict[str, Any]:
"""줄 구실 잣대 — `axis_policy.json`(데스크탑 서브) 한 곳에서."""
path = FOLDER / "axis_policy.json"
if not path.is_file():
return {}
roles = _read(str(path), path.stat().st_mtime_ns).get("roles") or {}
return {key: str(role.get("name_ko") or key) for key, role in roles.items()}
return _read(str(path), path.stat().st_mtime_ns) if path.is_file() else {}
def _role_names() -> dict[str, str]:
"""거르기 상자에 뜰 이름. 목록에서는 「총칙」이 아니라 「공종 아님 · 규정·기준」으로 적는다."""
roles = _policy().get("roles") or {}
return {
key: str(role.get("list_label") or role.get("name_ko") or key)
for key, role in roles.items()
}
def _default_of(key: str) -> str:
"""이 가름의 기본값 — **잣대가 정한다**(화면도 서버도 스스로 가르지 않음).
총칙 줄은 표가 붙어 목록에 섞여 뜨지만 공종이 아니라 규정·기준이다. 기본은 안 보이되
상자를 고르면 보인다 — ⚠ **지운 것이 아니라 감춘 것**이다(2026-09-17 브레인).
"""
wanted = _policy().get("list_default") or {}
return str(wanted.get("value") or ALL) if wanted.get("filter") == key else ALL
def filters(kind: str, rows: list[dict[str, Any]]) -> list[dict[str, Any]]:
"""거르기 상자 — 값이 둘 이상 갈리는 가름만 · 기본은 「전부」(안 거름)."""
"""거르기 상자 — 값이 둘 이상 갈리는 가름만. 기본**잣대**가 정한다(`list_default`)."""
facets = _facets(kind)
labels = {"division": ("부문", {}), "axis_role": ("줄 구실", _role_names())}
out = []
@@ -179,13 +195,14 @@ def filters(kind: str, rows: list[dict[str, Any]]) -> list[dict[str, Any]]:
if len(values) < 2:
continue
label, names = labels[key]
default = _default_of(key)
out.append(
{
"key": key,
"label": label,
"options": [{"value": ALL, "label": "전부", "rows": len(rows)}]
+ [{"value": v, "label": names.get(v, v), "rows": counts[v]} for v in values],
"default": ALL,
"default": default if default in values else ALL,
}
)
return out
@@ -194,9 +211,15 @@ def filters(kind: str, rows: list[dict[str, Any]]) -> list[dict[str, Any]]:
def apply_filters(
kind: str, rows: list[dict[str, Any]], picked: dict[str, str]
) -> list[dict[str, Any]]:
"""고른 값으로 거른다. **안 고른 가름은 잣대의 기본값**을 쓴다.
⚠ 기본값을 서버가 매기는 까닭 — 화면만 기본값을 알면 「상자엔 공종이라 떠 있는데 목록엔
총칙이 섞여 있는」 어긋남이 난다. 「전부」는 빈 값을 **적어 보내면** 된다.
"""
facets = _facets(kind)
for key, value in picked.items():
if key in FILTER_KEYS and value != ALL:
for key in FILTER_KEYS:
value = picked[key] if key in picked else _default_of(key)
if value != ALL:
rows = [r for r in rows if facets.get(r["@id"], {}).get(key) == value]
return rows
@@ -1933,11 +1933,11 @@
"merged_columns": 172,
"files": 41,
"tables": 100,
"columns": 532,
"value_groups": 202,
"columns": 534,
"value_groups": 203,
"unknown": 0,
"value_groups_by_kind": {
"doc": 136,
"doc": 137,
"value": 66
}
},
@@ -7533,6 +7533,18 @@
"name_ko": "까닭",
"unit": "",
"visible": true
},
{
"key": "list_label",
"name_ko": "목록에 뜰 이름",
"unit": "",
"visible": true
},
{
"key": "hidden_by_default",
"name_ko": "기본으로 감추나",
"unit": "",
"visible": true
}
]
},
@@ -7655,6 +7667,12 @@
"name_ko": "가르는 차례",
"summary": "총칙 → 공종 → 묶는 마디 → 빈 잎 차례로 본다.",
"kind": "doc"
},
{
"key": "list_default",
"name_ko": "목록 기본 거르기",
"summary": "목록을 열면 무엇만 보일지 — 기본은 공종만. 총칙은 감춘 것이지 지운 것이 아니다.",
"kind": "doc"
}
]
},
@@ -13,25 +13,33 @@
"work_item": {
"name_ko": "공종",
"rule": "품셈 표가 붙은 줄",
"keep": true
"keep": true,
"list_label": "공종",
"hidden_by_default": false
},
"group": {
"name_ko": "묶는 마디",
"rule": "표는 없고 아래를 묶는 줄",
"keep": true,
"why": "`parent_mode`(choose_one·sum_steps)가 여기 붙는다 — 계산 규칙을 지닌 줄이다."
"why": "`parent_mode`(choose_one·sum_steps)가 여기 붙는다 — 계산 규칙을 지닌 줄이다.",
"list_label": "묶는 마디",
"hidden_by_default": true
},
"general_provision": {
"name_ko": "총칙",
"rule": "`general_provision` 뿌리 아래의 줄",
"keep": true,
"why": "문서 구역이나 값표가 붙어 원가가 읽는다."
"why": "문서 구역이나 값표가 붙어 원가가 읽는다.",
"list_label": "공종 아님 · 규정·기준",
"hidden_by_default": true
},
"empty": {
"name_ko": "빈 잎",
"rule": "표도 아래도 없는 잎",
"keep": true,
"why": "원문에 표가 안 붙은 자리. 지우면 「있었는지 없었는지」가 안 남는다."
"why": "원문에 표가 안 붙은 자리. 지우면 「있었는지 없었는지」가 안 남는다.",
"list_label": "빈 잎",
"hidden_by_default": true
}
},
"decision_order": [
@@ -106,5 +114,10 @@
"note": "총칙 표시 전 셈(랩탑 메인 첫 산출). 뿌리를 붙이면 `general_provision` 으로 옮겨 간다 — 줄이 줄지는 않는다."
}
}
},
"list_default": {
"filter": "axis_role",
"value": "work_item",
"why": "목록 기본은 **공종만**(산림 306 · 건설 983). 총칙 줄은 표가 붙어 있어 목록에 섞여 뜨는데, 공종이 아니라 규정·기준이다. 상자를 따로 만들지 않고 **기본 감춤 + 고르면 보임**으로 간다 (2026-09-17 브레인). ⚠ 지운 것이 아니라 감춘 것이다."
}
}
+18 -9
View File
@@ -41,13 +41,14 @@ def test_산림_평평한_잎_목록과_계산_규칙(client: TestClient) -> Non
assert forest["group"] == "work_item" and forest["rows"] == 365
table = _get(client, "work_item_forest", size=500)
assert table["total"] == 365 and table["stats"] == {"work_items": 365, "units": 627}
# 2026-09-17 목록 기본이 **공종만**(잣대 `list_default`) — 뜨는 줄 306, 총칙 59 는 감춰져 있다.
# `stats` 는 쪽 나누기·거르기와 무관한 **전체** 셈이라 365 그대로다.
assert table["total"] == 306 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
assert (
len({r["name"] for r in rows}) == 365
) # 잎 이름 겹침 — 경로로 풀림 · 목차 오기 바로잡아 358 → 360(12-17-2 · 12-24-1)
assert len({r["@id"] for r in rows}) == 306 # 뜨는 줄 = 공종만
# 잎 이름 겹침 — 경로로 풀림. 뜨는 줄만큼 이름도 다 달라야 한다(겹치면 사람이 못 고름).
assert len({r["name"] for r in rows}) == 306
by_code = {r["work_item_code"]: r for r in rows}
assert by_code["FP-09-03-02"]["name"] == "토공 토사깍기 기계"
@@ -68,7 +69,8 @@ def test_산림_평평한_잎_목록과_계산_규칙(client: TestClient) -> Non
def test_건설_공종_축도_같은_길(client: TestClient) -> None:
"""건설(2026-09-17 뽑음) — 부문이 뿌리라 경로가 부문부터 · 열쇠 CW- · 계산 규칙은 전부 choose_one."""
table = _get(client, "work_item_const", size=500)
assert table["total"] == table["stats"]["work_items"] > 900
# 기본이 공종만이라 뜨는 줄 983 · 전체 997(총칙 14 감춤)
assert table["total"] == 983 and table["stats"]["work_items"] == 997
rows = table["rows"]
assert all(r["@id"].startswith("CW-") for r in rows)
assert all(r["name"].split(" ")[0].endswith("부문") for r in rows)
@@ -123,7 +125,12 @@ def test_거르기는_자료에_있는_가름만_서버가_판정(client: TestCl
assert set(by_key) == {"division", "axis_role"}
division = by_key["division"]
assert division["default"] == ""
assert division["options"][0] == {"value": "", "label": "전부", "rows": const["total"]}
# 거르기 상자의 셈은 **전체** 기준이다 — 「전부 997」. 지금 뜨는 줄(`total`)과는 다르다.
assert division["options"][0] == {
"value": "",
"label": "전부",
"rows": const["stats"]["work_items"],
}
assert [o["value"] for o in division["options"][1:]] == [
"공통부문",
"토목부문",
@@ -131,10 +138,12 @@ def test_거르기는_자료에_있는_가름만_서버가_판정(client: TestCl
"기계설비부문",
"유지관리부문",
]
assert sum(o["rows"] for o in division["options"][1:]) == const["total"]
assert sum(o["rows"] for o in division["options"][1:]) == const["stats"]["work_items"]
# 2026-09-17 목록에서는 「총칙」이 아니라 **공종이 아님**을 드러내는 이름으로 적는다(브레인).
assert {o["value"]: o["label"] for o in by_key["axis_role"]["options"]}[
"general_provision"
] == "총칙"
] == "공종 아님 · 규정·기준"
assert by_key["axis_role"]["default"] == "work_item" # 기본 감춤 — 지운 것이 아니라 감춘 것
civil = _get(client, "work_item_const", size=500, division="토목부문")
assert civil["total"] == next(