936be972 화면: 돌쌓기(찰) H=2.5 장에 H=2.0 호표 → 배지 「규격 다름 H2 ↔ H2.5」 · 테두리 · 사유 첫 줄 규격 다름 + 원문 시점 수량 · 뒷길이·돌 종류 사유 걷힘 · 되돌려 전부 같음 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
97 lines
3.7 KiB
Python
97 lines
3.7 KiB
Python
"""㉰ 고정형 장 사유 · ㉱ 규격 다름 (2026-09-14 브레인 판정).
|
|
|
|
㉰ 고정형을 가져온 장에 **전개 사유(뒷길이 표준·돌 종류…)가 그대로 남아** 고정형 줄과 안 맞음 = 거짓 사유 →
|
|
항목 사유(원문 시점 수량·가산 행)를 띄우고 전개 사유는 **남긴 전개 줄(토공·버림·기초잡석·채집석)에 걸린 것만** 둠.
|
|
㉱ H=2.0 호표를 H=2.5 벽에 쓰면 벽 수량은 박힌 값(H2.0) · 토공·사토 공제는 장 제원(H2.5) — 밑수가 갈림 →
|
|
미확정과 같은 급으로 보임(빨간 테두리·「규격 다름」 배지) · 금액은 섬 · 막지 않음.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from B05_Profile.B05_Profile_Structures_Schema import StructureInstance
|
|
from B08_Quantity.B08_Quantity_Engine_StmateRecipe import recipe_item
|
|
from B08_Quantity.B08_Quantity_Engine_StructureSheet import build_standard_sheets
|
|
from B08_Quantity.B08_Quantity_Engine_StructureTemplate import apply_templates
|
|
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import build_table
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
HOPYO = {
|
|
"no": 6,
|
|
"source_code": "B00010",
|
|
"name": "기슭막이(깬잡석,찰쌓기 L3=45m)",
|
|
"spec": "H=2.0m, 채집",
|
|
"unit": "M",
|
|
"basis": [],
|
|
"contract_rows": 0,
|
|
"rows": [
|
|
{
|
|
"name": "깬잡석찰쌓기",
|
|
"spec": "L3=45",
|
|
"amount": 2.09,
|
|
"unit": "M2",
|
|
"remark": "",
|
|
"source_code": "",
|
|
},
|
|
{
|
|
"name": "공구손료",
|
|
"spec": "노무비의 %",
|
|
"amount": 2,
|
|
"unit": "%",
|
|
"remark": "",
|
|
"source_code": "",
|
|
},
|
|
],
|
|
}
|
|
NAMES = {"masonry_wet": "돌쌓기(찰)"}
|
|
|
|
|
|
def _sheet(height: float) -> dict:
|
|
wall = StructureInstance.model_validate(
|
|
{
|
|
"structure_id": "a",
|
|
"type_id": "masonry_wet",
|
|
"placement": "interval",
|
|
"start_m": 0.0,
|
|
"end_m": 10.0,
|
|
"options": {"height_m": height, "foundation": "기초유"},
|
|
}
|
|
).model_dump()
|
|
templates = {
|
|
"masonry_wet": {
|
|
**recipe_item(HOPYO, type_id="masonry_wet", file_name="a", project="p"),
|
|
"code": "AX-ST-0000abcd",
|
|
}
|
|
}
|
|
table = build_table([wall], NAMES, {}, {}, None, structure_templates=templates)
|
|
payload = build_standard_sheets(table, {})
|
|
apply_templates(payload, {}, templates)
|
|
return payload["sheets"][0]
|
|
|
|
|
|
def test_고정형_장은_항목_사유를_띄우고_남의_사유를_걷는다() -> None:
|
|
notes = " / ".join(_sheet(2.0)["notes"])
|
|
assert "원문 시점 수량" in notes and "가산 행 1줄" in notes
|
|
assert "돌 종류를 안 골라" not in notes and "뒷채움 폭" not in notes
|
|
|
|
|
|
def test_규격이_다르면_미확정_급으로_밑수_갈림을_알린다() -> None:
|
|
sheet = _sheet(2.5)
|
|
mismatch = sheet["spec_mismatch"]
|
|
assert (mismatch["item_height_m"], mismatch["sheet_height_m"]) == (2.0, 2.5)
|
|
assert "규격 다름" in sheet["notes"][0]
|
|
assert "토공·사토 공제는 장 제원(H=2.5m)" in sheet["notes"][0]
|
|
assert any(row["amount"] for row in sheet["rows"]) # 금액·수량은 막지 않음
|
|
|
|
|
|
def test_규격이_같으면_아무것도_안_뜬다() -> None:
|
|
sheet = _sheet(2.0)
|
|
assert not sheet.get("spec_mismatch")
|
|
assert not any("규격 다름" in note for note in sheet["notes"])
|
|
|
|
|
|
def test_화면이_규격_다름을_빨간_배지로() -> None:
|
|
ui = (ROOT / "B08_Quantity" / "B08_Quantity_UI_StructureSheet.ts").read_text(encoding="utf-8")
|
|
assert "spec_mismatch" in ui and "규격 다름" in ui and "b08-unit__badge" in ui
|