Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RoyUwuTFiDJfvCfHpvKKzp
108 lines
5.1 KiB
Python
108 lines
5.1 KiB
Python
"""M01 자재 조합(`/api/m01/matset…` · 파일 `자재조합.json` · 키 UM) — 담은 자재 목록만 지님.
|
|
|
|
못박는 것
|
|
- 새로 만들면 키를 서버가 `UM` 다음 번호로 줌 · 열 한 벌 · 담은 자재는 네 칸.
|
|
- 없는 자재 코드 · 같은 자재 두 번 · 이름 없음 · 없는 본뜬키는 막음.
|
|
- 고치기는 낡은 판본이면 409 · 지우기는 구조물 열이 「자재조합」 칸으로 쓰면 409 + 구조물 이름들.
|
|
- 정본은 읽기만 함(사본 폴더 · 사본 집계표).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from fastapi import FastAPI
|
|
from fastapi.testclient import TestClient
|
|
|
|
from M01_MasterData import M01_MasterData_Router as router_module
|
|
from M01_MasterData import M01_MasterData_Store as store
|
|
from M01_MasterData import M01_MasterData_Store_Combo as combo_store
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
@pytest.fixture
|
|
def client(tmp_path: Path, monkeypatch) -> TestClient:
|
|
for path in store.FOLDER.glob("*.json"):
|
|
if not path.name.startswith("_") or path.name == store.mk.BOOK.name:
|
|
shutil.copy(path, tmp_path / path.name)
|
|
monkeypatch.setattr(store, "FOLDER", tmp_path)
|
|
sheet = tmp_path / "집계표.json"
|
|
sheet.write_text(json.dumps({"열": []}), encoding="utf-8")
|
|
monkeypatch.setattr(combo_store, "USERS", (sheet,))
|
|
app = FastAPI()
|
|
app.include_router(router_module.router)
|
|
return TestClient(app)
|
|
|
|
|
|
def _mat(client: TestClient) -> dict:
|
|
"""자재품목에서 실제 줄 하나 — 자재 찾기 길 그대로."""
|
|
got = client.get("/api/m01/pick", params={"kind": "price", "q": "합판", "limit": 2}).json()
|
|
one = got["items"][0]
|
|
return {"코드": one["ref"], "이름": one["이름"], "규격": one["규격"], "단위": one["단위"]}
|
|
|
|
|
|
def _new(client: TestClient, name: str, mats: list[dict], **more) -> dict:
|
|
body = {"matset": {"이름": name, "담은자재": mats, **more}}
|
|
return client.post("/api/m01/matset/new", json=body)
|
|
|
|
|
|
def test_정본_자재조합_파일은_틀대로다() -> None:
|
|
data = json.loads((ROOT / "resources/master_data/자재조합.json").read_text(encoding="utf-8"))
|
|
assert data["그룹"] == "자재조합" and isinstance(data["줄"], list)
|
|
assert store.cm.msk.check_form("자재조합.json", data) == []
|
|
assert '"UM"' in (ROOT / "resources/master_data/_키대장.json").read_text(encoding="utf-8")
|
|
|
|
|
|
def test_새로_만들면_UM_키와_열_한_벌(client) -> None:
|
|
mat = _mat(client)
|
|
res = _new(client, "합판 자재", [{**mat, "덤": 1}])
|
|
assert res.status_code == 200, res.text
|
|
made = res.json()
|
|
assert made["key"].startswith("UM") and len(made["key"]) == 8
|
|
assert tuple(made["matset"]) == store.cm.msk.COLS
|
|
assert made["matset"]["담은자재"] == [mat] and made["matset"]["본뜬키"] is None
|
|
rows = client.get("/api/m01/matsets").json()["matsets"]
|
|
assert [(r["키"], r["count"]) for r in rows] == [(made["key"], 1)]
|
|
got = client.get("/api/m01/matset", params={"key": made["key"]}).json()
|
|
assert got["matset"]["이름"] == "합판 자재"
|
|
|
|
|
|
def test_없는_자재_두_번_담기_이름_본뜬키는_막는다(client) -> None:
|
|
mat = _mat(client)
|
|
assert _new(client, "없는 코드", [{**mat, "코드": "MT999999"}]).status_code == 422
|
|
assert _new(client, "두 번", [mat, mat]).status_code == 422
|
|
assert _new(client, " ", [mat]).status_code == 400
|
|
assert _new(client, "없는 원본", [mat], 본뜬키="UM999999").status_code == 400
|
|
ok = _new(client, "원본", [mat]).json()["key"]
|
|
assert _new(client, "본뜬 것", [mat], 본뜬키=ok).json()["matset"]["본뜬키"] == ok
|
|
assert _new(client, "원본", [mat]).status_code == 422 # 이름 겹침
|
|
|
|
|
|
def test_고치기는_낡은_판본이면_409(client) -> None:
|
|
mat = _mat(client)
|
|
key = _new(client, "고칠 것", [mat]).json()["key"]
|
|
one = client.get("/api/m01/matset", params={"key": key}).json()
|
|
body = {"key": key, "version": one["version"], "matset": {**one["matset"], "이름": "고침"}}
|
|
assert client.post("/api/m01/matset/edit", json=body).status_code == 200
|
|
assert client.post("/api/m01/matset/edit", json=body).status_code == 409 # 같은 옛 판본
|
|
|
|
|
|
def test_쓰는_열이_있으면_못_지우고_없으면_지워진다(client) -> None:
|
|
mat = _mat(client)
|
|
key = _new(client, "쓰는 것", [mat]).json()["key"]
|
|
cols = [{"id": "c9", "머리": ["돌붙임", "찰붙임", "", ""], "자재조합": key}]
|
|
combo_store.USERS[0].write_text(json.dumps({"열": cols}, ensure_ascii=False), encoding="utf-8")
|
|
version = client.get("/api/m01/matset", params={"key": key}).json()["version"]
|
|
res = client.post("/api/m01/matset/delete", json={"key": key, "version": version})
|
|
assert res.status_code == 409 and res.json()["detail"]["users"] == ["돌붙임 찰붙임"]
|
|
combo_store.USERS[0].write_text(json.dumps({"열": []}), encoding="utf-8")
|
|
assert (
|
|
client.post("/api/m01/matset/delete", json={"key": key, "version": version}).status_code
|
|
== 200
|
|
)
|
|
assert client.get("/api/m01/matset", params={"key": key}).status_code == 404
|