Files
Aislo/resources/tester/test_703_1_b09_past.py
T
eomsangdonandClaude Opus 5.5 fdb3eb9b77 feat(B09): 오른쪽 재료 창고 · 지난 공사 일위대가 가져오기(PLAN 703-1)
- 설계내역서 표 오른쪽 서랍(공용 side_panels · 접고 펴기 · 좁은 화면 = 아래) — 찾기 하나 + 출처 탭
  이 공사 · 내 것 · 회사 · 품셈(704-1 기준 목록 · 우클릭 계산서 보기) · 지난 공사
- 두 번 누름 · Enter = 고른 내역 줄에 단가연결 · 끌어 놓기 = 놓은 줄 · 연결 = 단가연결 모달과 같은 길(702-3 즉시 금액)
- 품셈 = 넣을 값 창에 계산서 입력 전부(목록 바꿈은 기본과 다른 것만 — 석축헐기 뒷길이 60 이 0 으로 열리던 것)
- 서버 B09_Estimation_Past + GET/POST /estimation/past — 같은 회사 다른 공사 구조물 사본 · 서고 사본 →
  이 공사 서고 사본(폴더 통째 · 가져온곳 · 덮개째 · 단가 = 이 공사 책) · 남의 회사 403
- 표 높이 셈(spaceBelow)이 뒤 형제만 보므로 서랍 = DOM 앞 · CSS order 로 오른쪽
- 시험 test_703_1 6 · 셸 꼴 글 시험 200-2 · 202-1 = 표 칸 + 서랍 꼴로 고침(낡은 글)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 14:59:58 +09:00

148 lines
7.0 KiB
Python

