# ruff: noqa: F811 — 임시 층 fixture(world)를 test_m02_labor_ref 에서 받아 씀 """서고 나무 지우기 = 경고 뒤 지움 · 쓰는 곳 그 줄도 지움(PLAN 735-1 · 요구 574) — 임시 storage. 미리 보기(쓰는 줄 = 종류 · 이름 · 키 · 줄) · 확인 없으면 409 목록 · 확인 = 그 줄 지움 (금액 다시 셈) + 문서 지움 + `_합친것/` 기록 · 되돌림(문서 · 자리 · 고친 문서 앞판 · 그새 고친 문서는 건너뜀) · 권한 밖 409(아무것도 안 바뀜) · 폴더 통째 = 한 기록 · 단가산출 바탕 · 더한줄 열쇠 당김(`strip`). """ import pytest from fastapi import FastAPI from fastapi.testclient import TestClient from common_util.common_util_auth import verify_session from M02_MasterTemplete import M02_Labor_Ref as refs from M02_MasterTemplete import M02_Labor_Router as labor_router from M02_MasterTemplete import M02_Library_Delete as deleting from M02_MasterTemplete import M02_Library_Same_Router as same_router from M02_MasterTemplete import M02_MasterTemplete_Store as store from resources.tester.test_m02_labor_ref import MINE, world # noqa: F401 USER = {"user_id": 42, "company_id": 7, "role": "USER", "is_master": False, "name": "갑"} TREE = "/api/m02/layers/personal/precombo-tree" SAME = "/api/m02/layers/personal/precombo-same" SK_TREE = "/api/m02/layers/personal/sangeun-tree" SK_SAME = "/api/m02/layers/personal/sangeun-same" FIX = {"고정": {"이름": "운반", "단위": "식", "단가": {"경비": 5000}}, "수량": {"손": 1}} @pytest.fixture() def api(world): app = FastAPI() app.include_router(labor_router.router) app.include_router(same_router.router) app.dependency_overrides[verify_session] = lambda: USER return TestClient(app) def _sc(folder, name, lines): with store.at(folder): return refs.create("precombo", {"이름": name, "단위": "m", "담은로직": lines})["이름"] def _labor(folder, lines): with store.at(folder): store.write("labor", "x1", "", {"열": "x1", "담은로직": lines, "자재": []}) def _read(folder, kind, key): with store.at(folder): return store.read(kind, key)["문서"] def _sum(folder): return _read(folder, "labor", "x1")["계산값"]["반영합"]["계"] def _tree(api, url=TREE, **body): 판 = api.get(url).json()["판"] return api.post(url, json={"판": 판, **body}) def _world(world): """단가산출 하나(운반 3000 · 1 단위)를 구조물 조합 x1(2 단위) · 일위대가가 물게.""" me = world["personal"] line = {"고정": {"이름": "운반", "단위": "식", "단가": {"경비": 3000}}, "수량": 1} with store.at(me): doc = {"이름": "임시 단가산출", "단위": "m", "바탕": None, "더한줄": [line]} sk = refs.create("sangeun", doc)["이름"] top = _sc(me, "위 일위대가", [{"참조": {**MINE, "키": sk}}, FIX]) _labor(me, [{"참조": {**MINE, "키": sk}, "수량": {"손": 2}}, FIX]) return me, sk, top def test_미리보기_확인없으면_409_확인하면_그줄_지움_금액_다시셈_되돌림(api, world): me, sk, top = _world(world) before = _sum(me) assert before == pytest.approx(5000 + 2 * 3000) got = api.post(SK_TREE + "/delete-check", json={"대상": [{"키": sk}]}) assert got.status_code == 200, got.text rows = got.json()["쓰는곳"] assert got.json()["문서"] == [sk] assert sorted((r["종류"], r["이름"], r["키"], r["줄"], r["쓰기"]) for r in rows) == [ ("구조물 조합", "x1", sk, "1째", True), ("일위대가", "위 일위대가", sk, "1째", True), ] res = _tree(api, SK_TREE, op="delete", 대상=[{"키": sk}]) assert res.status_code == 409 and len(res.json()["detail"]["쓰는곳"]) == 2 assert (me / "sangeun" / f"{sk}.json").is_file() res = _tree(api, SK_TREE, op="delete", 대상=[{"키": sk}], 확인=True) assert res.status_code == 200, res.text assert res.json()["알림"]["기록"] == sk assert not (me / "sangeun" / f"{sk}.json").exists() assert [x.get("고정", {}).get("이름") for x in _read(me, "labor", "x1")["담은로직"]] == ["운반"] assert len(_read(me, "precombo", top)["담은로직"]) == 1 assert _sum(me) == pytest.approx(5000) # 서버가 다시 셈 gone = api.get(SK_SAME).json()["합친것"] assert [(g["키"], g["남김"], g["옮긴곳수"]) for g in gone] == [(sk, None, 2)] back = api.post(SK_SAME + "/undo", json={"키": sk}) assert back.status_code == 200, back.text assert back.json()["되돌린곳수"] == 2 and back.json()["못한곳"] == [] assert (me / "sangeun" / f"{sk}.json").is_file() assert _read(me, "labor", "x1")["담은로직"][0]["참조"]["키"] == sk assert _sum(me) == pytest.approx(before) assert api.get(SK_SAME).json()["합친것"] == [] def test_쓰는곳_없으면_그냥_지움_기록은_남음(api, world): me = world["personal"] sc = _sc(me, "혼자", [FIX]) assert api.post(TREE + "/delete-check", json={"대상": [{"키": sc}]}).json()["쓰는곳"] == [] assert _tree(api, op="delete", 대상=[{"키": sc}]).status_code == 200 assert not (me / "precombo" / f"{sc}.json").exists() assert api.post(SAME + "/undo", json={"키": sc}).status_code == 200 assert (me / "precombo" / f"{sc}.json").is_file() def test_권한_밖이면_409_목록_아무것도_안_바뀜(api, world, monkeypatch): me, sk, _top = _world(world) monkeypatch.setattr(deleting, "can_write", lambda session, at: False) res = _tree(api, SK_TREE, op="delete", 대상=[{"키": sk}], 확인=True) assert res.status_code == 409 detail = res.json()["detail"] assert "권한 밖" in detail["까닭"] and "x1" in detail["까닭"] and sk in detail["까닭"] assert {r["이름"] for r in detail["막힘"]} == {"x1", "위 일위대가"} assert (me / "sangeun" / f"{sk}.json").is_file() assert len(_read(me, "labor", "x1")["담은로직"]) == 2 def test_폴더_통째_한_기록_되돌림_자리까지_그새_고친_문서는_건너뜀(api, world): me = world["personal"] a = _sc(me, "가", [FIX]) b = _sc(me, "나", [FIX]) _labor(me, [{"참조": {**MINE, "키": a}, "수량": {"손": 1}}, FIX]) with store.at(me): # 쓰는 곳 = 구조물 조합(740-1 — 일위대가 안 일위대가는 사본 블록) other = [{"참조": {**MINE, "키": b}, "수량": {"손": 1}}, FIX] store.write("labor", "x2", "", {"열": "x2", "담은로직": other, "자재": []}) assert _tree(api, op="add-folder", 경로=[], 이름="묶음").status_code == 200 for key in (a, b): assert _tree(api, op="move", 키=key, 새경로=["묶음"]).status_code == 200 check = api.post(TREE + "/delete-check", json={"대상": [{"경로": ["묶음"]}]}).json() assert sorted(check["문서"]) == [a, b] assert sorted(r["키"] for r in check["쓰는곳"]) == [a, b] res = _tree(api, op="delete", 대상=[{"경로": ["묶음"]}], 확인=True) assert res.status_code == 200, res.text name = res.json()["알림"]["기록"] assert [g["키"] for g in api.get(SAME).json()["합친것"]] == [name] with store.at(me): # 그새 x2 를 고침 → 그 문서는 앞판으로 안 돌림 have = store.read("labor", "x2") lines = [{**x, "메모": "고침"} for x in have["문서"]["담은로직"]] store.write("labor", "x2", have["판"], {**have["문서"], "담은로직": lines}) back = api.post(SAME + "/undo", json={"키": name}).json() assert back["되돌린곳수"] == 1 and "그새 고침" in back["못한곳"][0] assert (me / "precombo" / f"{a}.json").is_file() and (me / "precombo" / f"{b}.json").is_file() assert api.get(TREE).json()["자리"] == {a: ["묶음"], b: ["묶음"]} assert _read(me, "labor", "x1")["담은로직"][0]["참조"]["키"] == a def test_단가산출_바탕_더한줄_지움_열쇠_당김(): gone = {**MINE, "키": "SK-000002"} keep = {**MINE, "키": "SK-000003"} doc = { "바탕": {"참조": gone}, "열린입력": ["높이"], "더한줄": [{"참조": gone, "수량": 1}, {"참조": keep, "수량": 1}, {"종류": "로직"}], "덮개": {"labor:A#1": {"qty": 1}, "add:#1": {"배율": 2}, "add:#2/labor:B#1": {"qty": 3}}, "뺀줄": ["labor:A#2", "add:#0"], "고름": {"add:#2/material:C#1": "MT1"}, "자재표시": {}, } out = deleting.strip(doc, {refs.ref_id(gone)}) assert out["바탕"] is None and out["열린입력"] == [] assert [x.get("참조") for x in out["더한줄"]] == [keep, None] assert out["덮개"] == {"add:#0": {"배율": 2}, "add:#1/labor:B#1": {"qty": 3}} assert out["뺀줄"] == [] assert out["고름"] == {"add:#1/material:C#1": "MT1"} assert deleting.strip(doc, set()) == doc # 안 걸리면 그대로