feat(master_data): 기계 갈래 칸 이름 원문으로 · 틀 문서를 지금 데이터 모양에 맞춤

- `기계.json` — 갈래 칸 「세부분류」 → 「원문」(머리 묶음·줄 654) · 줄의 원문 글 칸은 「값원문」 으로(34 줄) · 줄의 `구분`·`상세구분` 과 이름이 겹치지 않게 함
- `check_master` MERGED 는 `master_keys.MERGED` 에서 받음 — 칸 이름을 한 곳에서만 적음 · 머리 「원문」 이 묶음인 파일도 틀 검사가 돎
- `master_keys.MERGED` · `build_기계_건설품셈.py` · `compare_estx.py` — 새 칸 이름
- `M01 서버` — 갈래 칸을 MERGED 에서 찾음(박은 이름 없앰) · 머리 원문이 묶음이면 `book` 은 빈 값
- `_틀.md` — 기계 원문·구분·값원문 · 자재품목 구분 채움과 묶음 문서 · 소요량·계수 「용도」 칸 · 인력 줄 갈래 칸 바로잡음
- `ref/_묶음_기계.md` 새로 — 구분 11 · 상세구분 174 (654 줄)
- `_갱신절차.md` 기계 절 칸 이름
- 검사 — `check_master` 틀 0 · 로직 0 · 시험 83 통과(test_m01_api 25 · test_masterdata_check 58)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
This commit is contained in:
2026-09-20 22:24:13 +09:00
co-authored by Claude Opus 5
parent 6993c6b95e
commit a6f12fb07f
10 changed files with 784 additions and 719 deletions
@@ -2,7 +2,7 @@
본문 md(확정) 표를 읽어 기계 한 줄로 합침. 값은 md 에서만 · 계산·추정 없음.
실행: python resources/master_data/scripts/build_기계_건설품셈.py [--dry]
옛 모양(열쇠)으로 쓰고 `master_keys.adopt` 가 기계.json(키 · 세부분류 건설품셈)으로 받음.
옛 모양(열쇠)으로 쓰고 `master_keys.adopt` 가 기계.json(키 · 원문 건설품셈)으로 받음.
"""
import json
@@ -504,7 +504,7 @@ def compose(rows):
org = dict(v.get("원문83") or {})
org.update({f"{v['sec84']} {a}": b for a, b in (v.get("원문84") or {}).items()})
if org:
row["원문"] = org
row["원문"] = org
out.append(row)
return out
@@ -512,7 +512,7 @@ def compose(rows):
def dumps_row(r):
j = lambda o: json.dumps(o, ensure_ascii=False)
head = f'{{ "열쇠": {j(r["열쇠"])}, "이름": {j(r["이름"])}, "규격": {j(r["규격"])},'
tail = [k for k in ("비고", "원문") if k in r]
tail = [k for k in ("비고", "원문") if k in r]
body = [f' "단위": {j(r["단위"])},', f' "": {j(r[""])},']
body.append(f' "출처": {j(r["출처"])}' + ("," if tail else " }"))
for n, k in enumerate(tail):
+8 -10
View File
@@ -94,8 +94,8 @@ ROW_KEYS = {
),
"품셈재료": ("", "원문번호", "이름", "규격", "단위", "요구절", "연결", "고르기"),
}
# 한 테이블 파일 — 줄의 갈래 칸 · 머리의 갈래 묶음
MERGED = {"인력": "구분", "기계": "세부분류"}
# 한 테이블 파일 — 줄의 갈래 칸 · 머리의 갈래 묶음 (칸 이름은 `master_keys.MERGED` 한 곳에서)
MERGED = {group: slot for group, (_, slot, _) in mk.MERGED.items()}
# 인력 줄 — 모든 줄이 같은 열 한 벌 · 상태 값
LABOR_COLS = (
"",
@@ -222,25 +222,23 @@ def check_form(name: str, data: dict) -> list[str]:
f"{name} · 파일 이름이 「그룹_원문[_NN장_장 제목].json」 · 「인력.json」 · 「기계.json」 아님"
]
out = _head(name, data, m)
# 한 테이블 파일(기계)은 머리 「원문」 이 갈래 묶음 — 원문 이름은 묶음 안에
book = data.get("원문") if isinstance(data.get("원문"), str) else None
try:
tid = mk.table_id(data.get("그룹"), data.get("원문"))
tid = mk.table_id(data.get("그룹"), book)
except KeyError:
return out + [f"{name} · 테이블ID 없는 그룹·원문"]
merged = MERGED.get(data.get("그룹"))
table = data.get("그룹") in mf.TABLE_GROUPS
kind = "" if table else "로직" if data.get("그룹") == "로직" else "요소"
if data.get("원문") == "품셈재료":
if book == "품셈재료":
kind = "품셈재료"
rows = data.get("" if table else "")
if not isinstance(rows, list):
return out + [f"{name} · 머리 「{'' if table else ''}」 목록 없음"]
division = data.get("부문") if kind != "요소" else None
# 장 파일 줄의 갈래 — 구분 = 원문 + 부문 · 상세구분 = 「NN장 장 제목」(파일 이름 그대로)
want = (
(" ".join(x for x in (data.get("원문"), division) if x), _detail(name))
if m.group(4)
else None
)
want = (" ".join(x for x in (book, division) if x), _detail(name)) if m.group(4) else None
for row in rows:
key, number = str(row.get("")), str(row.get("원문번호") or "")
where = f"{name} · {key} {row.get('이름') or number}"
@@ -257,7 +255,7 @@ def check_form(name: str, data: dict) -> list[str]:
f"{where} · 구분·상세구분 「{row.get('구분')} · {row.get('상세구분')}"
f" 이 파일 머리·이름 「{want[0]} · {want[1]}」 과 다름"
)
cols = COLS.get(data.get("원문"))
cols = COLS.get(book)
for need in cols or ROW_KEYS[kind]:
if need not in row:
out.append(f"{where} · 칸 「{need}」 없음")
@@ -269,7 +269,7 @@ def machine(estx: Estx, files: dict, master: mf.Master):
for r in estx.table("MachTitleDat"):
if r.get("Unite") == "hr" and r.get("TC"):
est.setdefault(mach_key(r.get("Name"), r.get("Size")), r)
ours = [m for m in files["기계.json"][""] if m["세부분류"] == "건설품셈"]
ours = [m for m in files["기계.json"][""] if m["원문"] == "건설품셈"]
pairs = [(m, est[k]) for m in ours if (k := mach_key(m["이름"], m["규격"])) in est]
print(f"## 기계 — 우리 {len(ours)} · ESTX 시간당 {len(est)} · 기종·규격 짝 {len(pairs)}")
out = []
+1 -1
View File
@@ -134,7 +134,7 @@ LABOR = {
}
MERGED = {
"인력": ("인력.json", "구분", LABOR),
"기계": ("기계.json", "세부분류", {"건설품셈": "건설품셈", "산림품셈": "산림품셈"}),
"기계": ("기계.json", "원문", {"건설품셈": "건설품셈", "산림품셈": "산림품셈"}),
}
DIVISIONS = ("공통", "토목", "건축", "기계설비", "유지관리")
# 장 파일 줄의 열 차례 — 앞 넷은 한 줄에 · 「그룹」(소요량 파일 안의 계수 표 표시)은 맨 뒤