fix(b09): 구조물도 호표 내역 단가를 호표 계금으로 — 화면과 1원 갈림 없앰

- 내역 단가 = 구조물도 일위대가 표 계금(성분 칸 0.1원 절사 합의 1원 절사), 금액 = 성분 소계 × 연장
- 명세 7장 「호표 안 성분 소계는 절사」 — 안 자른 값을 쓰면 192,429 ↔ 192,430 으로 갈렸음

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
This commit is contained in:
2026-09-13 22:35:41 +09:00
co-authored by Claude Opus 5
parent d1958d067b
commit 41e0b5b7ea
3 changed files with 26 additions and 9 deletions
@@ -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": [
@@ -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
@@ -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