Files
Aislo/resources/tester/test_stmate_ui_protect.py
T

91 lines
3.6 KiB
Python

"""STMATE 재현 앱 보호표시(UC) 일괄 손질 제외 · 단가 성분 검사(TAMT = 재+노+경 · 코드종류별 비목).
보호 = wM_Boxa 단가 격자 「보호」 열(√/공란 = True/False) → 기초·견적단가(M·L·S·W) 행 COSTN UC.
일괄 손질(가격지 채택 · 기준단가 수정 · 일괄할증 · 일괄변경 · 후보 채택)은 보호 행을 건너뜀(22 §3.1 안내문).
B·D 행 UC 는 산근 편집기 「결과값에 낙찰율적용」(Ck_UC) 자리 — 실무 7건 UC=T ⇔ NAGCD>0.
성분 검사 = 10 §3 검증 조건식 — 실무 7건 COSTN·내역 어긋남 0 · 일부러 어긋낸 칸만 잡힘.
"""
import json
import subprocess
import sys
from pathlib import Path
import pytest
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / "tools/stmate-test"))
import server # noqa: E402
from stc_save import apply_save # noqa: E402
HERE = Path(__file__).parent
STCS = sorted((ROOT / "resources/knowledge/original/실무문서").rglob("*.STC"))
IDS = [p.stem[:16] for p in STCS]
_CACHE: dict = {}
def _f(v):
return float(v or 0)
def run(stc):
if stc not in _CACHE:
d = server.api_load(server.LoadReq(source_path=str(stc)))
# 보호 대상 = 바뀔 수 있는 기초단가 몇 건(후보 있는 재료 · 노무 · 경비) — 자료에서 고름
mls = [r for r in d["costn_rows"] if r["CODE"][:1] in "MLS" and _f(r["TAMT1"]) > 0]
cand = [r for r in mls if any(_f(r.get(f"AMT_{i}1")) > 0 for i in range(1, 6))]
prot = [r["CODE"].strip() for r in (cand[:3] + [r for r in mls if r not in cand][:2])]
d["prot"] = prot
out = subprocess.check_output(
["node", str(HERE / "helper_stmate_ui_protect.cjs")],
input=json.dumps(d, ensure_ascii=False, default=str),
text=True,
encoding="utf-8",
)
_CACHE[stc] = (d, json.loads(out))
return _CACHE[stc]
@pytest.mark.parametrize("stc", STCS, ids=IDS)
def test_batch_edits_skip_protected_rows(stc):
d, r = run(stc)
prot = set(d["prot"])
assert prot
moved = 0
for name, o in r["ops"].items():
assert o["untouched"], name # 보호 행 단가 그대로
assert o["marked"] == sorted(set(o["plain"]) - prot), name # 나머지는 보호 없을 때와 같음
moved += len(set(o["plain"]) & prot)
assert moved > 0 # 보호가 없었으면 바뀌었을 행이 실제로 있었음
@pytest.mark.parametrize("stc", STCS, ids=IDS)
def test_unprotect_auto_hal_and_bd_uc_is_bid_rate_flag(stc):
d, r = run(stc)
a = r["autoHal"]
assert a["uc"] == "F" and a["got"] is not None and a["got"] == a["want"]
assert r["bdProtected"] == 0 # 산근·일위 UC=T 는 보호로 보지 않음
for row in d["costn_rows"]: # 근거 — UC=T ⇔ 낙찰율 열(NAGCD) > 0
if row["CODE"][:1] in "BD":
assert (str(row.get("UC") or "").strip() == "T") == (_f(row.get("NAGCD")) > 0)
@pytest.mark.parametrize("stc", STCS, ids=IDS)
def test_protect_mark_saves_only_uc(stc):
d, r = run(stc)
files = server.read_project_files(str(stc))
_out, log = apply_save(files, r["payload"])
got = {(x["table"], x["field"]) for x in log}
assert got == {("COSTN.DBF", "UC")}
assert len(log) == len(d["prot"])
@pytest.mark.parametrize("stc", STCS, ids=IDS)
def test_component_check_clean_on_real_and_catches_broken(stc):
_d, r = run(stc)
assert r["check"] == []
assert r["checkBoq"] == [], r["checkBoq"][:3]
b = r["broken"]
hits = {(x["code"], x["slot"], x["rule"]) for x in b["res"]}
assert hits == {(b["m"], 1, "own"), (b["m"], 1, "sum"), (b["b"], 1, "sum")}