refactor(M02): 자재 조합 표를 마스터 템플릿으로 옮김 · M02 좌측 「자재 조합」 컨테이너
- 표 resources/master_data/자재조합.json → resources/master_template/자재조합.json(git mv) · 키 UM 은 표 안 「다음」 번호 · _키대장 · master_keys 의 UM 뺌 · check_master 틀이 새 자리를 같이 봄
- 서버: M01 /api/m01/matset* 뺌 · M02 저장소 M02_MasterTemplete_Matset.py(목록 · 새로 · 고치기 · 지우기 · 쓰는 열 검사) · 길 GET/POST /api/m02/material-combos · PUT/DELETE /api/m02/material-combos/{키} · 갈라 내기(branchMaterialCombo)도 이 저장소로
- 화면: M01 좌측 「자재 조합」 컨테이너 뺌 · M02 좌측 「자재 조합」 컨테이너(찾기 · 키 맨 앞 목록 · 새로 · 본떠 만들기 · 지우기) · 메인 칸 상세(이름 · 비고 · 본뜬키 · 담은 자재 표 · 자재 더하기 · 빼기 · 저장) · 쓰는 열이 있으면 지우기는 확인 창 없이 알림
- 시험: test_m01_matset → test_m02_matset · test_m02_combo_branch 사본 자리 · 실제 자재 코드
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VwJQ5eRrCKf3nH9EFeKvJz
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""자재 조합 — 구조물 열 재료산출이 쓰는 자재 목록 묶음(키 UM · `_틀.md` 11장).
|
||||
|
||||
담은 자재 목록만 지님(수량 · 계산은 재료산출 몫). 일위대가 조합(`master_combo`)과 같은 결 —
|
||||
갈라 내기(M02) 때 새 줄 · 본뜬키 = 원래 키.
|
||||
자리는 마스터 템플릿 `resources/master_template/자재조합.json`(구조물집계표조합.json 과 같은 결) ·
|
||||
키는 표 안 「다음」 번호(`_키대장` 밖). 담은 자재 목록만 지님(수량 · 계산은 재료산출 몫) ·
|
||||
갈라 내기(M02) 때 새 줄 · 본뜬키 = 원래 키. 저장 · 화면은 M02(`M02_MasterTemplete_Matset.py`).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import master_combo as mcb
|
||||
import master_keys as mk
|
||||
|
||||
@@ -15,7 +19,8 @@ FILE = "자재조합.json"
|
||||
TID = "UM"
|
||||
OWNERS = mcb.OWNERS
|
||||
MAX_이름 = mcb.MAX_이름
|
||||
COLS = mk.ROW_ORDER[GROUP] # 키 · 이름 · 담은자재 · 본뜬키 · 소유 · 비고
|
||||
PATH = Path(__file__).resolve().parents[2] / "master_template" / FILE
|
||||
COLS = ("키", "이름", "담은자재", "본뜬키", "소유", "비고")
|
||||
ITEM_COLS = ("코드", "이름", "규격", "단위")
|
||||
|
||||
|
||||
@@ -30,12 +35,18 @@ def check_form(name: str, data: dict) -> list[str]:
|
||||
rows = data.get("줄")
|
||||
if not isinstance(rows, list):
|
||||
return out + [f"{name} · 머리 「줄」 목록 없음"]
|
||||
after = data.get("다음")
|
||||
if not isinstance(after, int) or after < 1:
|
||||
out.append(f"{name} · 머리 「다음」 이 1 이상 정수 아님")
|
||||
after = None
|
||||
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자리 아님")
|
||||
elif after and int(key[2:]) >= after:
|
||||
out.append(f"{where} · 키 번호가 머리 「다음」({after}) 보다 작지 않음")
|
||||
if tuple(row) != COLS:
|
||||
out.append(f"{where} · 열이 한 벌이 아님 — 「{' · '.join(COLS)}」")
|
||||
plain = row.get("이름").strip() if isinstance(row.get("이름"), str) else ""
|
||||
@@ -64,3 +75,10 @@ def check_form(name: str, data: dict) -> list[str]:
|
||||
out.append(f"{where} 줄{at} · 같은 자재를 두 번 담음 「{code}」")
|
||||
codes.add(code)
|
||||
return out
|
||||
|
||||
|
||||
def check_file(path: Path = PATH) -> list[str]:
|
||||
"""마스터 템플릿 자재 조합 표 — 없으면 한 줄."""
|
||||
if not path.is_file():
|
||||
return [f"{path.name} · 마스터 템플릿에 없음"]
|
||||
return check_form(path.name, json.loads(path.read_text(encoding="utf-8")))
|
||||
|
||||
Reference in New Issue
Block a user