From 41e0b5b7ea64847a9cce5750eed9119a3b984558 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 13 Sep 2026 22:35:41 +0900 Subject: [PATCH] =?UTF-8?q?fix(b09):=20=EA=B5=AC=EC=A1=B0=EB=AC=BC?= =?UTF-8?q?=EB=8F=84=20=ED=98=B8=ED=91=9C=20=EB=82=B4=EC=97=AD=20=EB=8B=A8?= =?UTF-8?q?=EA=B0=80=EB=A5=BC=20=ED=98=B8=ED=91=9C=20=EA=B3=84=EA=B8=88?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=E2=80=94=20=ED=99=94=EB=A9=B4=EA=B3=BC=20?= =?UTF-8?q?1=EC=9B=90=20=EA=B0=88=EB=A6=BC=20=EC=97=86=EC=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 내역 단가 = 구조물도 일위대가 표 계금(성분 칸 0.1원 절사 합의 1원 절사), 금액 = 성분 소계 × 연장 - 명세 7장 「호표 안 성분 소계는 절사」 — 안 자른 값을 쓰면 192,429 ↔ 192,430 으로 갈렸음 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq --- .../B08_Quantity_Engine_StructurePriceLink.py | 14 ++++++++++---- .../B09_Estimation_BillOfQuantities_Rows.py | 6 +++--- resources/tester/test_b09_structure_price_link.py | 15 +++++++++++++-- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/B08_Quantity/B08_Quantity_Engine_StructurePriceLink.py b/B08_Quantity/B08_Quantity_Engine_StructurePriceLink.py index 6f7aaede..af6fc4f6 100644 --- a/B08_Quantity/B08_Quantity_Engine_StructurePriceLink.py +++ b/B08_Quantity/B08_Quantity_Engine_StructurePriceLink.py @@ -130,11 +130,16 @@ def price_sheets( library: Iterable[dict[str, Any]], manual_all: dict[str, Any] | None = None, ) -> dict[str, dict[str, Any]]: - """B09 내역이 쓸 호표 금액 `{B-AX-ST-…#키: {money, blocked, unconfirmed, reasons}}`. + """B09 내역이 쓸 호표 금액 `{B-AX-ST-…#키: {money, total, blocked, unconfirmed, reasons}}`. - `money` 는 **안 자른** 단위(m)당 3분할 — 자르기는 내역 줄 자리 규칙(B09)이 함. + ⚠ `money` 는 **호표 표의 성분 소계**(칸마다 0.1원 절사한 합) · `total` 은 계금(1원 절사) — + 명세 7장 「호표 안 성분 소계는 절사」. 안 자른 값을 쓰면 구조물도 화면(192,429)과 + 내역 단가(192,430)가 1원 갈림(2026-09-13 검증 프로젝트 실측). """ + from decimal import Decimal + from B08_Quantity.B08_Quantity_Engine_StructureUnitPrice import unit_price_money + from B09_Estimation.B09_Estimation_PriceBook import Money3 prices: dict[str, dict[str, Any]] = {} library = list(library) @@ -149,9 +154,10 @@ def price_sheets( ) if assembled is None: continue - table, money = assembled + table, _exact = assembled prices[structure_price_code(entry["code"], entry["key"])] = { - "money": money, + "money": Money3(*(Decimal(str(table[k])) for k in ("material", "labor", "expense"))), + "total": Decimal(str(table["total"])), "blocked": table["blocked"], "unconfirmed": table["unconfirmed"], "reasons": [ diff --git a/B09_Estimation/B09_Estimation_BillOfQuantities_Rows.py b/B09_Estimation/B09_Estimation_BillOfQuantities_Rows.py index 582aa524..b61f2f95 100644 --- a/B09_Estimation/B09_Estimation_BillOfQuantities_Rows.py +++ b/B09_Estimation/B09_Estimation_BillOfQuantities_Rows.py @@ -140,9 +140,9 @@ def _structure_price_row( ) return row - money = entry["money"] - line = money.scaled(item.quantity) - row.unit_price_krw = round_at(money.total, OutputPlace.UNIT_PRICE_ROW) + # 단가 = 호표 계금(구조물도 화면과 같은 값) · 금액 = 호표 성분 소계 × 수량(명세 7장). + line = entry["money"].scaled(item.quantity) + row.unit_price_krw = entry["total"] row.amount_krw = round_at(line.total, OutputPlace.BOQ_ROW) row.material_krw = line.material row.labor_krw = line.labor diff --git a/resources/tester/test_b09_structure_price_link.py b/resources/tester/test_b09_structure_price_link.py index bbeb6dde..75b83906 100644 --- a/resources/tester/test_b09_structure_price_link.py +++ b/resources/tester/test_b09_structure_price_link.py @@ -104,8 +104,19 @@ def test_내역은_호표_금액에_연장을_곱한다() -> None: row = next(r for r in bill.rows if r.code == entries[0]["code"]) # 모르터 공종 코드가 선 뒤(랩탑 메인 AX-WK) 찰쌓기 호표 세 줄이 다 섬. assert not entry["blocked"], entry["reasons"] - assert row.unit_price_krw == round_at(entry["money"].total, OutputPlace.UNIT_PRICE_ROW) - assert row.amount_krw == round_at(entry["money"].scaled(Decimal(10)).total, OutputPlace.BOQ_ROW) + # 단가 = 구조물도 일위대가 표 계금 그대로(화면과 한 값) · 금액 = 성분 소계 × 연장. + from B08_Quantity.B08_Quantity_Engine_StructureUnitPrice import unit_price_table + + table = unit_price_table( + entries[0]["template"], + entries[0]["sheet"], + _build().book, + lambda code, value: find_variant_code(code, value, _build()), + [load_template("masonry_wet")], + ) + assert row.unit_price_krw == Decimal(str(table["total"])) + cells = sum(Decimal(str(table[k])) for k in ("material", "labor", "expense")) + assert row.amount_krw == round_at(cells * Decimal(10), OutputPlace.BOQ_ROW) assert row.quantity == Decimal(10) and f"호표 {ref}" in row.note