"""703-1 B09 재료 창고 「지난 공사」 — 같은 회사 다른 공사 일위대가 → 이 공사 서고 사본(덮개째).
- 목록 = 그 공사 서고 사본 · 구조물 사본 · 고친 칸 수(그 공사 저장 덮개) · 같은 것 한 줄
- 가져옴 = 사본 폴더 통째 → `library/…~해시` · 가져온곳 · 덮개 = 그 공사 칸 · 다시 = 같은 사본
- 새 호표(`libs`) · 같은 꼴 블록이 이 공사에 먼저 있으면 그 블록 cover
- 모양 틀림 400 · 없음 404 · 다른 회사 403 · 이 공사 400
임시 층(견본 마스터 · 임시 storage) · 실제 마스터 · 프로젝트는 안 씀.
"""
import asyncio
import json
import sys
from pathlib import Path
import pytest
from fastapi import HTTPException
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from B09_Estimation import B09_Estimation_Bill_Library as library # noqa: E402
from B09_Estimation import B09_Estimation_Past as past # noqa: E402
from B09_Estimation import B09_Estimation_Router as router # noqa: E402
from B09_Estimation import B09_Estimation_Store as store_b09 # noqa: E402
from B09_Estimation.B09_Estimation_Labor_Source import daega_inputs # noqa: E402
from config import config_system # noqa: E402
from M02_MasterTemplete import M02_Labor_Ref as refs # noqa: E402
from M02_MasterTemplete import M02_MasterTemplete_Store as store # noqa: E402
from M02_MasterTemplete import M02_Template_Layers as layers # noqa: E402
from resources.tester.helper_m02_master_sample import copy_master_sample # noqa: E402
STONE = "GF000219" # 돌쌓기 메쌓기 원/㎡
@pytest.fixture()
def world(tmp_path, monkeypatch):
system = copy_master_sample(tmp_path / "master")
monkeypatch.setattr(store, "FOLDER", system)
monkeypatch.setattr(layers, "SYSTEM_ROOT", system)
monkeypatch.setattr(config_system, "STORAGE_BASE_DIR", str(tmp_path / "storage"))
with store.at(system):
key = refs.create(
"precombo",
{"이름": "지난 조합", "단위": "㎡", "담은로직": [{"로직": STONE, "수량": {"손": 2}}]},
)["이름"]
a, b = (tmp_path / "storage" / "7" / "1" / n for n in ("past", "here"))
a.mkdir(parents=True)
b.mkdir(parents=True)
folder = library.import_copy(a, "precombo", "system", None, key)["폴더"]
ref = {"층": "system", "주인": None, "키": key}
cover = {
f"C:{refs.ref_id(ref)}": {"sangeun:GF#0": {"qty": 5}},
"K:x": {"@copy": {"from": "S:y"}},
}
store_b09.write_user(a, {"daega_cover": cover})
return {"key": key, "a": a, "b": b, "folder": folder}
def test_목록_서고_사본_고친_칸_수_같은_것_한_줄(world):
a = world["a"]
rows = past.rows_of(a)
assert [(r["cover"], r["name"], r["unit"], r["kind"], r["covers"]) for r in rows] == [
(f"L:{world['folder']}", "지난 조합", "㎡", "사전조합", 1)
]
# 같은 원본 · 같은 값 · 덮개 없음 = 한 줄로 셈(값 해시 다른 사본)
library.import_copy(a, "precombo", "system", None, world["key"], haul={"given": {}})
assert len(past.rows_of(a)) == 1
def test_가져옴_사본_통째_덮개째_새_호표_다시는_같은_사본(world):
a, b, folder = world["a"], world["b"], world["folder"]
ref = {"project_id": "P-A", "프로젝트": "지난"}
made = past.import_past(b, a, ref, f"L:{folder}", {"이름": "나"})
name = made["폴더"]
assert made["만듦"] and made["덮개"] == {"sangeun:GF#0": {"qty": 5}}
assert name.startswith(f"precombo@system@-@{world['key']}~") and library.NAME.match(name)
copy = library.library_dir(b) / name
src = library.library_dir(a) / folder
for f in ("일위대가.json", "단가.json"):
assert (copy / f).read_bytes() == (src / f).read_bytes()
manifest = json.loads((copy / "manifest.json").read_text("utf-8"))
assert manifest["가져온곳"] == {**ref, "사본": f"L:{folder}"} and manifest["종류"] == "precombo"
got = daega_inputs(b)
bid = got["libs"][name]
block = next(x for x in got["blocks"] if x["id"] == bid)
# 사전조합 덮개 = 참조(공사 안 같은 사전조합 한 덮개) — 덮개자리 = 그 cover
assert (block["name"], block["cover"]) == ("지난 조합", made["덮개자리"])
assert made["덮개자리"] == "C:참조|system||" + world["key"]
again = past.import_past(b, a, ref, f"L:{folder}")
assert (again["폴더"], again["만듦"]) == (name, False)
def test_같은_꼴_블록이_먼저_있으면_그_cover(world):
a, b = world["a"], world["b"]
mine = library.import_copy(b, "precombo", "system", None, world["key"])["폴더"]
name = past.import_past(b, a, {"project_id": "P-A"}, f"L:{world['folder']}")["폴더"]
got = daega_inputs(b)
assert got["libs"][name] == got["libs"][mine]
block = next(x for x in got["blocks"] if x["id"] == got["libs"][name])
assert block["cover"].startswith("C:") # 사전조합 = 같은 참조 한 덮개(화면이 빈 때만 얹음)
def test_구조물조합_사본_덮개자리_새_폴더(world):
a, b = world["a"], world["b"]
folder = library.import_copy(a, "combo", "system", None, "SS000011")["폴더"]
store_b09.write_user(a, {"daega_cover": {f"L:{folder}": {"x#0": {"qty": 2}}}})
row = next(r for r in past.rows_of(a) if r["cover"] == f"L:{folder}")
assert (row["kind"], row["covers"]) == ("구조물 조합", 1)
made = past.import_past(b, a, {"project_id": "P-A"}, f"L:{folder}")
assert made["덮개자리"] == f"L:{made['폴더']}" and made["덮개"] == {"x#0": {"qty": 2}}
got = daega_inputs(b)
block = next(x for x in got["blocks"] if x["id"] == got["libs"][made["폴더"]])
assert block["cover"] == made["덮개자리"]
def test_모양_틀림_없음(world):
a, b = world["a"], world["b"]
for bad in ("L:../x", "X:y", "S:../../z"):
with pytest.raises(ValueError):
past.import_past(b, a, {}, bad)
with pytest.raises(LookupError):
past.import_past(b, a, {}, "S:nope")
with pytest.raises(LookupError):
past.import_past(b, a, {}, "L:precombo@system@-@SC-000999")
def test_길_다른_회사_403_이_공사_400(world, monkeypatch):
rows = {
"here": {"company_id": 7, "root": world["b"]},
"far": {"company_id": 8, "root": world["a"]},
}
async def project(_session, pid):
return {"name": pid, **rows["here" if pid.startswith("0") else "far"]}
monkeypatch.setattr(router, "_project", project)
pid = router.UUID("00000000-0000-0000-0000-000000000001")
body = router.PastBody(project_id="far", cover=f"L:{world['folder']}")
with pytest.raises(HTTPException) as e:
asyncio.run(router.past_import(pid, body, {"user_id": 1}))
assert e.value.status_code == 403
same = router.PastBody(project_id=str(pid), cover="L:x")
with pytest.raises(HTTPException) as e:
asyncio.run(router.past_import(pid, same, {"user_id": 1}))
assert e.value.status_code == 400
assert not library.library_dir(world["b"]).exists() # 아무것도 안 씀