- M02_Hopyo_Material.spec_fit: 827-2 「자재 수 한 번씩」 을 좁힘 — 줄 수와 그대로 같은 자재 수만 그 줄 수 몫 · 배율로만 맞는 수는 같이 씀(글 붙은 「#200.9mm200.4m/kg」 = #20 0.9mm 200.4m/kg → MT000209 되살림 · 블레이드 d=320~400 t=3.2 → 4"×3.2 는 그대로 풀림 · 21-17-17 의 17 둘 각각) - 호표 길 전수(실무 엑셀 8 · 일위대가 줄 1564): 827-2 앞 대비 바뀜 = 블레이드 1 줄(틀린 이음 풀림)뿐 · 어닐링철선 5 줄 되살림 · 단산 길 전수 827-2 전후표 수치 그대로(새 이음 · 풀림 · 키 바뀜 0) - M02_Sangeun_Imported 검산: 첫 자리가 같은 글줄 여럿(814-1 기계 노 · 재 · 경 · 노 줄만 딸린 기계까지) = 값 합으로도 맞댐(check · 화면 more 둘 다) · 계약(낙찰률) 블록 = 비목 × 낙찰률 원 버림과도 맞댐(머리 금액만 있는 STmate) - 세 원천 3241 블록 검산 다름 287 → 4(EST main 1308 · 북부청임도 2 · 4 · 48 = 엑셀 글 소계가 줄 합과 다름 — 진짜 다름 · 금액은 같음) - 시험: 827-5 xfail 셋 뗌(test_778_5 자재 표 · test_793_2 동부청영월 · 울진소광) · 지킴 둘 더함(글 붙은 규격 수 · 묶은 줄 합 · 계약 셈) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
147 lines
7.8 KiB
Python
147 lines
7.8 KiB
Python
"""778-5 줄 잇기 한 벌 · 블록 = 줄 판정 모음 · 단위 SK(D-2 · D-3 · 요구 622 · 623 · 624).
|
||
|
||
- 줄 잇기(`M02_Hopyo_Units`) — 작업반장 = 건설업 · 숫자 규격 치수 차례 · 구분자 무관 · 글자 규격 = 고를 것 ·
|
||
손료율 = 자재 줄 방법 · 우리에 없는 율 항목(설치비 · 제경비) = 율 줄 · 여덟 파일 묶음별 수 굳힘
|
||
- 단위 SK(`M02_Hopyo_SkUnit` · `M02_Hopyo_Sangeun`) — 확인 안 한 블록 안 만듦 · 확인 블록 = 바탕 없는 SK +
|
||
근거 꼬리표 · 고를 줄 남으면 못만듦 · 고르면 만듦 · 다시 올려도 같은 SK 재사용 · 일위대가 = 확인 전 못 이음
|
||
층 = 임시 폴더 · M01 · 마스터 읽기만.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
|
||
import pytest
|
||
|
||
from M02_MasterTemplete import M02_Hopyo_Material as hmat
|
||
from M02_MasterTemplete import M02_Hopyo_Sangeun as sangeun
|
||
from M02_MasterTemplete import M02_Hopyo_SkUnit as skunit
|
||
from M02_MasterTemplete import M02_Hopyo_Units as units
|
||
from M02_MasterTemplete import M02_Labor_Doc as labor
|
||
from M02_MasterTemplete import M02_Sangeun_Calc as calc
|
||
from M02_MasterTemplete import M02_Sangeun_Doc as sd
|
||
from resources.tester import helper_m02_hopyo_golden as golden
|
||
from resources.tester.test_m02_hopyo_excel import URL, _post, client, master_hash # noqa: F401
|
||
|
||
# 여덟 파일 불리는 블록 줄 연결 표(778-5 D-2 · 바닥값 — 이어짐은 이 수 이상 · 고를 것 · 못 이음은 이 수 이하 ·
|
||
# 마스터 · 기계 자료가 좋아지면 바닥이 오름 · 줄 수는 엑셀 몫이라 그대로)
|
||
TABLE = {
|
||
"L": {"이어짐": 366, "고를 것": 0, "못 이음": 0},
|
||
"X": {"이어짐": 187, "고를 것": 1, "못 이음": 2}, # 812-9 찾기 · 못 이음 = 조합 · 괄호 깨짐
|
||
"M": {"이어짐": 71, "고를 것": 55, "못 이음": 4},
|
||
"R": {"이어짐": 150, "고를 것": 2, "못 이음": 0},
|
||
"S": {"이어짐": 3, "고를 것": 0, "못 이음": 0},
|
||
"E": {"이어짐": 1, "고를 것": 0, "못 이음": 0},
|
||
}
|
||
ALL_LINKED = 161 # 815-3 호표 기계 글 쌍점 · 율 꼬리 뗌 — 줄이 다 이어진 블록 수 바닥
|
||
BLOCKS = 206
|
||
|
||
|
||
@pytest.fixture(scope="module")
|
||
def us():
|
||
return units.Units()
|
||
|
||
|
||
def test_작업반장_건설업_기본(us):
|
||
got = us.line({"묶음": "L", "이름": "작업반장", "직종": "작업반장", "품": 0.1})
|
||
assert got["상태"] == units.LINKED and got["단위"] == {"노임": "LB000001"} # 건설업
|
||
assert got["꼬리표"] == ["기본 — 건설업 작업반장"] and got["후보"][0]["키"] == "LB000261"
|
||
one = us.line({"묶음": "L", "이름": "보통인부", "직종": "보통인부", "품": 0.5})
|
||
assert one["단위"] == {"노임": "LB000002"} and not one["꼬리표"]
|
||
|
||
|
||
def test_숫자_규격_차례_구분자_무관_글자_규격_후보(us):
|
||
assert hmat.dims("600×1200") == hmat.dims("1200x600 mm") == hmat.dims("1200*600㎜")
|
||
assert hmat.dims("1종2류(철재)") is None and hmat.lettered("1종2류(철재)")
|
||
assert not hmat.lettered("600*1200mm") and not hmat.lettered("#20, 0.9mm")
|
||
for spec in ("600×1200", "1200x600", "1200 X 600mm"):
|
||
got = us.line({"묶음": "M", "이름": "유로폼패널", "규격": spec, "단위": "매", "품": 1})
|
||
assert got["상태"] == units.LINKED and got["단위"] == {"자재": "MT000467"}, spec
|
||
named = us.line({"묶음": "M", "이름": "유로폼(패널)(600×1200)", "단위": None, "품": 1})
|
||
assert named["단위"] == {"자재": "MT000467"} # 「유로폼(패널)」 = 유로폼패널 · 단위 없는 EST 줄
|
||
paint = {"묶음": "M", "이름": "광명단조합페인트", "규격": "1종2류(철재)", "단위": "L", "품": 1}
|
||
got = us.line(paint)
|
||
assert got["상태"] == units.PICK and got["글"] == units.LETTERS and got["후보"]
|
||
|
||
|
||
def test_손료율_자재_줄_율_항목_율_줄(us):
|
||
wear = us.line({"묶음": "M", "이름": "유로폼패널", "규격": "600×1200", "품": 0.267,
|
||
"손료율": 0.267}) # fmt: skip
|
||
assert wear["방법"] == units.WEAR and wear["상태"] == units.LINKED
|
||
setup = {"묶음": "R", "이름": "설치비(재료비의 5%)", "품": 0.05, "기준꼴": "자재"}
|
||
assert us.line(setup)["단위"] == {"기준": "재료", "비목": "재료비"} # 우리에 없는 율 항목
|
||
rest = {"묶음": "R", "이름": "제경비(노무비의 60%)", "품": 0.6, "기준꼴": "노무비"}
|
||
assert us.line(rest)["단위"] == {"기준": "노무비", "비목": "경비"}
|
||
lost = us.line({"묶음": "R", "이름": "기구손료(노무비의 9%)", "기준": "노무비", "품": 0.09})
|
||
assert lost["상태"] == units.PICK and lost["후보"] == [{"기준": "노무비", "비목": "경비"}]
|
||
# 단위 SK 셈 — 설치비 = 재료 줄 × 5 % · 제경비 = 노무비 × 60 %
|
||
block = {"항목": [
|
||
{"묶음": "L", "이름": "보통인부", "직종": "보통인부", "품": 0.5, "행": 1},
|
||
{"묶음": "M", "이름": "유로폼패널", "규격": "600×1200", "단위": "매", "품": 2, "행": 2},
|
||
{**setup, "행": 3}, {**rest, "행": 4},
|
||
]} # fmt: skip
|
||
got = skunit.judge(block, us, lambda sub: None, None, "㎡")
|
||
assert got["판정"] == skunit.GOOD and [r["상태"] for r in got["줄"]] == [units.LINKED] * 4
|
||
labor_, mat = (got["줄"][0]["우리금액"], got["줄"][1]["우리금액"])
|
||
assert got["줄"][2]["우리금액"] == pytest.approx(mat * 0.05, abs=0.1)
|
||
assert got["줄"][3]["우리금액"] == pytest.approx(labor_ * 0.6, abs=0.1)
|
||
doc = {"키": "SK-000001", "이름": "t", "단위": "㎡", "바탕": None, "더한줄": got["더한줄"]}
|
||
whole = us.whole
|
||
ran = labor._json(calc.run(sd.clean(doc, None, whole), whole))
|
||
assert ran["1단위"]["계"] == pytest.approx(got["우리금액"])
|
||
|
||
|
||
def test_글_붙은_규격_수_배율_같이_씀_같은_수는_한_번(us):
|
||
"""827-6 — 「#200.9mm200.4m/kg」(#20 0.9mm 200.4m/kg 글 붙음) = 어닐링철선 이음 · 같은 수 두 번
|
||
맞춤(블레이드 320 · 3.2 → 4"×3.2) · 이름 다른 드릴롯드 = 이음 안 함 · 21-17-17 의 17 둘."""
|
||
|
||
def got(name, spec=""):
|
||
return us.line({"묶음": "M", "이름": name, "규격": spec, "품": 1})
|
||
|
||
wire = got("어닐링철선(결속선)(#200.9mm200.4m/kg)")
|
||
assert wire["상태"] == units.LINKED and wire["단위"] == {"자재": "MT000209"}
|
||
assert got("블레이드", "d=320~400mm t=3.2")["상태"] != units.LINKED
|
||
assert got("유압식드릴롯드", "T38×R32x3660mm")["상태"] != units.LINKED
|
||
assert got("복합비료(21-17-1720kg/포)")["단위"] == {"자재": "MT006490"}
|
||
|
||
|
||
@pytest.fixture(scope="module")
|
||
def table(us):
|
||
rows, full, blocks = [], 0, 0
|
||
for tag in golden.FILES:
|
||
hp = golden.read(tag)
|
||
_, first = sangeun.calls(hp)
|
||
for b in hp["단산"]:
|
||
if int(b["번"]) not in first:
|
||
continue
|
||
got = [(o["묶음"], us.line(o)["상태"]) for o in b.get("항목") or [] if not o.get("밖")]
|
||
rows += got
|
||
blocks += 1
|
||
full += all(s == units.LINKED for _, s in got)
|
||
return units.summary(rows), full, blocks
|
||
|
||
|
||
def _floor(got: dict, kind: str) -> None:
|
||
want = TABLE[kind]
|
||
assert sum(got[kind].values()) == sum(want.values()), kind # 줄 수 = 엑셀 몫
|
||
assert got[kind][units.LINKED] >= want[units.LINKED], kind
|
||
assert got[kind][units.PICK] <= want[units.PICK], kind
|
||
assert got[kind][units.NONE] <= want[units.NONE], kind
|
||
|
||
|
||
def test_여덟_파일_줄_연결_표(table):
|
||
got, _, blocks = table
|
||
assert set(got) == set(TABLE) and blocks == BLOCKS
|
||
for kind in "LXRSE":
|
||
_floor(got, kind)
|
||
|
||
|
||
def test_여덟_파일_자재_줄_연결_표(table):
|
||
got, full, _ = table
|
||
_floor(got, "M")
|
||
assert full >= ALL_LINKED
|
||
|
||
|
||
def _sks(folder) -> dict[str, dict]:
|
||
return {p.stem: json.loads(p.read_bytes()) for p in (folder / "sangeun").glob("SK-*.json")}
|