diff --git a/B08_Quantity/B08_Quantity_Engine_ObservedUnit.py b/B08_Quantity/B08_Quantity_Engine_ObservedUnit.py index a29c376f..aab337de 100644 --- a/B08_Quantity/B08_Quantity_Engine_ObservedUnit.py +++ b/B08_Quantity/B08_Quantity_Engine_ObservedUnit.py @@ -283,8 +283,16 @@ def expand_observed( source_key = str(found.get("source") or "") options = structure.get("options") or {} components: list[dict[str, Any]] = [] + blocked: list[str] = [] for item in found.get("components") or []: note = str(item.get("basis_note") or "") + if not item.get("destination"): + # ⛔ 갈 곳 기본값 금지(명세 13장) — 종전 `or "material"` 은 줄이 늘 때 조용히 자재로 샘. + blocked.append( + f"「{item['name']}」 관측 원단위 줄에 갈 곳이 없어 물량을 어느 축에도 안 보냄" + " — 표(`structure_unit_observed`)에 적을 것(명세 13장 갈 곳 기본값 금지)" + ) + continue weep = ( weep_component(found, options, scale, scale_note) if item["name"] == "물구멍관" @@ -298,7 +306,7 @@ def expand_observed( "name": item["name"], "unit": item["unit"], "amount": float(item["amount"]) * scale, - "destination": item.get("destination") or "material", + "destination": item["destination"], # 근거를 값 옆에 붙인다 — 관측값임을 화면·인계에서 바로 알아야 한다. "basis": f"관측 원단위 {item['amount']:g}/{found.get('unit')} × {scale_note}" + (f" ({note})" if note else ""), @@ -308,7 +316,7 @@ def expand_observed( "spec": str(item.get("spec") or ""), } ) - notes = [f"관측 원단위 적용 — {found.get('source_note') or source_key}"] + notes = [f"관측 원단위 적용 — {found.get('source_note') or source_key}", *blocked] # 줄에 붙은 사유(원문끼리 다름 등) — 구조물도 그림도 같은 글자를 씀. notes.extend(str(note) for note in found.get("notes") or []) earthwork_note = earthwork_missing_note(found) diff --git a/resources/tester/test_b08_destination_no_default.py b/resources/tester/test_b08_destination_no_default.py index e604b41a..67c4cd1c 100644 --- a/resources/tester/test_b08_destination_no_default.py +++ b/resources/tester/test_b08_destination_no_default.py @@ -53,3 +53,36 @@ def test_드러난_넷이_제자리로_감() -> None: sod, sod_notes = soil_guard({"form": "떼"}) assert {c.name: c.destination for c in sod}["떼"] == "material" assert not [note for note in sod_notes if "갈 곳이 표" in note] + + +def test_관측_원단위_줄도_갈_곳이_없으면_막히고_사유() -> None: + """관측 원단위 로더의 `destination or "material"` 도 같은 병 — 줄이 늘 때 바로 드러나게.""" + from B08_Quantity.B08_Quantity_Engine_ObservedUnit import ObservedUnitTable, expand_observed + + table = ObservedUnitTable( + entries=[ + { + "type_id": "시험구조물", + "unit": "개소", + "components": [ + {"name": "콘크리트", "unit": "㎥", "amount": 1.0, "destination": "unit_price"}, + {"name": "새자재", "unit": "㎥", "amount": 2.0}, + ], + } + ] + ) + components, notes = expand_observed("시험구조물", {}, {"options": {}}, table) + assert [c["name"] for c in components] == ["콘크리트"] + assert any("새자재" in note and "기본값 금지" in note for note in notes) + + +def test_관측_원단위_표의_전_줄에_갈_곳이_있음() -> None: + from B08_Quantity.B08_Quantity_Engine_ObservedUnit import load_observed_table + + missing = [ + (entry.get("type_id"), item.get("name")) + for entry in load_observed_table().entries + for item in entry.get("components") or [] + if not item.get("destination") + ] + assert missing == []