- 설계내역서 표 오른쪽 서랍(공용 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>
148 lines
7.0 KiB
Python
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() # 아무것도 안 씀
|