"""초류종자살포 5-24-1·2 뿜어붙이기 — 2026-09-15 브레인 판정 ①②′④ (③ 물탱크는 `test_b09_water_tank_operating`). 산림 5-24 표(㎡당): 종자 0.025 · 복합비료 0.1 · 화이버 0.18 · 합성접착제 0.1 · 색소 0.002 kg · 종자살포기 2,500-3,000ℓ 0.0024h · 트럭 4.5ton 0.0024h · 물탱크 5,500ℓ 0.0036h · 조경공 0.0007 · 보통인부 0.0004 [주]⑤ 「건설공사 표준품셈 공통부문 4-1-2 초류종자 살포」 참조 ① 트럭 4.5ton → 덤프트럭 4.5(0602-0045) — 카탈로그에 「트럭」 없음(원문 애매) · 거창 실무 「덤프트럭 (4.5Ton)」 ②′ 종자살포기 → 취부기 11.94㎾(7750-0016) · **손료만** — 원문 규격은 ℓ(탱크 용량) · 건설 4-1-3 「취부기 11.94kW」 · 거창 실무 「종자살포기 : 취부기(녹생토)」 · 8-4 운전경비표에 7750 줄 없음(원문 없음) · 거창도 손료 20,295 만 디젤엔진 11.19㎾ 는 거창만 따로 세움 — 산림 5-24 · 건설 4-1-3 표 둘 다에 없어 안 넣고 어긋남만 기록 ④ 종자 규격 후보 넷(생태복원형 초본·목본 · 초본류 · 목본류) — 화약류 길: 「자재 단가」 칸 · 넣은 쪽 하나가 붙음 """ from __future__ import annotations from decimal import ROUND_FLOOR, Decimal from B09_Estimation.B09_Estimation_KnownGaps import known_gap_note from B09_Estimation.B09_Estimation_MachineExpenseSheet import machine_expense_sheets from B09_Estimation.B09_Estimation_UnitPrice import cached_build CODES = ("FP-05-24-01", "FP-05-24-02") SEEDS = ("AR-M-f89c57d4", "AR-M-d52b8fc1", "AR-M-8f852514", "AR-M-e39ee36e") def _rows(book, code: str) -> dict[str, Decimal]: return {r.ref_code: r.quantity for r in book.details[f"B-{code}"]} def test_트럭은_덤프트럭_종자살포기는_취부기_물탱크까지_표_시간대로() -> None: build = cached_build() for code in CODES: rows = _rows(build.book, code) assert rows["X-0602-0045"] == Decimal("0.0024"), rows assert rows["X-7750-0016"] == Decimal("0.0024"), rows assert rows["X-7204-0055"] == Decimal("0.0036"), rows left = " ".join(build.unattached.get(code, [])) assert "트 럭" not in left and "종자살포기" not in left, left assert code not in build.component_gaps, build.component_gaps.get(code) def test_취부기는_손료만으로_서고_사유가_붙음() -> None: build = cached_build() assert not any(m.startswith("7750-0016") for m in build.incomplete_machines) money = build.book.resolve("X-7750-0016") assert money.material == 0 and money.labor == 0 assert ( money.expense.quantize(Decimal(1), rounding=ROUND_FLOOR) == 20295 ) # 거창 46,603,000 × 4,355 notes = " ".join(r.note for r in build.book.details["X-7750-0016"]) assert "8-4" in notes and "거창" in notes, notes sheet = next(s for s in machine_expense_sheets(build) if s["code"] == "X-7750-0016") assert sheet["gaps"] == [] and "8-4" in sheet["attachment_note"], sheet def test_종자는_후보_넷_칸_넣은_하나만_붙고_둘이면_사유() -> None: none = cached_build() for code in CODES: assert all(code in none.material_uses.get(seed, []) for seed in SEEDS) left = " ".join(none.unattached.get(code, [])) assert "종자 — 규격 미정" in left and "종 자" not in left, left one = cached_build(material_prices=(("AR-M-8f852514", "20000", "견적"),)) assert _rows(one.book, "FP-05-24-01")["AR-M-8f852514"] == Decimal("0.025") assert "종자" not in " ".join(one.unattached.get("FP-05-24-01", [])) two = cached_build( material_prices=(("AR-M-8f852514", "20000", "견적"), ("AR-M-e39ee36e", "30000", "견적")) ) rows = _rows(two.book, "FP-05-24-01") assert "AR-M-8f852514" not in rows and "AR-M-e39ee36e" not in rows assert "하나만" in " ".join(two.unattached.get("FP-05-24-01", [])) def test_사유는_어긋남을_나란히() -> None: note = known_gap_note("FP-05-24-01") for word in ("트럭", "덤프트럭", "ℓ", "취부기", "손료만", "디젤엔진"): assert word in note, (word, note) assert known_gap_note("FP-05-24-02") == note