Files
Aislo/resources/tester/test_714_1_sheet_line.py
T
eomsangdonandClaude Opus 5.5 8c519c0ab2 feat(714-1b): 장비 줄 펼침 덧칸 — 부른 기계경비 로직 계산서 줄 · 시간당 소계 · 계 · 키 · 인자
- master_sheet_line 장비(기계경비) 줄에 「펼침」 = {키, 이름, 단위, 입력, 줄[비목 · 이름 · 글 · 금액], 소계, 계} · 못 셈 = 까닭
- 셈 결과(master_text.lines)를 그대로 실음 — 조종원 환산 같은 규칙을 여기 두지 않음
- annotate 가 files 를 받음(펼침 계산서) · M01 /text · M02 /logic-lib/sheet 같은 KEYS
- 시험 test_714_1_sheet_line 펼침 · 두 길 같은 수(JSON 수 규칙)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 16:32:57 +09:00

76 lines
3.3 KiB
Python

"""714-1 지킴 — 계산서 줄 덧칸(쓰는 입력 · 묶음 · 기준단위 · 환산 근거) · M01 `/text` 와
M02 `/logic-lib/sheet` 가 같은 줄 꼴(`master_sheet_line`)."""
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
from M01_MasterData import M01_MasterData_Store as store # noqa: E402
from M01_MasterData import M01_MasterData_Store_Sheet as sheet # noqa: E402
from M02_MasterTemplete import M02_Logic_Standard as standard # noqa: E402
msl = sheet.msl
num = standard.labor_inputs._num # Decimal → JSON 수(두 길 같은 규칙)
def _text(key: str) -> dict:
auto = {k: v for k, v in store.auto(key)["값"].items() if v is not None}
return sheet.text(key, auto)
def _lines(got: dict, groups: str = "groups") -> list[dict]:
return [line for g in got[groups] for line in g["줄"]]
def test_line_keys_and_bundle():
got = _text("GF000103") # 구조물터파기 — 인력 + 굴착기 기계경비 줄
assert got["ok"] and got["기준단위"] == "㎥"
lines = _lines(got)
assert all({"쓰는입력", "묶음", "기준단위", "환산근거"} <= set(line) for line in lines)
machine = [line for line in lines if line.get("장비")]
assert machine and all(line["묶음"] == "경비" for line in machine)
assert {"지역", "보정작업"} <= set(machine[0]["쓰는입력"])
assert any(line["묶음"] == "인력" for line in lines)
def test_machine_spread():
"""714-1b — 장비 줄 「펼침」 = 부른 기계경비 로직 계산서(조종원 · 연료 · 손료) · 시간당 계."""
lines = _lines(_text("GF000103"))
spread = next(line for line in lines if line.get("장비"))["펼침"]
assert spread["키"].startswith("GC0002") and spread["단위"] == "시간"
names = " ".join(one["이름"] for one in spread["줄"])
assert "조종원" in names and "손료" in names
sums = [v for v in spread["소계"].values() if v is not None]
assert spread["계"] == sum(sums) and spread["계"] > 0
assert not any(line.get("펼침") for line in lines if not line.get("장비"))
def test_uses_follow_middle_values():
"""중간값을 거슬러 입력까지 — 돌쌓기 석공 품은 높이 · 쌓기 · 돌 입력을 씀."""
lines = _lines(_text("GF000219"))
assert {"높이", "쌓기", "돌"} <= set(lines[0]["쓰는입력"])
def test_basis_note_tenfold():
"""표 10㎡당 → 결과 원/㎡ 「÷10」 · 결과도 원/10㎡ 면 근거 없음."""
one = _lines(_text("GC000037"))
assert one[0]["기준단위"] == "10㎡" and one[0]["환산근거"] == "10㎡당 → 1㎡당 ÷10"
ten = _text("GF000124")
assert ten["기준단위"] == "10㎡" and all(not x["환산근거"] for x in _lines(ten))
def test_two_routes_same_shape():
"""M01 `/text` 와 M02 계산서 — 줄 차례 · 덧칸 값이 같음(금액 끝수만 다를 수 있음)."""
for key in ("GF000169", "GF000103", "GF000219"):
m01 = _lines(_text(key))
m02 = _lines(standard.sheet(key, {}), "묶음")
assert len(m01) == len(m02)
for a, b in zip(m01, m02):
assert set(b) == {"이름", "글", "금액", *msl.KEYS}
assert a["이름"] == b["이름"]
assert num([a.get(k) for k in msl.KEYS]) == [b.get(k) for k in msl.KEYS]