feat(M02): 프로젝트에서 만든 개인 층 항목도 경로 그대로(PLAN 26-2a · 26-2b 이음)
- M02_Item_Personal.create_item — 경로를 제목행 넷에 접지 않고 그대로(머리 줄 수는 집계표 저장이 맞춤) · 같은 경로면 「이름 (2)」 · 같은 앞마디 형제 곁에 끼움 - 시험 test_m02_tree 6(깊이 5 새 항목 · 같은 경로 이름 (2)) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KmELpdXFDRZHhfbGuRhSmL
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
개인 층 새 항목 = 구조물집계표 새 열 하나 + 빈 도면 · 면적산출 · 재료산출(번호 · SS 키는 저장소가
|
||||
줌). [개인에 저장]은 구조물 복사본의 열 정의 · 도면 · 면적 · 재료 · 자재조합 · 입력연결을 담음 —
|
||||
단가 묶음 · 입력값 · 고른자재는 프로젝트 몫이라 안 가져감. 쓰기는 지금 층 저장소 함수(`store.at` ·
|
||||
`store.write` · `matset.create` · 항목 연결 `write_file`) — sub4 나무 길
|
||||
(`POST /layers/{layer}/tree`)이 오면 그리로.
|
||||
`store.write` · `matset.create` · 항목 연결 `write_file`) — 나무 고침(`M02_MasterTemplete_Tree`)과
|
||||
같은 집계표 저장 한 줄기(경로 · 머리 줄 수 맞춤 · 번호 · SS 장부)를 탐(PLAN 26-2a).
|
||||
권한(본인 개인 층 · 회사 없음 409)은 부르는 쪽 몫.
|
||||
"""
|
||||
|
||||
@@ -19,24 +19,30 @@ from M02_MasterTemplete import M02_MasterTemplete_Inputs as inputs_store
|
||||
from M02_MasterTemplete import M02_MasterTemplete_Items as items_store
|
||||
from M02_MasterTemplete import M02_MasterTemplete_Matset as matset
|
||||
from M02_MasterTemplete import M02_MasterTemplete_Store as store
|
||||
from M02_MasterTemplete import M02_MasterTemplete_Tree as tree
|
||||
from M02_MasterTemplete import M02_Template_Layers as layers
|
||||
from M02_MasterTemplete.M02_Item_Source import LINK_FILE, UM_FILE, read_json
|
||||
|
||||
#: 복사본 파일 → 층 양식 종류
|
||||
PART_KINDS = (("도면.json", "structure"), ("면적.json", "area"), ("재료.json", "material"))
|
||||
LEVELS = 4 # 지금 집계표 제목행 층 수 — 26-2a 경로 모델이 오면 깊이 자유
|
||||
|
||||
|
||||
def heads_of(path: list[str], name: str | None) -> list[str]:
|
||||
"""경로 + 이름 → 제목행(`머리`) — 빈 칸은 뺌 · 넷을 넘으면 넷째 칸에 이어 붙임.
|
||||
|
||||
ponytail: 제목행 4층 한계 — 26-2a(sub4) 경로 모델이 오면 경로를 그대로 적음."""
|
||||
"""경로 + 이름 → 항목 경로(깊이 자유 · 빈 칸은 뺌) — 머리 줄 수는 집계표 저장이 맞춤."""
|
||||
full = [str(p).strip() for p in [*path, name or ""] if str(p or "").strip()]
|
||||
if not full:
|
||||
raise ValueError("새 항목의 경로 · 이름이 비어 있습니다.")
|
||||
if len(full) > LEVELS:
|
||||
full = [*full[: LEVELS - 1], " ".join(full[LEVELS - 1 :])]
|
||||
return [*full, *[""] * (LEVELS - len(full))]
|
||||
return full
|
||||
|
||||
|
||||
def _free_path(doc: dict[str, Any], full: list[str]) -> list[str]:
|
||||
"""같은 경로 항목이 이미 있으면 마지막 이름을 「이름 (2)」 로
|
||||
(나무는 같은 경로 두 항목을 안 둠)."""
|
||||
taken = [tree.path_of(c) for c in doc.get("열", []) if tree.is_item(c)]
|
||||
out, n = list(full), 2
|
||||
while out in taken:
|
||||
out, n = [*full[:-1], f"{full[-1]} ({n})"], n + 1
|
||||
return out
|
||||
|
||||
|
||||
def _new_matset(row: dict[str, Any], fallback: str) -> str:
|
||||
@@ -73,10 +79,12 @@ def create_item(
|
||||
new_id = items_store._fresh_id(str(base_col.get("id") or "item").split("@")[0], used)
|
||||
um_row = read_json(copy / UM_FILE) if copy else None
|
||||
um_key = _new_matset(um_row, heads[0]) if isinstance(um_row, dict) else None
|
||||
heads = _free_path(doc, heads)
|
||||
column = {
|
||||
**json.loads(json.dumps(base_col)),
|
||||
"id": new_id,
|
||||
"머리": heads,
|
||||
"경로": heads,
|
||||
"꼴": "수",
|
||||
"단위": unit or base_col.get("단위") or base_row.get("단위"),
|
||||
"일위대가": base_col.get("일위대가") or base_row.get("일위대가"),
|
||||
@@ -85,7 +93,7 @@ def create_item(
|
||||
column.pop("본뜬열", None)
|
||||
if origin:
|
||||
column["본뜬"] = origin
|
||||
doc["열"] = [*doc.get("열", []), column]
|
||||
tree._place(doc, column) # 같은 앞마디 형제 곁(제목행 병합이 이어지게)
|
||||
store.write("table", store.STRUCTURE_TABLE, table["판"], doc) # 빈 세 파일 · 번호 · SS
|
||||
for file, kind in PART_KINDS if copy else ():
|
||||
got = read_json(copy / file)
|
||||
@@ -103,7 +111,7 @@ def create_item(
|
||||
if isinstance(links, dict) and links.get("줄"):
|
||||
inputs_store.write_file(new_id, {"판": 1, "줄": links["줄"]})
|
||||
ss = next(r for r in store.read_combos()["줄"] if r.get("열") == new_id)
|
||||
return {"key": ss["키"], "열": new_id, "이름": " ".join(h for h in heads if h)}
|
||||
return {"key": ss["키"], "열": new_id, "이름": tree.name_of(heads)}
|
||||
|
||||
|
||||
def personal_item(company: int, user: int, made: dict[str, Any]) -> dict[str, Any]:
|
||||
|
||||
@@ -245,3 +245,17 @@ def test_표_저장과_나무가_한_줄기(world):
|
||||
)
|
||||
assert "rv" not in [r["열"] for r in Tree(admin, "system").now["items"]]
|
||||
assert not (world["system"] / "structure" / "rv.json").is_file()
|
||||
|
||||
|
||||
def test_프로젝트에서_새_항목도_경로_그대로(world):
|
||||
"""개인에 저장 · 프로젝트에서 새 항목(`M02_Item_Personal`)도 경로를 넷에 접지 않고 그대로 ·
|
||||
같은 경로면 「이름 (2)」."""
|
||||
from M02_MasterTemplete import M02_Item_Personal as personal
|
||||
|
||||
folder = layers.personal_dir(7, 42)
|
||||
made = personal.create_item(folder, ["가", "나", "다", "라"], "마", "m")
|
||||
again = personal.create_item(folder, ["가", "나", "다", "라"], "마", "m")
|
||||
t = Tree(_as(world), "personal")
|
||||
assert t.item(["가", "나", "다", "라", "마"])["key"] == made["key"]
|
||||
assert t.item(["가", "나", "다", "라", "마 (2)"])["key"] == again["key"]
|
||||
assert made["이름"] == "가 나 다 라 마"
|
||||
|
||||
Reference in New Issue
Block a user