fix(b09): 내역 수량을 1-2-2 자리로 반올림해 확정한 뒤 금액(버림) — 표에 없는 종목 기본 2자리 · 철근 ton 소수 3자리(kg 정수 환산) · 단위 대소문자 흡수 · STmate 원본 수량 321줄 대조 시험
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
This commit is contained in:
@@ -109,8 +109,9 @@ def test_사급_자재총괄_줄은_본체_자재_줄로_서고_관급은_수량
|
||||
group = next(r for r in result.rows if r.name == "자재(사급)")
|
||||
rows = [r for r in result.rows if r.item_no.startswith(f"{group.item_no}-")]
|
||||
assert [(r.name, r.spec) for r in rows] == [("각재", "50×50")] # 판재 단가 없음 · 관급 안 올림
|
||||
assert rows[0].material_krw == Decimal("174460") # 0.2684 × 650,000
|
||||
assert rows[0].unconfirmed == 1 and result.direct_material_krw == Decimal("174460")
|
||||
# 수량을 1-2-2 자리(㎥ 2자리)로 반올림해 확정한 뒤 곱함 — 0.2684 → 0.27 × 650,000
|
||||
assert rows[0].quantity == Decimal("0.27") and rows[0].material_krw == Decimal("175500")
|
||||
assert rows[0].unconfirmed == 1 and result.direct_material_krw == Decimal("175500")
|
||||
assert any(m["name"] == "판재 T12" and "단가 없음" in m["reason"] for m in result.missing)
|
||||
sheet = result.material_sheet
|
||||
assert (
|
||||
@@ -162,3 +163,27 @@ def test_목록은_자원_축_자재와_사라진_저장_줄() -> None:
|
||||
"material_sheet",
|
||||
)
|
||||
assert sheet_row["supply_type"] == "contractor_supplied" and rows["못"]["missing"] is True
|
||||
|
||||
|
||||
def test_내역_수량은_자리로_반올림해_확정한_뒤_금액은_버림() -> None:
|
||||
"""1-2-2 [주]① 수량 반올림 → 금액 버림 — 둘을 섞지 않음(2026-09-14 브레인 판정).
|
||||
|
||||
인계 전정밀 0.28181999…96 로 곱하면 183,182 원(1원 샘) — 확정 수량 0.28 × 650,000 = 182,000.
|
||||
"""
|
||||
from B09_Estimation.B09_Estimation_BillOfQuantities import build_bill
|
||||
from B09_Estimation.B09_Estimation_QuantityDigits import digits_for
|
||||
|
||||
payload = {
|
||||
"work_items": [],
|
||||
"materials": [
|
||||
_자재("각재", "50×50", "0.28181999999999996", "contractor_supplied", ["비탈 규준틀"])
|
||||
],
|
||||
}
|
||||
result = build_bill(
|
||||
payload, build=cached_build(), material_prices={"각재 50×50": {"price_krw": "650000"}}
|
||||
)
|
||||
row = next(r for r in result.rows if r.name == "각재")
|
||||
assert (row.quantity, row.amount_krw) == (Decimal("0.28"), Decimal("182000"))
|
||||
assert row.as_dict()["quantity"] == "0.28" # 계약·기성이 읽는 수량도 확정값
|
||||
assert digits_for("낯선종목", "개") == 2 # 표에 없는 종목은 우리 기본 2자리
|
||||
assert digits_for("돌쌓기(찰)", "㎡") == 1 and digits_for("철근", "kg") == 0
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
"""수량 자리 맞춤 골든 대조 — STmate 실무 원본 내역 수량이 우리 자리 규칙으로 **안 바뀌어야** 함.
|
||||
|
||||
2026-09-14 브레인 판정 — 내역 수량은 1-2-2 자리로 반올림해 확정한 뒤 금액(버림). 골든 금액 시험
|
||||
(`test_b09_golden_stmate`)은 원본 수량을 `bill_line` 에 바로 넣어 이 길을 안 거치므로, 원본 수량
|
||||
자체로 자리 규칙을 따로 잰다(321줄 · 철근 ton 소수 3자리가 이 대조에서 드러남).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from test_b09_golden_stmate import _bill_rows, _num
|
||||
|
||||
from B09_Estimation.B09_Estimation_QuantityDigits import round_quantity
|
||||
|
||||
|
||||
def test_실무_원본_내역_수량이_자리_규칙으로_안_바뀐다() -> None:
|
||||
rows = _bill_rows()
|
||||
if not rows:
|
||||
pytest.skip("실무 원본 XLSX 가 없음")
|
||||
changed = []
|
||||
for name, row in rows:
|
||||
quantity, unit = _num(row[3]), str(row[4] or "").strip()
|
||||
if quantity is None or unit == "%":
|
||||
continue
|
||||
settled, digits = round_quantity(quantity, str(row[1] or ""), unit, str(row[2] or ""))
|
||||
if settled != quantity:
|
||||
changed.append((name, row[1], unit, str(quantity), digits))
|
||||
assert len(rows) >= 300, len(rows)
|
||||
assert not changed, (len(changed), changed[:5])
|
||||
Reference in New Issue
Block a user