# -*- coding: utf-8 -*- """자재 조합 — 구조물 열 재료산출이 쓰는 자재 목록 묶음(키 UM · `_틀.md` 11장). 담은 자재 목록만 지님(수량 · 계산은 재료산출 몫). 일위대가 조합(`master_combo`)과 같은 결 — 갈라 내기(M02) 때 새 줄 · 본뜬키 = 원래 키. """ from __future__ import annotations import master_combo as mcb import master_keys as mk GROUP = "자재조합" FILE = "자재조합.json" TID = "UM" OWNERS = mcb.OWNERS MAX_이름 = mcb.MAX_이름 COLS = mk.ROW_ORDER[GROUP] # 키 · 이름 · 담은자재 · 본뜬키 · 소유 · 비고 ITEM_COLS = ("코드", "이름", "규격", "단위") def items(row: dict) -> list[dict]: got = row.get("담은자재") return got if isinstance(got, list) else [] def check_form(name: str, data: dict) -> list[str]: """파일 틀 + 줄 — 키 모양 · 열 한 벌 · 이름 · 소유 · 담은 자재(빈 목록 · 모양 · 같은 코드 두 번).""" out = [] if data.get("그룹") == GROUP else [f"{name} · 머리 그룹이 「{GROUP}」 아님"] rows = data.get("줄") if not isinstance(rows, list): return out + [f"{name} · 머리 「줄」 목록 없음"] seen_names: dict[str, str] = {} for row in rows: key = str(row.get("키")) where = f"{name} · {key} {row.get('이름') or ''}".strip() if not mk.KEY.fullmatch(key) or key[:2] != TID: out.append(f"{where} · 키 모양이 「{TID}」 + 6자리 아님") if tuple(row) != COLS: out.append(f"{where} · 열이 한 벌이 아님 — 「{' · '.join(COLS)}」") plain = row.get("이름").strip() if isinstance(row.get("이름"), str) else "" if not plain or len(plain) > MAX_이름: out.append(f"{where} · 「이름」 이 없거나 {MAX_이름}자 넘음") elif plain in seen_names: out.append(f"{where} · 「이름」 이 같은 조합과 겹침 — {seen_names[plain]}") seen_names.setdefault(plain, key) if row.get("소유") not in OWNERS: out.append(f"{where} · 소유 「{row.get('소유')}」 — {' · '.join(OWNERS)} 아님") origin = row.get("본뜬키") if origin is not None and not (mk.KEY.fullmatch(str(origin)) and origin[:2] == TID): out.append(f"{where} · 본뜬키 모양 「{origin}」") got = items(row) if not got: out.append(f"{where} · 빈 조합 — 담은 자재가 없음") codes: set[str] = set() for at, one in enumerate(got, start=1): if not isinstance(one, dict) or set(one) - set(ITEM_COLS): out.append(f"{where} 줄{at} · 담은 자재 줄 모양 「{one}」") continue code = str(one.get("코드") or "") if not mk.KEY.fullmatch(code): out.append(f"{where} 줄{at} · 자재 코드 모양 아님 「{code}」") elif code in codes: out.append(f"{where} 줄{at} · 같은 자재를 두 번 담음 「{code}」") codes.add(code) return out