"""항목 하나 비우기(PLAN 40-4 · 카드 [삭제]) — `POST /api/m02/layers/{층}/{종류}/{열}/clear`. 새 열과 같은 빈 문서 · 번호 · 열 그대로 · 권한 = 받는 층 쓰기(`_root`). 시스템 층 = 견본 표(임시 폴더) · 개인 층 = 임시 storage · 로직은 M01 마스터(읽기만). """ from __future__ import annotations import json from pathlib import Path from typing import Any import pytest from fastapi import FastAPI from fastapi.testclient import TestClient from common_util.common_util_auth import verify_session from config import config_system from M02_MasterTemplete import M02_MasterTemplete_Items as items_store from M02_MasterTemplete import M02_MasterTemplete_Router_Items as items_router from M02_MasterTemplete import M02_MasterTemplete_Store as store from M02_MasterTemplete import M02_Template_Layers as layers from resources.tester.test_m02_structure import write_sample_table TEN = "GC000421" URL = "/api/m02/layers/{}/{}/{}/clear" NUMBER = { "structures": ("structure", "도번"), "labor": ("labor", "일위대가번"), "area": ("area", "면적번"), } def _fill(folder: Path, cid: str) -> None: """세 문서를 채움 — 도면 선 · 일위대가 로직 · 면적 칸 + 알약 연결.""" with store.at(folder): for kind in ("structure", "labor", "area"): store._ensure(kind, cid) got = store.read("structure", cid) doc = got["문서"] doc["도면"]["entities"] = [{"type": "line"}] store.write("structure", cid, got["판"], doc) got = store.read("labor", cid) store.write("labor", cid, got["판"], {**got["문서"], "담은로직": [{"로직": TEN}]}) got = store.read("area", cid) sheet = got["문서"]["시트"][0] sheet["칸"] = {"B6": {"값": "5"}} sheet["연결"] = [{"키": "사석 수상고르기|㎡", "이름": "x", "칸": "B6", "단위": "㎡"}] store.write("area", cid, got["판"], got["문서"]) @pytest.fixture() def world(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> dict[str, Any]: system = tmp_path / "system" system.mkdir() write_sample_table(system) monkeypatch.setattr(store, "FOLDER", system) monkeypatch.setattr(layers, "SYSTEM_ROOT", system) (tmp_path / "storage").mkdir() monkeypatch.setattr(config_system, "STORAGE_BASE_DIR", str(tmp_path / "storage")) with store.at(system): store.create_structure("rv") _fill(system, "rv") personal = layers.personal_dir(7, 42) items_store.ensure(personal) with store.at(personal): got = store.read("table", store.STRUCTURE_TABLE) got["문서"]["열"] = [{"id": "a", "머리": ["돌", "가"], "꼴": "수"}] store.write("table", store.STRUCTURE_TABLE, got["판"], got["문서"]) _fill(personal, "a") session: dict[str, Any] = {"user_id": 42, "company_id": 7, "role": "USER", "is_master": False} app = FastAPI() app.include_router(items_router.router) app.dependency_overrides[verify_session] = lambda: session return {"client": TestClient(app), "session": session, "system": system, "personal": personal} def _as(world: dict, role: str = "USER", user: int = 42) -> TestClient: world["session"].update(role=role, user_id=user) return world["client"] def _doc(folder: Path, kind: str, cid: str) -> dict: return json.loads((folder / kind / f"{cid}.json").read_bytes()) @pytest.mark.parametrize("kind", ["structures", "labor", "area"]) def test_세_종류_빈_문서_번호_열_그대로(world, kind): system = world["system"] part, key = NUMBER[kind] before = _doc(system, part, "rv") got = _as(world, "SYSTEM_ADMIN").post(URL.format("system", kind, "rv")) assert got.status_code == 200, got.text after = _doc(system, part, "rv") with store.at(system): blank = store._blank(part, "rv") assert after == {**blank, key: before[key]} # 새 열과 같은 빈 문서 + 번호 assert after["열"] == "rv" and after[key] with store.at(system): # 장부 번호 그대로 row = next(r for r in store.read_combos()["줄"] if r["열"] == "rv") assert row[key] == before[key] def test_면적_비우면_일위대가_계산값_수량_없음으로(world): system = world["system"] assert _doc(system, "labor", "rv")["계산값"]["줄"][0]["수량출처"] == "칸" _as(world, "SYSTEM_ADMIN").post(URL.format("system", "area", "rv")) assert _doc(system, "labor", "rv")["계산값"]["줄"][0]["수량출처"] == "없음" assert _doc(system, "labor", "rv")["담은로직"][0]["로직"] == TEN # 일위대가는 그대로 def test_권한_일반_마스터_403_남의_개인_403_내_개인_됨(world): system, personal = world["system"], world["personal"] client = _as(world) assert client.post(URL.format("system", "labor", "rv")).status_code == 403 assert _doc(system, "labor", "rv")["담은로직"] # 안 지워짐 other = URL.format("personal", "labor", "a") + "?owner=7/99" assert client.post(other).status_code == 403 assert client.post(URL.format("personal", "labor", "a")).status_code == 200 assert _doc(personal, "labor", "a")["담은로직"] == [] def test_회사_관리자는_동료_개인_층_비움(world): personal = world["personal"] client = _as(world, "ADMIN", user=41) got = client.post(URL.format("personal", "structures", "a") + "?owner=7/42") assert got.status_code == 200, got.text assert _doc(personal, "structure", "a")["도면"]["entities"] == [] def test_없는_열_404_모르는_종류_422(world): client = _as(world, "SYSTEM_ADMIN") assert client.post(URL.format("system", "labor", "없는열")).status_code == 404 assert client.post(URL.format("system", "material", "rv")).status_code == 422