Files
Aislo/resources/tester/test_166_3_b09_material_qty.py
T
eomsangdonandClaude Opus 5.5 ad8b9e626b fix(b09): 재료비목록표 B08 총괄 줄 안 들어옴 — B08 답 sheets 한 층 아래 읽기 · 파형강관 관급 기본(167-2)
B08 자재 길 답 = {source, sheets: {material}} 인데 B09 가 한 층 위를 읽어 총괄 줄 · 운반 수량이 늘 빈칸 · 시험 가짜 답도 같은 꼴로 바로잡음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sDZSjFvoiDjdGpgj3muc3
2026-10-10 00:28:34 +09:00

117 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""166-3 재료비목록표 = B08 총괄 합계 × 적용 단가 = 총액 ROUND 0 · 공제 거름 · MT 합침 · 거울."""
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from B09_Estimation import B09_Estimation_Prices as prices # noqa: E402
from B09_Estimation.B09_Estimation_Calc_Base import compute_base # noqa: E402
from resources.tester.test_144_b09_base_calc import _run_ts # noqa: E402
MATERIALS = [
{"key": "MT1", "name": "부직포", "prices": {"물가자료": 1234.5}, "qty": 10.25},
{"key": "MT2", "name": "수량 없는 사본 줄", "prices": {"물가자료": 500}},
{"key": "b08:cement", "name": "시멘트", "prices": {}, "qty": 3.333},
{"key": "b08:sand", "name": "모래", "prices": {}, "qty": 7},
]
INPUTS = {"labor": [], "machines": [], "materials": MATERIALS}
USER = {"materials": {"b08:cement": {"applied": 7000.5}}}
def test_총액_ROUND_0_빈칸():
rows = {r["key"]: r for r in compute_base(INPUTS, USER)["material"]}
assert (rows["MT1"]["qty"], rows["MT1"]["price"], rows["MT1"]["amount"]) == (
10.25,
1234.5,
12654,
) # 12,653.6 → 반 올림
assert rows["b08:cement"]["amount"] == 23333 # 3.333 × 7000.5 = 23,332.67
assert rows["MT2"]["qty"] is None and rows["MT2"]["amount"] is None # 수량 빈칸
assert rows["b08:sand"]["price"] is None and rows["b08:sand"]["amount"] is None # 단가 빈칸
def test_거울_TS():
for user in ({}, USER):
assert _run_ts(INPUTS, user) == compute_base(INPUTS, user)
def test_공제_거름_MT_합침(monkeypatch):
sheets = {
"material": {
"rows": [
{"key": "cement", "group": "시멘트", "unit": "포", "amount": 12.5},
{"key": "picked_deduct", "group": "채집석 공제", "unit": "㎥", "amount": 4},
{"key": "MT1", "group": "부직포", "unit": "㎡", "amount": 30.1},
{"key": "MT9", "group": "사본에 없는 MT", "unit": "개", "amount": 2},
{"key": "empty", "group": "수량 없음", "amount": None},
]
}
}
keys = [r["key"] for r in prices.b08_material_rows(sheets)]
assert keys == ["b08:cement", "b08:MT1", "b08:MT9"]
monkeypatch.setattr(prices, "_master", lambda: None)
monkeypatch.setattr(
prices,
"demand",
lambda master, keys: {"labor": [], "machines": [], "materials": ["MT1", "MO1"],
"fuel_keys": {}, "missing": []},
) # fmt: skip
book = {"rows": {"MT1": {"key": "MT1", "name": "부직포"}, "MO1": {"key": "MO1"}}}
got = prices.build_inputs(book, [], sheets)["materials"]
assert [r["key"] for r in got] == ["MT1", "MO1", "b08:cement", "b08:MT9"]
assert got[0]["qty"] == 30.1 and "qty" not in book["rows"]["MT1"] # 책은 안 바꿈
assert got[2]["qty"] == 12.5
def test_167_2_B08_답_한_층_아래_총괄_줄(monkeypatch):
"""B08 길 답 = {source, sheets: {material: {rows}}} — sheets 를 읽어야 총괄 줄이 들어옴."""
import asyncio
from B09_Estimation import B09_Estimation_Router as router_mod
rows = [
{"key": "pipe_1200", "group": "파형강관", "spec": "Φ1200mm", "unit": "m", "amount": 7},
{
"key": "coupling_1200",
"group": "커플링밴드",
"spec": "Φ1200mm",
"unit": "개",
"amount": 0,
},
{"key": "합판(준내수)|㎡", "group": "합판(준내수)", "unit": "㎡", "amount": 7},
{"key": "picked_deduct", "group": "채집석 공제", "amount": None},
]
async def materials(_pid):
return {"source": {"columns": []}, "notes": [], "sheets": {"material": {"rows": rows}}}
async def earthwork(_pid):
return None
monkeypatch.setattr(router_mod, "material_sheets", materials)
monkeypatch.setattr(router_mod, "earthwork_table", earthwork)
b08 = asyncio.run(router_mod._b08(None, []))
assert b08["summary"] == {"columns": []}
got = prices.b08_material_rows(b08["materials"])
assert [(r["key"], r["qty"], r.get("supply")) for r in got] == [
("b08:pipe_1200", 7, "관급"),
("b08:coupling_1200", 0, None),
("b08:합판(준내수)|㎡", 7, None),
]
s = compute_base({"labor": [], "machines": [], "materials": got}, USER_PIPE)
rows_out = {r["key"]: r for r in s["material"]}
assert rows_out["b08:pipe_1200"]["supply"] == "별도" # 사용자 표시가 앞섬
plain = compute_base({"labor": [], "machines": [], "materials": got}, {})
assert plain["material"][0]["supply"] == "관급" # 파형강관 기본 = 관급
assert rows_out["b08:합판(준내수)|㎡"]["amount"] == 7 * 12000
assert rows_out["b08:coupling_1200"]["price"] is None # 단가 없음 = 빈칸(견적 칸으로)
assert _run_ts({"labor": [], "machines": [], "materials": got}, USER_PIPE) == s
USER_PIPE = {"materials": {"b08:합판(준내수)|㎡": {"quote": 12000},
"b08:pipe_1200": {"supply": "별도"}}} # fmt: skip