Files
Aislo/resources/tester/test_144_b09_base_calc.py
T
eomsangdonandClaude Opus 5.5 5d8d9a4fd3 test(841-1): B09 = M02 값 — 산근 · 대가 · 고정 줄 셈 다듬기 · 낡은 시험 정리 — C 걸음
코드
- 고정 줄 단가 = M02_Labor_Fixed.line(사본 묶음 · 이은 노임 · 자재 = 묶음 값) — B09 단가 책으로 다시 안 덮음
- 대가 · 산근 고친 칸 = 품만 실제로(단가 칸 덮기 줄 남던 흠 · 품 고친 뒤 줄 금액 다시 셈 흠 py · ts 짝)
- 산근 글 = 엔진 단가 셈 그대로 · 별도계상 재료 줄 끝 「· 별도계상 = 0.0」 · 계 줄 = 블록 합
- 노무비 · 중기목록 이름에서 규격 겹침 뗌 · TS 바탕 셈 이름 PARTS → MACHINE_PARTS(짝 시험이 TS 를 이어 붙일 때 겹침)

시험(고친 까닭 = 단가 원천이 B09 책 → M02 엔진 · 노임 · 기계 덮개 · 단가 고친 칸 · 중기사용료 걷음)
- 144 바탕 · 뼈대: 운전사 · 중기사용료 · 경비 · 덮개 시험 걷음 → 노무 · 중기 나열 · 사급 표시 · 자재만 책
- 145-1 · 145-2 · 155 · 157-1 · 166-2 · 166-6 · 719-3 · 719-4 · 723-4 · 778-4 · 792-3: 줄 단가 = own(엔진) · 산근 = Solver() · collect 새 부름 꼴
- 702 · 705-1 · 719-2: 단가 칸 덮개 = 안 읽음 · 고정 줄 = M02 셈(노임 새 판 따라가기 시험 걷음)
- 203-1 · 296 · 703-3 · 795-4: 단가 책 = 자재 줄로
- 707 · 707-6 · 707-7: 단가표 불러오기 = 자재만 · 거창 이은 안내판 줄 = M02 사본 셈(엑셀 −50,000)
- 201-1: 환율 · 중기사용료 표 걷음 · b09 저장 속도: 산근 앞 풀이 그대로(단가 표 같음 견줌 걷음)
- 대상 113 파일 764 통과 · 25 실패 = 원래 실패(formatMoney · formatPrice 없음 · 단위 글 ㎜ · sec · 719-1 · 796-2e · 717-4 · 721 · 311 · 243 · 246)

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

124 lines
5.6 KiB
Python

