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:
@@ -259,8 +259,6 @@ def check_combo_form(name: str, data: dict) -> list[str]:
|
||||
def check_form(name: str, data: dict) -> list[str]:
|
||||
if name == mcb.FILE:
|
||||
return check_combo_form(name, data)
|
||||
if name == mmc.FILE:
|
||||
return mmc.check_form(name, data)
|
||||
if name in SPECIAL_FILES:
|
||||
return []
|
||||
m = _FILE.match(name)
|
||||
@@ -685,6 +683,7 @@ def main(argv: list[str]) -> int:
|
||||
report = {}
|
||||
if mode in ("틀", "전부"):
|
||||
report["틀"] = [x for name, data in files.items() for x in check_form(name, data)]
|
||||
report["틀"] += mmc.check_file() # 자재 조합은 마스터 템플릿 표
|
||||
if mode in ("본문", "전부"):
|
||||
report["본문"] = check_body(files)
|
||||
if mode in ("로직", "전부"):
|
||||
|
||||
@@ -32,13 +32,12 @@ TABLES = {
|
||||
("로직", "건설품셈"): "GC",
|
||||
("로직", "자체"): "GX",
|
||||
("일위대가조합", None): "UA",
|
||||
("자재조합", None): "UM",
|
||||
}
|
||||
GROUP_OF = {tid: group for (group, _), tid in TABLES.items()}
|
||||
IDS = tuple(GROUP_OF)
|
||||
# 줄에 원문번호를 두지 않는 테이블 — 자재품목은 번호가 남의 품번이라 이름 몫을 못 하고,
|
||||
# 조합은 원문이 없어 번호 자체가 없음(대조는 대장에만)
|
||||
NO_NUMBER = ("MT", "UA", "UM")
|
||||
NO_NUMBER = ("MT", "UA")
|
||||
|
||||
|
||||
def table_id(group: str, book: str | None) -> str:
|
||||
@@ -187,7 +186,6 @@ ROW_ORDER = {
|
||||
"소유",
|
||||
"비고",
|
||||
),
|
||||
"자재조합": ("키", "이름", "담은자재", "본뜬키", "소유", "비고"),
|
||||
}
|
||||
OLD_CHAPTER = re.compile(r"^(소요량|계수|로직)_(산림품셈|건설품셈)_(\D*)(\d+)장\.json$")
|
||||
CHAPTER = re.compile(r"^(소요량|계수|로직)_(산림품셈|건설품셈|자체)_(\d\d)장_.+\.json$")
|
||||
|
||||
@@ -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