Merge remote-tracking branch 'origin/main_desktop_1' into sub_desktop_1
This commit is contained in:
@@ -61,8 +61,12 @@ def test_설계자_몫과_우리_몫을_가른다() -> None:
|
||||
|
||||
|
||||
def test_반쪽은_반쪽이라_적는다() -> None:
|
||||
"""⚠ 2026-09-09 밤 — 중기경비계산서를 세우면서 **반쪽이 하나 줄었다**(기종마다 한 장).
|
||||
|
||||
남은 반쪽은 산출기초 하나 — 근거 문구는 줄마다 있으나 한 장으로 묶는 자리가 없다.
|
||||
"""
|
||||
partial = {item["name"] for item in DESIGN_DOC_ITEMS if item["status"] == STATUS_PARTIAL}
|
||||
assert partial == {"각종 중기경비계산서", "산출기초"}
|
||||
assert partial == {"산출기초"}
|
||||
|
||||
|
||||
def test_서는_것은_어디서_나오는지_적혀_있다() -> None:
|
||||
@@ -80,7 +84,7 @@ def test_못_내는_것에는_무엇이_필요한지_적혀_있다() -> None:
|
||||
|
||||
def test_요약이_셈과_맞는다() -> None:
|
||||
data = design_doc_index()
|
||||
assert data["counts"][STATUS_READY] == 7
|
||||
assert data["counts"][STATUS_READY] == 8
|
||||
assert sum(data["counts"].values()) == len(DESIGN_DOC_ITEMS)
|
||||
ours_missing = [
|
||||
item["name"]
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
"""각종 중기경비계산서 — 기종마다 한 장 (2026-09-09).
|
||||
|
||||
별표2 (5)(가) 가 설계서에 「각종 중기경비계산서」를 넣으라 한다. 중기목록표는 「얼마」 한 줄
|
||||
이고, 이 장은 **그 값이 나온 과정**이다.
|
||||
|
||||
⚠ 겨누는 것 다섯
|
||||
① **내역에 선 기종만** 낸다 — 카탈로그 613 을 다 뿌리지 않는다
|
||||
② 손료 = 취득가(천원) × 1,000 × 계수 — 천원 단위를 놓치면 1,000배 틀린다
|
||||
③ 계산서의 시간당 합계가 **일위대가가 실제로 쓰는 값과 같다**(두 벌이면 안 된다)
|
||||
④ 부착 장비(브레이커·콤팩터·집게)는 **손료만 드는 것이 정상** — 결함으로 세지 않는다
|
||||
⑤ 수송비는 이 장에 안 붙는다 — 「회당」으로 서는 별개 공종이라 자리만 가리킨다
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from decimal import Decimal
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from B09_Estimation.B09_Estimation_MachineExpenseSheet import ( # noqa: E402
|
||||
machine_expense_report,
|
||||
)
|
||||
from B09_Estimation.B09_Estimation_PriceBook import PriceKind # noqa: E402
|
||||
from B09_Estimation.B09_Estimation_UnitPrice import cached_build # noqa: E402
|
||||
|
||||
|
||||
def _report():
|
||||
return machine_expense_report(cached_build())
|
||||
|
||||
|
||||
def test_내역에_선_기종만_낸다() -> None:
|
||||
build = cached_build()
|
||||
hourly = {c for c, t in build.book.titles.items() if t.kind is PriceKind.MACHINE_HOURLY}
|
||||
sheets = _report()["sheets"]
|
||||
assert sheets, "계산서가 한 장도 없습니다"
|
||||
assert len(sheets) <= len(hourly)
|
||||
assert {sheet["code"] for sheet in sheets} <= hourly
|
||||
|
||||
|
||||
def test_손료가_취득가와_계수로_맞는다() -> None:
|
||||
"""② 천원 단위를 놓치면 1,000배 틀린다."""
|
||||
for sheet in _report()["sheets"]:
|
||||
if sheet["loss_krw_per_hour"] is None or sheet["loss_coefficient"] is None:
|
||||
continue
|
||||
price = Decimal(sheet["price_thousand_krw"]) * Decimal(1000)
|
||||
coefficient = Decimal(sheet["loss_coefficient"]) / Decimal(10**7)
|
||||
assert abs(Decimal(sheet["loss_krw_per_hour"]) - price * coefficient) < Decimal("0.01")
|
||||
|
||||
|
||||
def test_계산서_합계가_일위대가와_같은_값이다() -> None:
|
||||
"""③ 두 벌로 세면 화면과 금액이 어긋난다."""
|
||||
build = cached_build()
|
||||
for sheet in machine_expense_report(build)["sheets"]:
|
||||
used = build.book.resolve(sheet["code"]).total
|
||||
assert Decimal(sheet["total_krw"]) == used, sheet["code"]
|
||||
|
||||
|
||||
def test_부착_장비는_결함이_아니다() -> None:
|
||||
"""④ 제 엔진이 없어 연료·조종원이 본체에 든다(품셈 제8장 [주]⑤)."""
|
||||
sheets = _report()["sheets"]
|
||||
attachments = [sheet for sheet in sheets if sheet["attachment"]]
|
||||
assert attachments, "부착 장비가 한 대도 안 잡혔습니다"
|
||||
for sheet in attachments:
|
||||
assert sheet["gaps"] == []
|
||||
assert sheet["attachment_note"]
|
||||
assert sheet["loss_krw_per_hour"] is not None # 손료는 있어야 한다
|
||||
|
||||
|
||||
def test_수송비는_이_장에_안_붙는다() -> None:
|
||||
"""⑤ 「회당」으로 서는 별개 공종이라 자리만 가리킨다."""
|
||||
report = _report()
|
||||
assert any("수송비" in line and "회당" in line for line in report["notes"])
|
||||
for sheet in report["sheets"]:
|
||||
assert "transport" not in sheet
|
||||
Reference in New Issue
Block a user