refactor(M02): 재료산출 시트 지움 — 종류 material · 재료번 SM · 좌측 줄 · 집계표 「재료산출」 줄 · 카드 · 전체 편집 · 복사 길 · 프로젝트 복사본 「재료」 · 고르기 모달 · 시스템 층 · fixture · 시험
- 새 프로젝트 씨앗(KINDS)에서도 빠짐 · 새 열은 구조물 도면 · 면적산출만 만듦 - storage 층(회사 · 개인 · 프로젝트) material/ 파일은 지우지 않음(읽기만 끊음) - 장부 재료번 칸은 다음 집계표 [저장] 때 빠짐 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPJGtfXo6GMbcpiboQC4uK
This commit is contained in:
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"종류": "통합문서",
|
||||
"판": 1,
|
||||
"열": "item1",
|
||||
"서식": [
|
||||
{}
|
||||
],
|
||||
"시트": [
|
||||
{
|
||||
"id": "s1",
|
||||
"이름": "재료산출",
|
||||
"칸": {}
|
||||
}
|
||||
],
|
||||
"활성": "s1",
|
||||
"재료번": "SM-000001"
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"종류": "통합문서",
|
||||
"판": 1,
|
||||
"열": "item2",
|
||||
"서식": [
|
||||
{}
|
||||
],
|
||||
"시트": [
|
||||
{
|
||||
"id": "s1",
|
||||
"이름": "재료산출",
|
||||
"칸": {}
|
||||
}
|
||||
],
|
||||
"활성": "s1",
|
||||
"재료번": "SM-000002"
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"종류": "통합문서",
|
||||
"판": 1,
|
||||
"열": "item3",
|
||||
"서식": [
|
||||
{}
|
||||
],
|
||||
"시트": [
|
||||
{
|
||||
"id": "s1",
|
||||
"이름": "재료산출",
|
||||
"칸": {}
|
||||
}
|
||||
],
|
||||
"활성": "s1",
|
||||
"재료번": "SM-000003"
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"종류": "통합문서",
|
||||
"판": 1,
|
||||
"열": "c4",
|
||||
"서식": [
|
||||
{}
|
||||
],
|
||||
"시트": [
|
||||
{
|
||||
"id": "s1",
|
||||
"이름": "재료산출",
|
||||
"칸": {
|
||||
"I5": {
|
||||
"값": 6
|
||||
}
|
||||
},
|
||||
"연결": [
|
||||
{
|
||||
"키": "MT003810",
|
||||
"이름": "모 래, 서울, 도착도 강모래",
|
||||
"칸": "I5",
|
||||
"단위": "㎥",
|
||||
"자재": {
|
||||
"코드": "MT003810",
|
||||
"이름": "모 래, 서울, 도착도",
|
||||
"규격": "강모래",
|
||||
"단위": "㎥"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"활성": "s1",
|
||||
"재료번": "SM01010101",
|
||||
"계산값": {}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"종류": "통합문서",
|
||||
"판": 1,
|
||||
"열": "ms",
|
||||
"서식": [
|
||||
{}
|
||||
],
|
||||
"시트": [
|
||||
{
|
||||
"id": "s1",
|
||||
"이름": "재료산출",
|
||||
"칸": {}
|
||||
}
|
||||
],
|
||||
"활성": "s1",
|
||||
"재료번": "SM10010100"
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"종류": "통합문서",
|
||||
"판": 1,
|
||||
"열": "pp_len",
|
||||
"서식": [
|
||||
{}
|
||||
],
|
||||
"시트": [
|
||||
{
|
||||
"id": "s1",
|
||||
"이름": "재료산출",
|
||||
"칸": {}
|
||||
}
|
||||
],
|
||||
"활성": "s1",
|
||||
"재료번": "SM03010100"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
"""시험 안 마스터 견본(PLAN 26-5a) — 초기화 전 마스터 층을 줄여 얼린 것
|
||||
(`fixtures/m02_master_sample`).
|
||||
|
||||
집계표(바인딩 열 54) · SS 장부(51 줄) · 자재조합 · 세 파일은 rv · c4 · pp_len · ms 넷(도면 줄임) —
|
||||
집계표(바인딩 열 54) · SS 장부(51 줄) · 도면 · 면적 파일은 rv · c4 · pp_len · ms 넷(도면 줄임) —
|
||||
시험은 실제 `resources/master_template` 을 안 읽고 이 견본을 임시 폴더에 복사해 씀.
|
||||
"""
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""저장 뒤 식 · 값 유지 — M02 면적산출 · 재료산출 저장본을 서버 엔진으로 다시 풀면 저장된 `계산값` 과 같음.
|
||||
"""저장 뒤 식 · 값 유지 — M02 면적산출 저장본을 서버 엔진으로 다시 풀면 저장된 `계산값` 과 같음.
|
||||
|
||||
시험 안 견본 저장본(`fixtures/m02_master_sample` · PLAN 26-5a)을 읽기만 함.
|
||||
저장 때 서버가 적은 값과 지금 엔진 풀이가 어긋나면 화면을 다시 열 때
|
||||
@@ -18,7 +18,7 @@ pytestmark = pytest.mark.skipif(shutil.which("node") is None, reason="node 가
|
||||
|
||||
def _books() -> list[tuple[str, dict]]:
|
||||
out = []
|
||||
for kind in ("area", "material"):
|
||||
for kind in ("area",):
|
||||
for path in sorted((FOLDER / kind).glob("[!.]*.json")):
|
||||
book = json.loads(path.read_text(encoding="utf-8"))
|
||||
if isinstance(book, dict) and book.get("시트"):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""F — 면적산출(area) · 재료산출(material) 저장 · 옛 산출근거(basis) 옮김 · [저장] 때 서버 계산값 ·
|
||||
"""F — 면적산출(area) 저장 · 옛 산출근거(basis) 옮김 · [저장] 때 서버 계산값 ·
|
||||
알약 연결(`연결`)은 저장 · 복사 때 문서와 같이.
|
||||
|
||||
서버 Node 풀이는 `test_spreadsheet_node.py` 가 따로 봄 — 여기는 `with_server_values` 를 바꿔 끼워
|
||||
@@ -42,7 +42,7 @@ def _write(folder, kind, column, doc):
|
||||
|
||||
|
||||
def test_옛_산출근거를_면적산출로_옮기고_번호_8자리(client, tmp_path):
|
||||
"""12장 파일(SD · SC 6자리 · basis/) → SA 로 옮김 · 끝에 00 · 재료산출 새로 · 내용 그대로."""
|
||||
"""12장 파일(SD · SC 6자리 · basis/) → SA 로 옮김 · 끝에 00 · 재료산출은 안 만듦 · 내용 그대로."""
|
||||
structure = {"양식": "구조물도면", "종류": "structure", "판": 1, "열": "rv", "도번": "SD010101"}
|
||||
_write(tmp_path, "structure", "rv", {**structure, "도면": {"entities": [{"type": "line"}]}})
|
||||
old = {**store._blank("area", "rv"), "표번": "SC010101", "연결": LINKS}
|
||||
@@ -56,30 +56,26 @@ def test_옛_산출근거를_면적산출로_옮기고_번호_8자리(client, tm
|
||||
"A2": {"값": "터파기"}
|
||||
}
|
||||
assert store.read("structure", "rv")["문서"]["도번"] == "SD01010100"
|
||||
material = store.read("material", "rv")["문서"]
|
||||
assert (material["재료번"], material["시트"][0]["이름"]) == ("SM01010100", "재료산출")
|
||||
assert material["시트"][0]["칸"] == {} and material["서식"] == [{}] # 진짜 빈 시트
|
||||
assert not (tmp_path / "material").exists() # 재료산출은 없앰
|
||||
before = {p: p.read_bytes() for p in tmp_path.rglob("*.json")}
|
||||
assert store.renumber() == {"옮김": [], "지움": [], "바꿈": [], "새로": []}
|
||||
assert before == {p: p.read_bytes() for p in tmp_path.rglob("*.json")} # 두 번 돌려도 같음
|
||||
|
||||
|
||||
def test_새_구조물_도면은_면적_재료_진짜_빈_시트_같은_8자리(client):
|
||||
def test_새_구조물_도면은_면적_진짜_빈_시트_같은_8자리(client):
|
||||
made1 = client.post("/api/m02/structures/rv").json()["문서"]
|
||||
made2 = client.post("/api/m02/structures/pv_b").json()["문서"]
|
||||
# 새 항목 번호 = 자리 뜻 없는 일련번호(PLAN 26-1)
|
||||
assert made1["도번"] == "SD-000001" and made2["도번"] == "SD-000002"
|
||||
for kind, key, head in (("area", "면적번", "SA"), ("material", "재료번", "SM")):
|
||||
for kind, key, head in (("area", "면적번", "SA"),):
|
||||
doc = client.get(f"/api/m02/templates/{kind}/pv_b").json()["문서"]
|
||||
assert doc[key] == f"{head}-000002"
|
||||
assert doc["시트"][0]["칸"] == {} and doc["서식"] == [{}] # 머리 줄 없음
|
||||
numbers = client.get("/api/m02/structures/numbers").json()
|
||||
assert numbers["pv_b"] == {"도번": "SD-000002", "면적번": "SA-000002", "재료번": "SM-000002"}
|
||||
assert numbers["pv_b"] == {"도번": "SD-000002", "면적번": "SA-000002"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("kind", "key", "head"), [("area", "면적번", "SA"), ("material", "재료번", "SM")]
|
||||
)
|
||||
@pytest.mark.parametrize(("kind", "key", "head"), [("area", "면적번", "SA")])
|
||||
def test_다른_열_내용을_복사해_가져옴_연결도_같이(client, kind, key, head):
|
||||
store.renumber()
|
||||
got = client.get(f"/api/m02/templates/{kind}/rv").json()
|
||||
@@ -117,21 +113,21 @@ def test_저장은_서버_계산값만_적음_연결_두고_번호는_서버_것
|
||||
|
||||
|
||||
def test_못_풀면_저장을_막음(client, monkeypatch):
|
||||
store._ensure("material", "rv")
|
||||
got = client.get("/api/m02/templates/material/rv").json()
|
||||
store._ensure("area", "rv")
|
||||
got = client.get("/api/m02/templates/area/rv").json()
|
||||
|
||||
def broken(_book):
|
||||
raise spreadsheet.RecalcError("스프레드시트 계산 실패 — 시험")
|
||||
|
||||
monkeypatch.setattr(spreadsheet, "with_server_values", broken)
|
||||
r = client.put("/api/m02/templates/material/rv", json={"판": got["판"], "문서": got["문서"]})
|
||||
r = client.put("/api/m02/templates/area/rv", json={"판": got["판"], "문서": got["문서"]})
|
||||
assert r.status_code == 503
|
||||
assert client.get("/api/m02/templates/material/rv").json()["판"] == got["판"]
|
||||
assert client.get("/api/m02/templates/area/rv").json()["판"] == got["판"]
|
||||
|
||||
|
||||
def test_층_규칙과_프로젝트_복사(client, tmp_path, monkeypatch):
|
||||
client.post("/api/m02/structures/rv")
|
||||
for kind in ("area", "material"):
|
||||
for kind in ("area",):
|
||||
doc = store.read(kind, "rv")["문서"]
|
||||
layers.check_skeleton(kind, doc)
|
||||
for bad in ({}, {**doc, "시트": {}}):
|
||||
@@ -140,5 +136,6 @@ def test_층_규칙과_프로젝트_복사(client, tmp_path, monkeypatch):
|
||||
layers.check_skeleton("structure", {"도면": {"entities": []}}) # 산출근거 없어도 됨
|
||||
monkeypatch.setattr(layers, "SYSTEM_ROOT", tmp_path)
|
||||
copied = layers.seed_project(tmp_path / "project")
|
||||
for kind in ("area", "material"):
|
||||
assert not any(k.startswith("material/") for k in copied["작업본"]) # 재료산출 없앰
|
||||
for kind in ("area",):
|
||||
assert f"{kind}/rv" in copied["작업본"] and f"{kind}/rv" in copied["초기"]
|
||||
|
||||
@@ -54,7 +54,7 @@ def world(tmp_path: Path, monkeypatch, master_copy: Path) -> dict[str, Any]:
|
||||
system.mkdir()
|
||||
for name in (layers.COMBO_FILE,):
|
||||
shutil.copy2(REAL / name, system / name)
|
||||
for kind in ("table", "structure", "area", "material"):
|
||||
for kind in ("table", "structure", "area"):
|
||||
shutil.copytree(REAL / kind, system / kind)
|
||||
monkeypatch.setattr(layers, "SYSTEM_ROOT", system)
|
||||
monkeypatch.setattr(m01, "FOLDER", master_copy)
|
||||
|
||||
@@ -196,7 +196,7 @@ def test_분류_더하기로_복사한_열은_원본_키_세_파일_내용을_
|
||||
numbers = client.get("/api/m02/structures/numbers").json()
|
||||
assert numbers["c9"]["도번"] != numbers["rv"]["도번"] # 새 번호
|
||||
assert numbers["c9"]["면적번"][2:] == numbers["c9"]["도번"][2:]
|
||||
for kind in ("area", "material"):
|
||||
for kind in ("area",):
|
||||
assert client.get(f"/api/m02/templates/{kind}/c9").json()["문서"]["열"] == "c9"
|
||||
# 그 뒤로는 열마다 따로 — 원본을 고쳐도 복사본은 그대로
|
||||
drawing = client.get("/api/m02/templates/structure/rv").json()
|
||||
|
||||
@@ -80,7 +80,7 @@ def test_지운_뒤_항목_0_틀은_남음(empty):
|
||||
combos = client.get("/api/m02/structure-combos").json()
|
||||
assert combos["줄"] == [] and combos["다음"] == 52
|
||||
assert len(combos["지운번호"]) == 4 # 견본에 세 파일이 있던 넷(rv · c4 · pp_len · ms)
|
||||
for kind in ("structure", "area", "material", "inputs"):
|
||||
for kind in ("structure", "area", "inputs"):
|
||||
assert not list((system / kind).glob("*.json")), kind
|
||||
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ def test_새_번호는_옛_번호와_모양이_달라_안_겹침(world):
|
||||
doc = json.loads(path.read_bytes())
|
||||
path.write_text(json.dumps({**doc, key: f"{head}{code}"}), encoding="utf-8")
|
||||
old = {cid: _numbers(system, cid) for cid in store._column_ids()}
|
||||
assert old["rv"] == {"SD01010100", "SA01010100", "SM01010100"}
|
||||
assert old["rv"] == {"SD01010100", "SA01010100"}
|
||||
first = max(int(n[3:]) for nums in old.values() for n in nums if NEW.match(n)) + 1
|
||||
with store.at(system):
|
||||
got = store.read("table", store.STRUCTURE_TABLE)
|
||||
@@ -191,7 +191,7 @@ def test_새_번호는_옛_번호와_모양이_달라_안_겹침(world):
|
||||
got["문서"]["열"].append({"id": "y", "머리": ["y"], "꼴": "수"})
|
||||
store.write("table", store.STRUCTURE_TABLE, got["판"], got["문서"])
|
||||
last = f"-{first + 120:06d}" # 지운 x119 번호(first + 119) 다음
|
||||
assert _numbers(system, "y") == {f"SD{last}", f"SA{last}", f"SM{last}"}
|
||||
assert _numbers(system, "y") == {f"SD{last}", f"SA{last}"}
|
||||
|
||||
|
||||
def test_층마다_번호는_따로_파일은_열_id_로(world):
|
||||
|
||||
@@ -68,7 +68,7 @@ def test_시스템_층은_그대로_항목_목록은_SS_줄(world):
|
||||
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", "names", *items_router.items_store.ITEM_FIELDS}
|
||||
assert set(rows[0]["names"]) == {"일위대가", "도번", "면적번", "재료번"}
|
||||
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,7 +145,6 @@ def test_회사_항목을_개인으로_복사(world):
|
||||
"일위대가": ua_name,
|
||||
"도번": "돌기슭막이 찰쌓기 회사형",
|
||||
"면적번": "돌기슭막이 찰쌓기 회사형",
|
||||
"재료번": "돌기슭막이 찰쌓기 회사형",
|
||||
}
|
||||
|
||||
user = _as(world)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""M02 구조물 도면(structure) — 새로 · 도번 SD+8자리 · 409 · 저장 · 지운 뒤 번호 ·
|
||||
번호 매김(새 항목 = 자리 뜻 없는 일련번호 · PLAN 26-1) · 집계표 저장 때 만들기/지우기 ·
|
||||
복사 가져오기 · 프로젝트 복사.
|
||||
면적산출(area) · 재료산출(material)은 따로 파일 —
|
||||
면적산출(area)은 따로 파일(재료산출은 없앰) —
|
||||
`resources/tester/spreadsheet/test_spreadsheet_store.py`."""
|
||||
|
||||
import json
|
||||
@@ -64,8 +64,8 @@ def client(tmp_path, monkeypatch):
|
||||
|
||||
|
||||
def _num(code: str) -> dict:
|
||||
"""세 번호 — 같은 8자리."""
|
||||
return {"도번": f"SD{code}", "면적번": f"SA{code}", "재료번": f"SM{code}"}
|
||||
"""두 번호 — 같은 8자리."""
|
||||
return {"도번": f"SD{code}", "면적번": f"SA{code}"}
|
||||
|
||||
|
||||
def test_새로_도번_자동_409_없는_열(client):
|
||||
@@ -82,10 +82,10 @@ def test_새로_도번_자동_409_없는_열(client):
|
||||
assert doc["도면"]["format"] == 6
|
||||
assert doc["도면"]["entities"] == []
|
||||
assert len(doc["도면"]["layers"]) == 1
|
||||
# 면적산출 · 재료산출은 구조물 문서 밖 — 같은 열 id 로 따로 한 통합문서씩
|
||||
# 면적산출은 구조물 문서 밖 — 같은 열 id 로 따로 한 통합문서 · 재료산출은 안 만듦
|
||||
assert "산출근거" not in doc
|
||||
for kind in ("area", "material"):
|
||||
assert client.get(f"/api/m02/templates/{kind}/pp_len").json()["문서"]["종류"] == "통합문서"
|
||||
assert client.get("/api/m02/templates/area/pp_len").json()["문서"]["종류"] == "통합문서"
|
||||
assert client.get("/api/m02/templates/material/pp_len").status_code == 404
|
||||
|
||||
assert client.post("/api/m02/structures/rv").json()["문서"]["도번"] == "SD-000002"
|
||||
assert client.post("/api/m02/structures/pp_len").status_code == 409
|
||||
@@ -127,7 +127,7 @@ def test_지워도_번호를_당기지_않음_짝은_같은_번호(client):
|
||||
client.post(f"/api/m02/structures/{column}")
|
||||
assert client.delete("/api/m02/templates/structure/rv").status_code == 200
|
||||
numbers = client.get("/api/m02/structures/numbers").json()
|
||||
assert numbers["rv"] == {**_num("-000002"), "도번": ""} # 면적 · 재료는 남아 번호를 쥠
|
||||
assert numbers["rv"] == {**_num("-000002"), "도번": ""} # 면적은 남아 번호를 쥠
|
||||
assert numbers["ms"] == _num("-000003") # 다른 열 번호는 그대로
|
||||
# 새 열 = 다음 일련번호(자리 뜻 없음) · 다시 만든 도면은 짝(면적산출) 번호를 이어 받음
|
||||
assert client.post("/api/m02/structures/pp_cp").json()["문서"]["도번"] == "SD-000004"
|
||||
@@ -181,7 +181,7 @@ def test_집계표_저장_때_새_열은_만들고_지운_열은_같이_지움(c
|
||||
assert saved.status_code == 200
|
||||
numbers = client.get("/api/m02/structures/numbers").json()
|
||||
assert "pv_a" not in numbers and "note2" not in numbers
|
||||
for kind_ in ("structure", "area", "material"):
|
||||
for kind_ in ("structure", "area"):
|
||||
assert client.get(f"/api/m02/templates/{kind_}/pv_a").status_code == 404
|
||||
# 새 열 = 열 차례로 다음 일련번호 · 지운 pv_a(5) 는 비워 둠(다른 번호를 안 당김)
|
||||
assert numbers["pv_x"] == _num("-000014")
|
||||
|
||||
@@ -84,9 +84,9 @@ def test_집계표_저장_때_새_열_지운_열_고친_열을_맞춤_키_유지
|
||||
assert (rv["분류1"], rv["분류3"]) == (old_rv["분류1"], old_rv["분류3"])
|
||||
assert (rv["단위"], rv["일위대가"]) == ("m", "UA000004")
|
||||
assert (rv["바인딩"], rv["펼침"]) == ({"종류": "revetment"}, True)
|
||||
# 번호는 세 파일과 같음 — 새 열도 [저장] 한 번에 SD · SA · SM 이 섬
|
||||
# 번호는 파일과 같음 — 새 열도 [저장] 한 번에 SD · SA 가 섬
|
||||
numbers = client.get("/api/m02/structures/numbers").json()
|
||||
assert {k: rows["new1"][k] for k in ("도번", "면적번", "재료번")} == numbers["new1"]
|
||||
assert {k: rows["new1"][k] for k in ("도번", "면적번")} == numbers["new1"]
|
||||
assert rows["new1"]["도번"].startswith("SD")
|
||||
|
||||
# 또 저장해도(바뀐 것 없음) 키 · 다음 그대로
|
||||
|
||||
@@ -51,8 +51,8 @@ def test_소스가_700줄을_넘지_않음():
|
||||
),
|
||||
# 산출근거 저장은 컨테이너가 안 함 — [산출근거 수정] 이 여는 메인 칸 전체 편집이 함
|
||||
("M02_MasterTemplete_Api_Fetch.ts", ["saveTemplate"], MAIN),
|
||||
# 좌측 구조물 도면 · 면적산출 · 재료산출 줄 번호는 한 번에 받음
|
||||
# (`{열 id: {도번, 면적번, 재료번}}`)
|
||||
# 좌측 구조물 도면 · 면적산출 줄 번호는 한 번에 받음
|
||||
# (`{열 id: {도번, 면적번}}`)
|
||||
("M02_MasterTemplete_Api_Fetch.ts", ["fetchStructureNumbers"], SIDE),
|
||||
("M02_MasterTemplete_Structure.ts", ["structureLabel", "isStructureColumn"], SIDE),
|
||||
# 도면 카드(31-4)는 카드 파일에서 뗀 `DrawingCard` 가 부름
|
||||
@@ -72,15 +72,13 @@ def test_컨테이너가_쓰는_이름이_내보내진_것(source: str, names: l
|
||||
def test_sub2_가_부르는_이름과_모양():
|
||||
"""브레인 확정 이름 · 모양 — sub2 가 이대로 부름(바꾸면 브레인에게)."""
|
||||
body = _text(M02 / "M02_MasterTemplete_Api_Fetch.ts")
|
||||
for name in ("copyStructure", "copyArea", "copyMaterial"):
|
||||
for name in ("copyStructure", "copyArea"):
|
||||
assert re.search(
|
||||
rf"export const {name} = async \(column: string, from: string\): Promise<void>", body
|
||||
), name
|
||||
assert "fetchStructureNumbers = (): Promise<Record<string, StructureNumbers>>" in body
|
||||
assert re.search(
|
||||
r"interface StructureNumbers \{\s*도번: string;\s*면적번: string;\s*재료번: string;", body
|
||||
)
|
||||
assert re.search(r'export type Kind = [^;]*"area" \| "material"', body)
|
||||
assert re.search(r"interface StructureNumbers \{\s*도번: string;\s*면적번: string;\s*\}", body)
|
||||
assert re.search(r'export type Kind = [^;]*"area";', body)
|
||||
|
||||
|
||||
def test_집계표만_컨테이너를_붙임():
|
||||
@@ -154,7 +152,7 @@ def test_좌측_구조물_집계_양식_아래_하위_넷_새로_본떠_지우
|
||||
assert "createSelectField" not in side # 새로 = 종류 고르기 없이 이름만
|
||||
assert "cur?.종류 !== kind" in side # 본떠 · 지우기 = 그 컨테이너에서 고른 것이 있을 때만
|
||||
assert "i.이름 === STRUCTURE_TABLE" in side # 표는 구조물집계표 한 줄만
|
||||
# 구조물 도면 · 면적산출 · 재료산출 = 구조물 집계 양식 컨테이너 안(같이 접힘) · 자재 조합 없앰
|
||||
# 구조물 도면 · 면적산출 = 구조물 집계 양식 컨테이너 안(같이 접힘) · 자재 조합 없앰
|
||||
summary = side.split("const summary = section(")[1].split(");")[0]
|
||||
assert "COLUMN_KINDS.map" in summary and "matset" not in side
|
||||
assert 'M02_KindTable: ["구조물 조합"' in _text( # 화면 이름(26-7a)
|
||||
@@ -214,7 +212,7 @@ def test_표_도구_막대에_줄_더하기_줄_지우기_손_입력_열_없음(
|
||||
def test_상세_화면_돌아가기는_집계표로_그_열_고른_채():
|
||||
main = _text(MAIN)
|
||||
assert "children: [title, back, slot, reload, save, " in main # 제목 바로 오른쪽
|
||||
assert "!(sel.kind in NUMBER_FIELD)" in main # 구조물 도면 · 면적산출 · 재료산출만
|
||||
assert "!(sel.kind in NUMBER_FIELD)" in main # 구조물 도면 · 면적산출만
|
||||
body = main.split('back.addEventListener("click"')[1]
|
||||
assert "confirmLeave()" in body and "STRUCTURE_TABLE" in body
|
||||
assert "sheet?.selectColumn(column)" in body
|
||||
|
||||
@@ -188,7 +188,7 @@ def test_빈_층에서_폴더_항목_깊이_1_2_5_이름_옮기기_지우기(wor
|
||||
(root / "inputs" / f"{gone['열']}.json").write_text('{"판": 1, "줄": []}', encoding="utf-8")
|
||||
note = t.do(op="delete", 키=gone["key"])["알림"]
|
||||
assert note["지운항목"] == [gone["열"]]
|
||||
for part in ("structure", "area", "material", "inputs"):
|
||||
for part in ("structure", "area", "inputs"):
|
||||
assert not (root / part / f"{gone['열']}.json").is_file()
|
||||
t.do(op="add-item", 경로=["돌쌓기"], 이름="새것") # 지운 번호는 다시 안 줌
|
||||
assert _numbers(root, t.item(["돌쌓기", "새것"])["열"]) == {"-000004"}
|
||||
|
||||
@@ -50,7 +50,7 @@ def test_회사_항목_폴더를_개인에_붙임_새_키_파일_이름2(world):
|
||||
table = json.loads((root / "table/구조물집계표.json").read_bytes())
|
||||
made = next(c for c in table["열"] if c.get("경로") == ["옹벽"])
|
||||
assert made["본뜬"] == {"layer": "company", "owner": "7", "key": wall}
|
||||
for kind in ("structure", "area", "material"):
|
||||
for kind in ("structure", "area"):
|
||||
assert (root / kind / f"{made['id']}.json").is_file()
|
||||
# 다시 붙이면 같은 이름 「(2)」 · 붙일 폴더 안으로
|
||||
again = client.post(PASTE.format("personal"), json={**body, "경로": []}).json()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""표 도면 줄 · 칸 고르기 신호 — `ui_template_sheet_ops.ts` 를 Node 로 바로 돌려 봄.
|
||||
|
||||
마스터 줄 = 일위대가 · 도면 `s:drawing` · 면적산출 `s:area` · 재료산출 `s:material`(식 · 들어갈 것 줄 없음) ·
|
||||
마스터 줄 = 일위대가 · 도면 `s:drawing` · 면적산출 `s:area`(식 · 들어갈 것 줄 없음) ·
|
||||
master 만 · 단위 줄 바로 아래 차례(키보드) · project 에는 없음.
|
||||
`selectionOf` = 격자가 `onSelect` 로 넘기는 모양({row, col, colId} · 모르는 열은 col -1 · colId null).
|
||||
"""
|
||||
@@ -26,7 +26,7 @@ console.log(JSON.stringify({
|
||||
master: navRows(doc, "master"),
|
||||
project: navRows(doc, "project"),
|
||||
pick: [selectionOf(doc, "s:drawing", "c2"), selectionOf(doc, "d:r1", "c1"), selectionOf(doc, "s:unit", "zz")],
|
||||
blank: ["s:price", "s:drawing", "s:area", "s:material", "s:unit", "d:r1"].map((k) => [isBlankPick(k, { id: "t", 머리: [], 꼴: "글" }), isBlankPick(k, { id: "n", 머리: [], 꼴: "수" })]),
|
||||
blank: ["s:price", "s:drawing", "s:area", "s:unit", "d:r1"].map((k) => [isBlankPick(k, { id: "t", 머리: [], 꼴: "글" }), isBlankPick(k, { id: "n", 머리: [], 꼴: "수" })]),
|
||||
}));
|
||||
"""
|
||||
|
||||
@@ -53,7 +53,7 @@ def _run() -> dict:
|
||||
def test_drawing_row_under_price_master_only():
|
||||
got = _run()
|
||||
assert got["master"] == [
|
||||
"s:unit", "s:price", "s:drawing", "s:area", "s:material", "d:r1", "t:t1",
|
||||
"s:unit", "s:price", "s:drawing", "s:area", "d:r1", "t:t1",
|
||||
] # fmt: skip
|
||||
assert got["project"] == ["s:unit", "d:r1", "t:t1"]
|
||||
|
||||
@@ -68,5 +68,5 @@ def test_selection_shape():
|
||||
|
||||
def test_text_column_pick_rows_blank():
|
||||
assert _run()["blank"] == [
|
||||
[True, False], [True, False], [True, False], [True, False], [False, False], [False, False],
|
||||
[True, False], [True, False], [True, False], [False, False], [False, False],
|
||||
] # fmt: skip
|
||||
|
||||
@@ -36,7 +36,7 @@ def _copy_layer(target: Path) -> None:
|
||||
target.mkdir(parents=True)
|
||||
for name in (layers.COMBO_FILE,):
|
||||
shutil.copy2(REAL / name, target / name)
|
||||
for kind in ("table", "structure", "area", "material"):
|
||||
for kind in ("table", "structure", "area"):
|
||||
shutil.copytree(REAL / kind, target / kind)
|
||||
|
||||
|
||||
@@ -131,7 +131,12 @@ def test_지정하면_폴더가_생기고_내용이_원본과_같음(world):
|
||||
assert result == {"만듦": ["pipe@40.0", "st0"], "지움": [], "못만듦": [], "옮겨받음": []}
|
||||
folder = _items(root) / "st0"
|
||||
got = {path.name for path in folder.iterdir()}
|
||||
assert {"집계.json", "도면.json", "면적.json", "재료.json", "manifest.json"} <= got
|
||||
assert {
|
||||
"집계.json",
|
||||
"도면.json",
|
||||
"면적.json",
|
||||
"manifest.json",
|
||||
} <= got and "재료.json" not in got
|
||||
total = json.loads((folder / "집계.json").read_text(encoding="utf-8"))
|
||||
assert total["줄"]["키"] == "SS000022" and total["열"]["id"] == "ms"
|
||||
drawing = json.loads((world["system"] / "structure/ms.json").read_text(encoding="utf-8"))
|
||||
|
||||
@@ -43,7 +43,6 @@ const row = (
|
||||
일위대가: "UA000004",
|
||||
도번: "SD01010100",
|
||||
면적번: "SA01010100",
|
||||
재료번: "SM01010100",
|
||||
layer,
|
||||
owner: layer === "company" ? "샘플회사" : layer === "personal" ? "샘플회사/사용자" : null,
|
||||
...extra,
|
||||
@@ -55,7 +54,6 @@ const rows: PickerRow[] = [
|
||||
일위대가: "돌기슭막이 메쌓기 일위대가",
|
||||
도번: "돌기슭막이 도면",
|
||||
면적번: "돌기슭막이 면적산출",
|
||||
재료번: "돌기슭막이 재료산출",
|
||||
},
|
||||
}),
|
||||
row("SS000002", "rv2", "돌기슭막이", ["메쌓기", "1.5m", "기초유"], "system"),
|
||||
@@ -219,20 +217,20 @@ assert.deepEqual(pathIds(rows[0], labels), [
|
||||
"system|돌기슭막이|메쌓기|1.2m",
|
||||
]);
|
||||
|
||||
// 폴더 모양 — 네 줄 · 이름은 서버 names · 없으면 키만(작은 글) · 둘 다 없으면 빈 키
|
||||
// 폴더 모양 — 세 줄 · 이름은 서버 names · 없으면 키만(작은 글) · 둘 다 없으면 빈 키
|
||||
const lines = folderLines(rows[0]);
|
||||
assert.deepEqual(
|
||||
lines.map((l) => l.kind),
|
||||
["drawing", "area", "material", "unitPrice"],
|
||||
["drawing", "area", "unitPrice"],
|
||||
);
|
||||
assert.deepEqual(lines[0], { kind: "drawing", name: "돌기슭막이 도면", key: "SD01010100" });
|
||||
assert.deepEqual(lines[3], {
|
||||
assert.deepEqual(lines[2], {
|
||||
kind: "unitPrice",
|
||||
name: "돌기슭막이 메쌓기 일위대가",
|
||||
key: "UA000004",
|
||||
});
|
||||
assert.deepEqual(folderLines(rows[1])[0], { kind: "drawing", name: null, key: "SD01010100" }); // names 자체가 없음
|
||||
assert.deepEqual(folderLines({ key: "SS1", 열: "x" })[3], {
|
||||
assert.deepEqual(folderLines({ key: "SS1", 열: "x" })[2], {
|
||||
kind: "unitPrice",
|
||||
name: null,
|
||||
key: "",
|
||||
|
||||
Reference in New Issue
Block a user