Merge remote-tracking branch 'origin/sub_laptop_4' into sub_laptop_1
충돌 하나(UI_Side)는 sub_laptop_4 의 층별 구성(옵션 보이기 · 도면 양식은 시스템 층에만)을 취해 풂.
This commit is contained in:
@@ -13,6 +13,8 @@ from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from common_util.common_util_json import atomic_write_json
|
||||
from M01_MasterData import M01_MasterData_Store as m01
|
||||
from M01_MasterData import M01_MasterData_Store_Combo as combo_store
|
||||
from M02_MasterTemplete import M02_MasterTemplete_Matset as matset
|
||||
from M02_MasterTemplete import M02_MasterTemplete_Store as store
|
||||
|
||||
@@ -61,12 +63,36 @@ def ensure(folder: Path) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
def _combo_names() -> dict[str, str]:
|
||||
"""일위대가 조합 키 → 이름(M01 시스템 마스터 · 층 무관) — 못 읽으면 빈 표."""
|
||||
try:
|
||||
rows = m01.read(combo_store.FILE)[0].get("줄") or []
|
||||
except m01.StoreError:
|
||||
return {}
|
||||
return {str(r.get("키")): str(r.get("이름") or "") for r in rows}
|
||||
|
||||
|
||||
def items(folder: Path) -> list[dict[str, Any]]:
|
||||
"""그 층 항목 — SS 줄마다 `{key, 열, 종류, 분류1~3, 단위, 일위대가, 자재조합,
|
||||
도번, 면적번, 재료번}`."""
|
||||
도번, 면적번, 재료번, names}` · `names` = 화면 이름(키 대신 · 없으면 null) —
|
||||
일위대가 = 조합 이름 · 자재조합 = 그 층 자재 조합 이름 ·
|
||||
도번 · 면적번 · 재료번 = 항목(열) 이름."""
|
||||
ua = _combo_names()
|
||||
with store.at(folder):
|
||||
rows = store.read_combos().get("줄", [])
|
||||
return [{"key": r.get("키"), **{k: r.get(k) for k in ITEM_FIELDS}} for r in rows]
|
||||
um = {str(r.get("키")): str(r.get("이름") or "") for r in matset.listing()["줄"]}
|
||||
out = []
|
||||
for r in rows:
|
||||
head = " ".join(str(r[k]) for k in ("종류", "분류1", "분류2", "분류3") if r.get(k))
|
||||
names = {
|
||||
"일위대가": ua.get(str(r.get("일위대가"))) if r.get("일위대가") else None,
|
||||
"자재조합": um.get(str(r.get("자재조합"))) if r.get("자재조합") else None,
|
||||
**{
|
||||
k: (head or r.get("열")) if r.get(k) else None for k in ("도번", "면적번", "재료번")
|
||||
},
|
||||
}
|
||||
out.append({"key": r.get("키"), **{k: r.get(k) for k in ITEM_FIELDS}, "names": names})
|
||||
return out
|
||||
|
||||
|
||||
def _fresh_id(want: str, used: set[str]) -> str:
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
personal 읽기 · 쓰기 = 본인(SYSTEM_ADMIN 은 누구나) · 회사 없음 = 쓰기 409 「회사부터 등록」
|
||||
옛 길(`/api/m02/structures/…` 등 · `M02_MasterTemplete_Router.py`)은 시스템 층 별칭으로 그대로.
|
||||
회사 · 개인 층은 처음 부를 때 빈 뼈대를 만듦(`Items.ensure`).
|
||||
결정(PLAN 21-9): 일위대가(UA) 갈라 내기는 새 UA 가 M01 시스템 마스터에 생기므로 층 길에서도
|
||||
SYSTEM_ADMIN 만 · 첫 진입 뒤 구조물집계표가 이미 있어 같은 이름 새로 쓰기(판 없이)는 409 그대로.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -154,9 +154,12 @@ export function buildSide(opt: SideOptions): SideHandle {
|
||||
className: "m02-side__lists ui-sidebar-panel",
|
||||
children: [
|
||||
summary,
|
||||
section(options.title, options.body),
|
||||
// 구조물 옵션 보이기 · 도면 양식은 시스템 층(마스터 템플릿)에만
|
||||
...(layer === "system"
|
||||
? [section(L("M02_KindDrawing"), bodies.get("drawing")!, ...actionRow("drawing"))]
|
||||
? [
|
||||
section(options.title, options.body),
|
||||
section(L("M02_KindDrawing"), bodies.get("drawing")!, ...actionRow("drawing")),
|
||||
]
|
||||
: []),
|
||||
],
|
||||
});
|
||||
|
||||
@@ -76,7 +76,8 @@ def test_시스템_층은_그대로_항목_목록은_SS_줄(world):
|
||||
rows = client.get("/api/m02/items").json()
|
||||
ss = store.read_combos()["줄"]
|
||||
assert [r["key"] for r in rows] == [r["키"] for r in ss] and rows[0]["key"] == "SS000001"
|
||||
assert set(rows[0]) == {"key", *items_router.items_store.ITEM_FIELDS}
|
||||
assert set(rows[0]) == {"key", "names", *items_router.items_store.ITEM_FIELDS}
|
||||
assert set(rows[0]["names"]) == {"일위대가", "자재조합", "도번", "면적번", "재료번"}
|
||||
assert client.get("/api/m02/layers/system/structure-combos").json() == store.read_combos()
|
||||
# 시스템 층 쓰기는 SYSTEM_ADMIN 만
|
||||
assert client.post("/api/m02/layers/system/structures/rv").status_code == 403
|
||||
@@ -145,14 +146,26 @@ def test_회사_항목을_개인으로_복사(world):
|
||||
row = {"이름": "회사 자재", "담은자재": [_material()]}
|
||||
um = admin.post(f"{base}/material-combos", json={"판": 판, "줄": row}).json()["키"]
|
||||
admin.post(f"{base}/structures/cw/use-combo", json={"종류": "자재조합", "키": um})
|
||||
ss = admin.get("/api/m02/items?layer=company").json()[0]["key"]
|
||||
admin.post(f"{base}/structures/cw/use-combo", json={"종류": "일위대가", "키": "UA000004"})
|
||||
row = admin.get("/api/m02/items?layer=company").json()[0]
|
||||
ss = row["key"]
|
||||
ua_name = items_router.items_store._combo_names()["UA000004"]
|
||||
assert row["names"] == { # 키 대신 화면 이름
|
||||
"일위대가": ua_name,
|
||||
"자재조합": "회사 자재",
|
||||
"도번": "돌기슭막이 찰쌓기 회사형",
|
||||
"면적번": "돌기슭막이 찰쌓기 회사형",
|
||||
"재료번": "돌기슭막이 찰쌓기 회사형",
|
||||
}
|
||||
|
||||
user = _as(world)
|
||||
body = {"from_layer": "company", "from_owner": "7", "key": ss}
|
||||
got = user.post("/api/m02/layers/personal/items/copy", json=body)
|
||||
assert got.status_code == 200, got.text
|
||||
made = got.json()
|
||||
assert made["열"] == "cw" and made["key"] == "SS000001"
|
||||
assert made["열"] == "cw" and made["key"] == "SS000001" # 응답 = 새 SS 키(바로 고름)
|
||||
mine_rows = user.get("/api/m02/items?layer=personal").json()
|
||||
assert mine_rows[0]["key"] == made["key"] and mine_rows[0]["names"]["일위대가"] == ua_name
|
||||
mine = "/api/m02/layers/personal"
|
||||
copy = user.get(f"{mine}/templates/structure/cw").json()["문서"]
|
||||
assert copy["도면"]["entities"] == [{"type": "line"}] and copy["열"] == "cw"
|
||||
|
||||
Reference in New Issue
Block a user