93 lines
4.0 KiB
Python
93 lines
4.0 KiB
Python
"""자재 수동 단가(PLAN 1장 Ⓐ · 2026-09-14 브레인 판정).
|
||
|
||
지키는 것
|
||
① 키 = 코드(`AR-M-…`) · 코드 없는 자재만 「이름 규격」 — 조립엔 코드 키만 얹음
|
||
② 0 이하·수 아님은 안 받음 · 비우면 지움 · 값·출처가 같으면 넣은 날 그대로
|
||
③ 넣으면 자재 제목(6번 슬롯)이 서고 자원 축 자재 줄이 붙어 재료비가 섬 — 안 넣으면 종전 벌 그대로
|
||
④ 수동 단가가 닿은 내역 줄 = 금액은 서되 「미확정 N건」
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import sys
|
||
from decimal import Decimal
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
sys.path.insert(0, str(ROOT))
|
||
|
||
from B09_Estimation.B09_Estimation_MaterialPrices import ( # noqa: E402
|
||
MaterialPriceError,
|
||
build_key,
|
||
listing,
|
||
merge,
|
||
)
|
||
from B09_Estimation.B09_Estimation_UnitPrice import cached_build # noqa: E402
|
||
|
||
STAKE = "AR-M-dce99e46" # 말뚝 직경4~6㎝ — FP-05-15 에 2개/단위
|
||
|
||
|
||
def test_키와_넣은_날() -> None:
|
||
first = merge({}, [{"key": STAKE, "price_krw": "1,500", "source": "견적 A"}], "2026-09-14")
|
||
assert first[STAKE]["price_krw"] == "1500" and first[STAKE]["entered_at"] == "2026-09-14"
|
||
same = merge(first, [{"key": STAKE, "price_krw": "1500", "source": "견적 A"}], "2026-09-20")
|
||
assert same[STAKE]["entered_at"] == "2026-09-14" # 다시 저장해도 안 바뀜
|
||
moved = merge(first, [{"key": STAKE, "price_krw": "1600", "source": "견적 A"}], "2026-09-20")
|
||
assert moved[STAKE]["entered_at"] == "2026-09-20"
|
||
assert merge(first, [{"key": STAKE, "price_krw": ""}], "2026-09-20") == {}
|
||
for bad in ("0", "-3", "abc"):
|
||
with pytest.raises(MaterialPriceError):
|
||
merge({}, [{"key": STAKE, "price_krw": bad}], "2026-09-14")
|
||
named = merge(first, [{"key": "각재 50×50", "price_krw": "900000"}], "2026-09-14")
|
||
assert build_key(named) == ((STAKE, "1500", "견적 A"),) # 이름 키는 조립에 안 얹음
|
||
|
||
|
||
def test_넣으면_재료비가_서고_안_넣으면_종전_그대로() -> None:
|
||
base = cached_build()
|
||
assert base.book.resolve("B-FP-05-15").material == 0
|
||
assert STAKE not in base.book.titles and not base.manual_materials
|
||
built = cached_build(material_prices=((STAKE, "1500", "견적 A"),))
|
||
title = built.book.titles[STAKE]
|
||
assert (title.slots[5], title.slot_pages[5], title.unit) == (Decimal("1500"), "견적 A", "개")
|
||
assert built.book.resolve("B-FP-05-15").material == Decimal("3000") # 2개 × 1,500
|
||
assert built.book.resolve("B-FP-05-15").labor == base.book.resolve("B-FP-05-15").labor
|
||
assert "FP-05-15" in built.material_uses[STAKE]
|
||
|
||
|
||
def test_내역_줄은_미확정으로_선다() -> None:
|
||
from B09_Estimation.B09_Estimation_BillOfQuantities import build_bill
|
||
|
||
built = cached_build(material_prices=((STAKE, "1500", "견적 A"),))
|
||
payload = {
|
||
"work_items": [
|
||
{
|
||
"work_item_code": "FP-05-15",
|
||
"name": "말뚝박기",
|
||
"unit": built.book.titles["B-FP-05-15"].unit,
|
||
"quantity": 10,
|
||
"in_bill": True,
|
||
}
|
||
],
|
||
"materials": [],
|
||
}
|
||
row = next(r for r in build_bill(payload, build=built).rows if r.name == "말뚝박기")
|
||
assert row.material_krw == Decimal("30000") and row.unconfirmed == 1
|
||
result = build_bill(payload, build=built)
|
||
assert result.unconfirmed == [{"name": "말뚝박기", "code": "B-FP-05-15", "count": 1}]
|
||
plain = build_bill(payload, build=cached_build())
|
||
assert not plain.unconfirmed
|
||
|
||
|
||
def test_목록은_자원_축_자재와_사라진_저장_줄() -> None:
|
||
built = cached_build()
|
||
stored = {
|
||
STAKE: {"price_krw": "1500"},
|
||
"AR-M-00000000": {"price_krw": "7", "name": "옛 자재"},
|
||
}
|
||
rows = {row["key"]: row for row in listing(built, stored)}
|
||
assert rows[STAKE]["name"] == "말뚝" and rows[STAKE]["price_krw"] == "1500"
|
||
assert rows["AR-M-00000000"]["missing"] is True # 조용히 안 버림
|
||
assert rows["AR-M-b0853497"]["price_krw"] is None
|