"""144-2~4 B09 바탕 단가 셈 — 엑셀 검산 대조 · 거울(`B09_Estimation_Calc_Base.py` ↔ `.ts`).
견본 = 기번3 공통 엑셀(`2024년 간선임도사업(기번3).xlsx`) 자재단가대비표 5~12줄 같은 입력 ·
841-1 운전사 시간 노임 · 중기사용료 · 경비목록표 · 노임 · 기계 덮개 시험 걷음(B09 가 기계 시간당을
다시 셈하던 곳 · 값 = M02 단가산출 그대로) — 노무비 · 중기목록표 = 엔진 단가 나열만 봄.
"""
import json
import re
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from B09_Estimation.B09_Estimation_Calc_Base import ( # noqa: E402
compute_base,
round_half,
rounddown,
roundup,
)
IMPORTS = re.compile(r"^import[^;]*;\n", re.MULTILINE)
#: 841-1 노무비목록표 · 중기목록표 입력 = 대가 · 산근 줄 엔진 단가 나열(서버 `Supply.price_lists`)
LABOR = [
{"key": "LB000048", "name": "건설기계운전사", "spec": "", "unit": "인", "price": 267360},
{"key": "LB000002", "name": "보통인부", "spec": "", "unit": "인", "price": None},
]
MACHINES = [
{"key": "EQ000020", "name": "굴착기(무한궤도) 0.7㎥", "spec": "",
"labor": 1459, "material": 1077, "expense": 1012},
{"key": "EQ000001", "name": "빈 값", "spec": "", "labor": None, "material": 1, "expense": 1},
] # fmt: skip
def _mt(key, name, **prices):
return {"key": key, "name": name, "spec": "", "unit": "", "origin": "M01", "prices": prices}
MATERIALS = [
_mt("MO1", "휘발유", 관급=1369, 물가정보=0, 물가자료=0),
_mt("MO2", "경유", 관급=1272),
_mt("M3", "각재", 관급=500661, 물가정보=829341, 물가자료=748503),
_mt("M4", "못", 관급=1503, 물가정보=1935, 물가자료=1665),
_mt("M8", "화강석", 관급=0, 물가정보=288000, 물가자료=288000),
_mt("M9", "사용자 값 줄", 물가자료=1000),
_mt("b08:sand", "골재"),
]
INPUTS = {"labor": LABOR, "machines": MACHINES, "materials": MATERIALS}
USER = {"materials": {"M9": {"applied": 950, "supply": "관급"}, "M4": {"supply": "별도"},
"b08:sand": {"applied": None}}} # fmt: skip
def _run_ts(inputs, user):
calc = ROOT / "B09_Estimation" / "B09_Estimation_Calc_Base.ts"
body = (
f"\nconst i = {json.dumps(inputs, ensure_ascii=False)};"
f"\nconst u = {json.dumps(user, ensure_ascii=False)};"
"\nconsole.log(JSON.stringify(computeBase(i, u)));"
)
script = IMPORTS.sub("", calc.read_text(encoding="utf-8")) + body
result = subprocess.run(
["node", "--experimental-strip-types", "--no-warnings",
"--input-type=module-typescript", "-e", script],
capture_output=True, text=True, encoding="utf-8", timeout=60,
) # fmt: skip
assert result.returncode == 0, result.stderr
return json.loads(result.stdout)
def test_끝수_엑셀_자리():
assert rounddown(33412.7689, 1) == 33412.7 and rounddown(126000.9) == 126000
assert rounddown(-1.25, 1) == -1.2 # 0 쪽으로
assert roundup(69849380, -3) == 69850000 and roundup(69850000, -3) == 69850000
assert round_half(2.5) == 3 and round_half(0.125, 2) == 0.13 and round_half(-2.5) == -3
assert rounddown(0.1 + 0.2, 1) == 0.3 # 떠도는 끝수는 버리지 않음
def test_841_1_노무_중기목록_나열_걷은_표_빈():
s = compute_base(INPUTS, {})
assert [r["price"] for r in s["labor"]] == [267360, None]
assert ("labor", "LB000002") in {(g["tab"], g["key"]) for g in s["gaps"]}
got = {r["key"]: (r["sum"], r["labor"], r["material"], r["expense"]) for r in s["machine"]}
assert got == {"EQ000020": (3548, 1459, 1077, 1012), "EQ000001": (None, None, 1, 1)}
assert s["expense"] == [] and s["machine_blocks"] == [] # 경비목록표 · 중기사용료 걷음
assert s["basis"] == {"fx": [], "drivers": []} # 환율및기초자료(운전사 시간 노임) 걷음
def test_144_3_자재단가대비_최저_사용자_관급():
s = compute_base(INPUTS, USER)
rows = {r["key"]: r for r in s["compare"]}
# 엑셀 O 열 = 최저 · P 열 출처(0 은 뺌 · 같은 값이면 앞 칸 — 화강석 「물정」)
assert (rows["MO1"]["applied"], rows["MO1"]["applied_from"]) == (1369, "관급")
assert (rows["M3"]["applied"], rows["M3"]["lowest_from"]) == (500661, "관급")
assert rows["M4"]["applied"] == 1503 and rows["M4"]["supply"] == "별도"
assert (rows["M8"]["applied"], rows["M8"]["applied_from"]) == (288000, "물가정보")
assert (rows["M9"]["lowest"], rows["M9"]["applied"], rows["M9"]["applied_from"]) == (
1000,
950,
"사용자",
)
assert rows["M9"]["supply"] == "관급"
assert rows["b08:sand"]["applied"] is None # 출처 없음 · 사용자 빈칸 = 빈칸
material = {r["key"]: r["price"] for r in s["material"]}
assert material == {r["key"]: r["applied"] for r in s["compare"]} # 재료비목록표 = 적용 단가
gaps = [(g["tab"], g["key"]) for g in s["gaps"] if g["tab"] == "compare"]
assert gaps == [("compare", "b08:sand")]
def test_841_1_사급_표시_기본_끔():
rows = [{**MATERIALS[2], "supply": "별도"}] # M02 자재표시 기본 별도계상
s = compute_base({**INPUTS, "materials": rows}, {"materials": {"M3": {"supply": "사급"}}})
assert s["compare"][0]["supply"] is None
assert compute_base({**INPUTS, "materials": rows}, {})["compare"][0]["supply"] == "별도"
def test_거울_TS_가_같은_값():
for user in ({}, USER, {"materials": {"M3": {"supply": "사급"}}}):
assert _run_ts(INPUTS, user) == compute_base(INPUTS, user)