Files
Aislo/resources/tester/test_m02_labor_mat_marks.py
T

166 lines
7.1 KiB
Python

"""일위대가 자재목록 세 칸(PLAN 148-4) — 자재구분 · 별도계상 · 운반비 · 금액 무관.
- 서버 `clean` = 허용 값만(그 밖 · 빈 것 버림) · 사용자 자재 = 줄 덧칸 ·
로직 자재 = 로직 줄 `자재표시 {호표 차례: 세 칸}`(차례가 재료 줄인 것만 · 틀려도 400 아님)
- 기준합 · 반영합 그대로 · 저장 왕복에 남음 · 화면 `normalizeLabor` 도 같은 규칙(Node 헬퍼)
- 화면 칸 부품 = 새 파일 · 사용자 줄 · 로직 줄 같은 칸 · 사전조합 줄엔 안 넘김(소스 검사)
- 162-1 = 「일반」 지움(관급 · 사급) · 빈 칸 = 읽을 때 기본(사급 · 별도계상 · 포함 · 저장은 비움) ·
옛 「일반」 = 사급으로 읽음
- 168-1 = 운반비 드롭다운 늘 켬(별도계상과 따로 · 각자 저장)
"""
import json
import os
import subprocess
import pytest
from M02_MasterTemplete import M02_Labor_Doc as labor
from M02_MasterTemplete import M02_MasterTemplete_Store as store
from resources.tester.test_m02_structure import write_sample_table
HERE = os.path.dirname(os.path.abspath(__file__))
SRC = os.path.join(HERE, "..", "..", "M02_MasterTemplete")
NET = "GC000337" # 낙석방지망 — 재료 줄 3 · 4 · 5
WIRE = "MT000194"
MARKS = {"자재구분": "관급", "별도계상": "별도계상", "운반비": "미포함"}
def _doc(**extra):
return {"열": "rv", "담은로직": [], "자재": [], **extra}
def _first_non_material(code):
from M01_MasterData import M01_MasterData_Store as m01
rows = m01.loaded()[1].logic(code).get("호표") or []
return next(n for n, r in enumerate(rows) if r.get("종류") != "재료")
def test_사용자_자재_허용_값만():
got = labor.clean(
_doc(자재=[{"코드": WIRE, **MARKS}, {"코드": "MT000008", "자재구분": "아무", "운반비": ""}])
)["자재"]
assert {k: got[0][k] for k in MARKS} == MARKS
assert not set(MARKS) & set(got[1])
def test_로직_자재_자재표시_재료_줄_차례만_허용_값만():
other = _first_non_material(NET)
shown = {"3": MARKS, "4": {"자재구분": "엉뚱"}, str(other): MARKS, "99": MARKS, "x": MARKS}
line = labor.clean(_doc(담은로직=[{"로직": NET, "자재표시": shown}]))["담은로직"][0]
assert line["자재표시"] == {"3": MARKS}
bare = labor.clean(_doc(담은로직=[{"로직": NET, "자재표시": {"4": {"운반비": "?"}}}]))
assert "자재표시" not in bare["담은로직"][0]
def test_금액_그대로():
plain = _doc(
담은로직=[{"로직": NET, "수량": {"손": 2}}], 자재=[{"코드": WIRE, "수량": {"손": 3}}]
)
marked = _doc(
담은로직=[{"로직": NET, "수량": {"손": 2}, "자재표시": {"3": MARKS}}],
자재=[{"코드": WIRE, "수량": {"손": 3}, **MARKS}],
)
a, b = (labor.calc(labor.clean(d), {}) for d in (plain, marked))
assert a["기준합"] == b["기준합"] and a["반영합"] == b["반영합"]
@pytest.fixture()
def system(tmp_path, monkeypatch):
write_sample_table(tmp_path)
monkeypatch.setattr(store, "FOLDER", tmp_path)
store.create_structure("rv")
return tmp_path
def test_저장_왕복에_남음(system):
have = store.read("labor", "rv")
sent = {
**have["문서"],
"담은로직": [{"로직": NET, "수량": None, "자재표시": {"3": MARKS}}],
"자재": [{"코드": "MT000008", "수량": None, "자재구분": "사급"}],
}
store.write("labor", "rv", have["판"], sent)
doc = store.read("labor", "rv")["문서"]
assert doc["담은로직"][0]["자재표시"] == {"3": MARKS}
assert doc["자재"][0]["자재구분"] == "사급" and "운반비" not in doc["자재"][0]
def test_화면_정리도_허용_값만():
doc = {
"담은로직": [
{"로직": NET, "자재표시": {"3": MARKS, "4": {"운반비": "?"}}},
{
"로직": "",
"참조": {"층": "system", "주인": None, "키": "SC-1"},
"자재표시": {"3": MARKS},
},
],
"자재": [{"코드": WIRE, "별도계상": "직접계산", "자재구분": "?"}],
}
proc = subprocess.run(
["node", os.path.join(HERE, "helper_m02_labor_normalize.cjs")],
input=json.dumps({"doc": doc, "column": "rv"}, ensure_ascii=False),
capture_output=True,
text=True,
encoding="utf-8",
check=True,
)
got = json.loads(proc.stdout)
assert [r.get("자재표시") for r in got["담은로직"]] == [{"3": MARKS}, None]
assert got["자재"][0]["별도계상"] == "직접계산" and "자재구분" not in got["자재"][0]
def _src(name):
with open(os.path.join(SRC, name), encoding="utf-8") as f:
return f.read()
def test_화면_칸_부품_사용자_줄_로직_줄_같은_칸():
marks = _src("M02_MasterTemplete_Labor_MatMarks.ts")
assert '"—"' not in marks # 「—」 항목 없음(162-1)
assert "e.stopPropagation()" in marks # 줄 누름과 따로
rows = _src("M02_MasterTemplete_Labor_Rows.ts")
assert "...markCells(mat, on?.mark" in rows and "...markHeads()," in rows
assert "...markCells(" in _src("M02_MasterTemplete_Labor_LogicMats.ts")
detail = _src("M02_MasterTemplete_Labor_Detail.ts")
assert "mark: lib ? undefined : markLogicMat" in detail
assert "mark: markMat" in detail
# 서버 허용 값 = 화면 허용 값
api = _src("M02_MasterTemplete_Labor_Api.ts")
for key, allowed in labor.MARKS.items():
assert f"{key}: [{', '.join(json.dumps(v, ensure_ascii=False) for v in allowed)}]" in api
def test_빈_칸_기본값_허용_값_그대로():
assert labor.MARK_DEFAULT == {"자재구분": "사급", "별도계상": "별도계상", "운반비": "포함"}
assert {k: labor.mark_of({}, k) for k in labor.MARKS} == labor.MARK_DEFAULT
assert {k: labor.mark_of(MARKS, k) for k in labor.MARKS} == MARKS
assert labor.mark_of(None, "운반비") == "포함"
def test_옛_일반은_사급으로_읽음():
assert "일반" not in labor.MARKS["자재구분"]
got = labor.clean(
_doc(
담은로직=[{"로직": NET, "자재표시": {"3": {"자재구분": "일반", "운반비": "미포함"}}}],
자재=[{"코드": WIRE, "자재구분": "일반"}],
)
)
assert got["담은로직"][0]["자재표시"] == {"3": {"운반비": "미포함"}} # 저장은 채우지 않음
assert "자재구분" not in got["자재"][0]
assert labor.mark_of(got["자재"][0], "자재구분") == "사급"
assert labor.mark_of({"자재구분": "일반"}, "자재구분") == "사급"
def test_화면_기본값_한_벌_운반비_늘_켬():
api = _src("M02_MasterTemplete_Labor_Api.ts")
for key, v in labor.MARK_DEFAULT.items():
assert f'{key}: "{v}",' in api.split("MAT_MARK_DEFAULT")[1].split("};")[0]
marks = _src("M02_MasterTemplete_Labor_MatMarks.ts")
assert "value[key] ?? MAT_MARK_DEFAULT[key]" in marks
assert "disabled" not in marks and "haulOff" not in marks # 별도계상과 따로
assert "onChange: (v) => set(key, v)," in marks # 칸마다 제 값만 저장
assert '일반: "Mark_General"' not in marks