- 목록 = 이름 · 규격 · 구분 · 가격 · 손료계수 · 주연료 · 조종원 · 시간당 경비(서버 값) · 별칭 · 비고 (단위 · 출처 열 없음 · 가로 넘침 없음) · 다른 요소 표 그대로 - 상세 = 기계 양식 + 원문번호 · 원문 · 구분 · 상세구분 · 별칭 · 비고 · 쓰는 곳 · 지우기(쓰는 곳 보이고 확인) · 주소 ?machine= 로 바로 열림 · 뒤로 가기 = 목록 · 저장 안 한 고침 나가기 경고 - 고침 = 초안 → 페이지 [저장](자동저장 없음) · 서버 M01_MasterData_Machine.fix = 품셈 입력이 바뀌면 계수 짝으로 다시 셈 · 단위 · 출처 칸 채움(새 칸 = 마스터 단위 · 「자체」) - API /api/m01/machine/lists · hourly · uses · find · row (시스템 관리자만) · 시험 test_821_2_machine_save.py Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
157 lines
6.4 KiB
Python
157 lines
6.4 KiB
Python
"""PLAN 821-2 M01 기계 저장 — 지킴 시험(임시 사본 폴더만 · 정본 안 씀).
|
|
|
|
① 새 기계 = 단위 · 출처 자동(마스터 단위 · 「자체」) · 계수 서버 재계산 · 다른 줄 그대로
|
|
② 고침 = 그 칸 한 줄만 · 품셈 입력이 같으면 저장 계수 그대로(점보드릴 777) · 바뀌면 다시 셈
|
|
③ 기계 길은 시스템 관리자만(아니면 403) · 양식 목록 · 비슷한 기계 찾기 · 쓰는 곳
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import difflib
|
|
import json
|
|
import shutil
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from fastapi import Depends, FastAPI
|
|
from fastapi.testclient import TestClient
|
|
|
|
from common_util import common_util_auth as auth
|
|
from M01_MasterData import M01_MasterData_Router as router_module
|
|
from M01_MasterData import M01_MasterData_Store as store
|
|
|
|
sys.path.insert(
|
|
0, str(Path(__file__).resolve().parents[2] / "resources" / "master_data" / "scripts")
|
|
)
|
|
import master_machine_coef as mc # noqa: E402
|
|
|
|
REAL = store.FOLDER
|
|
MACHINE = "기계.json"
|
|
|
|
|
|
@pytest.fixture
|
|
def copy(tmp_path: Path, monkeypatch) -> Path:
|
|
for path in REAL.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)
|
|
return tmp_path
|
|
|
|
|
|
def _app(role: str = "SYSTEM_ADMIN") -> TestClient:
|
|
app = FastAPI()
|
|
app.dependency_overrides[auth.verify_session] = lambda: {
|
|
"user_id": 1,
|
|
"name": "시험",
|
|
"role": role,
|
|
"company_id": 1,
|
|
}
|
|
deps = [Depends(auth.verify_session), Depends(auth.require_system_admin)]
|
|
app.include_router(router_module.router, dependencies=deps)
|
|
return TestClient(app)
|
|
|
|
|
|
def _save(client: TestClient, version: str, change: dict) -> None:
|
|
res = client.post(
|
|
"/api/m01/save",
|
|
json={"files": [{"file": MACHINE, "version": version, "changes": [change]}]},
|
|
)
|
|
assert res.status_code == 200, res.text
|
|
|
|
|
|
def _diff(before: str, after: str) -> list[str]:
|
|
return [
|
|
x
|
|
for x in difflib.unified_diff(before.splitlines(), after.splitlines(), lineterm="", n=0)
|
|
if x[:1] in "+-" and not x.startswith(("+++", "---"))
|
|
]
|
|
|
|
|
|
def test_새_기계_단위_출처_자동_계수_서버_재계산(copy: Path) -> None:
|
|
client = _app()
|
|
lists = client.get("/api/m01/machine/lists").json()
|
|
assert {"경유", "휘발유"} <= {f["value"] for f in lists["fuels"]}
|
|
assert any(j["value"] == "1048" for j in lists["jobs"]) and lists["hour"] == 0.125
|
|
found = client.get("/api/m01/machine/find", params={"q": "굴착기 1.0㎥"}).json()["rows"]
|
|
seed = next(r for r in found if r["키"] == "EQ000022")
|
|
before = (copy / MACHINE).read_text(encoding="utf-8")
|
|
version = client.get("/api/m01/machine/row", params={"key": "EQ000022"}).json()["version"]
|
|
values = {**seed["값"], "내용시간": 8000, "손료계수": 1, "상각비계수": 1} # 계수 = 틀린 값
|
|
row = {
|
|
"키": "",
|
|
"원문번호": "",
|
|
**{k: seed[k] for k in ("원문", "구분", "상세구분")},
|
|
"이름": "시험기계sub1",
|
|
"규격": "9.9㎥",
|
|
"단위": {},
|
|
"값": values,
|
|
"출처": {},
|
|
"비고": None,
|
|
}
|
|
_save(client, version, {"op": "add", "row": row})
|
|
after = (copy / MACHINE).read_text(encoding="utf-8")
|
|
rows = json.loads(after)["줄"]
|
|
new = rows[-1]
|
|
assert new["이름"] == "시험기계sub1" and new["키"].startswith("EQ")
|
|
assert new["값"] | mc.coef(8000, 1250, 0.9, 0.7, 0.1) == new["값"] # 서버가 다시 셈
|
|
assert new["값"]["손료계수"] == 1125 + 875 + 496
|
|
assert set(new["단위"]) == set(new["값"]) == set(new["출처"])
|
|
assert new["단위"] == {
|
|
k: seed_unit for k, seed_unit in _units(before).items() if k in new["값"]
|
|
}
|
|
assert set(new["출처"].values()) == {"자체"}
|
|
assert json.loads(before)["줄"] == rows[:-1] # 다른 줄 그대로
|
|
assert all(x.startswith("+") for x in _diff(before, after)) # 글은 더하기만
|
|
|
|
|
|
def _units(text: str) -> dict:
|
|
return next(r for r in json.loads(text)["줄"] if r["키"] == "EQ000022")["단위"]
|
|
|
|
|
|
def _edit(client: TestClient, key: str, change) -> tuple[dict, dict]:
|
|
got = client.get("/api/m01/machine/row", params={"key": key}).json()
|
|
row = got["row"]
|
|
_save(client, got["version"], {"op": "edit", "key": key, "row": change(row)})
|
|
now = client.get("/api/m01/machine/row", params={"key": key}).json()["row"]
|
|
return row, now
|
|
|
|
|
|
def test_고침_그_줄_그_칸만(copy: Path) -> None:
|
|
client = _app()
|
|
before = (copy / MACHINE).read_text(encoding="utf-8")
|
|
row, now = _edit(client, "EQ000022", lambda r: {**r, "값": {**r["값"], "가격": 150000}})
|
|
assert now == {**row, "값": {**row["값"], "가격": 150000}}
|
|
lines = _diff(before, (copy / MACHINE).read_text(encoding="utf-8"))
|
|
assert len(lines) == 2 and "142069" in lines[0] and "150000" in lines[1] # 그 칸 한 줄만
|
|
|
|
|
|
def test_입력_같으면_저장_계수_그대로_바뀌면_다시_셈(copy: Path) -> None:
|
|
client = _app()
|
|
# 가격만 고침 + 화면이 계수를 틀리게 보내도 — 입력이 같으면 원문 표 값(정비비계수 777) 그대로
|
|
row, now = _edit(
|
|
client,
|
|
"EQ000347",
|
|
lambda r: {**r, "값": {**r["값"], "가격": 999, "정비비계수": 778, "손료계수": 1}},
|
|
)
|
|
assert now["값"] == {**row["값"], "가격": 999}
|
|
_, now = _edit(client, "EQ000347", lambda r: {**r, "값": {**r["값"], "내용시간": 10000}})
|
|
assert {k: now["값"][k] for k in mc.COEFS} == mc.coef(10000, 800, 0.9, 0.7, 0.1)
|
|
|
|
|
|
def test_기계_길은_시스템_관리자만() -> None:
|
|
for role in ("USER", "COMPANY_ADMIN"):
|
|
client = _app(role)
|
|
assert client.get("/api/m01/machine/lists").status_code == 403
|
|
assert client.get("/api/m01/machine/hourly", params={"keys": "EQ000022"}).status_code == 403
|
|
assert client.post("/api/m01/save", json={"files": []}).status_code == 403
|
|
|
|
|
|
def test_쓰는_곳_찾기(copy: Path, monkeypatch) -> None:
|
|
from M02_MasterTemplete import M02_Template_Layers as layers
|
|
|
|
monkeypatch.setattr(layers, "layer_files", lambda kind: []) # 공유 storage 안 읽음
|
|
uses = _app().get("/api/m01/machine/uses", params={"key": "EQ000022"}).json()["uses"]
|
|
assert any("GC000267" in u for u in uses)
|
|
assert _app().get("/api/m01/machine/uses", params={"key": "EQ999999"}).status_code == 404
|