Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1
This commit is contained in:
@@ -124,6 +124,7 @@ def test_엑셀_대가_블록_검산():
|
||||
assert out["daega"][0] == {
|
||||
"no": 1, "key": "DG14", "kind": "조합", "name": "돌붙임(채집)", "spec": "", "unit": "",
|
||||
"sum": 101522, "labor": 77755, "material": 9519, "expense": 14248,
|
||||
"blank": 0, "blank_names": [],
|
||||
} # fmt: skip
|
||||
assert daega_price(out, "pipe@100.0") == {
|
||||
"no": "대가1",
|
||||
@@ -147,11 +148,19 @@ def _blank_cases():
|
||||
|
||||
|
||||
def test_빈칸_규칙():
|
||||
"""166-6 — 블록 합 = 아는 줄 합 + 빈 줄 n · 내역 단가는 빈칸."""
|
||||
out = compute_labor(_blank_cases(), SHEETS, {})
|
||||
assert _block(out, "DG2")["sum"] is None and _block(out, "DG2")["labor"] is None
|
||||
assert _block(out, "DG14")["sum"] is None # 산근 단가 없음(145-1 전)
|
||||
assert _block(out, "DGZ")["sum"] is None
|
||||
assert _block(out, "DGX")["sum"] is None or _block(out, "DGY")["sum"] is None # 순환 = 빈칸
|
||||
dg2 = _block(out, "DG2")
|
||||
assert (dg2["sum"], dg2["labor"], dg2["blank"]) == (6013, 5275, 2)
|
||||
assert dg2["blank_names"] == ["L00032", "공구손료"] # 노임 없음 · 그 노무 밑수 % 줄
|
||||
dg14 = _block(out, "DG14") # 산근 단가 없음(145-1 전)
|
||||
assert (dg14["sum"], dg14["blank"]) == (53926, 3)
|
||||
assert _sums(dg14) == (53926, 43539, 3842, 6545)
|
||||
assert (_block(out, "DGZ")["sum"], _block(out, "DGZ")["blank"]) == (0, 1)
|
||||
assert _block(out, "DGX")["blank"] + _block(out, "DGY")["blank"] >= 1 # 순환 = 빈 줄
|
||||
assert daega_price(out, "pipe@100.0") == {
|
||||
"no": "대가1", "key": "DG14", "labor": None, "material": None, "expense": None, "sum": None,
|
||||
} # fmt: skip
|
||||
whys = {g["why"] for g in out["gaps"]}
|
||||
assert {"노임 단가 없음", "산근 단가 없음(145-1)", "수량 없음", "% 밑수 없음"} <= whys
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
@@ -54,7 +55,7 @@ LINES = {
|
||||
{"kind": "machine", "key": "X1", "qty": 4.295},
|
||||
{"kind": "hopyo", "key": "B", "qty": 0.5},
|
||||
{"kind": "material", "key": "M4", "qty": 0.354},
|
||||
{"kind": "expense", "key": "E16", "qty": 1.103},
|
||||
{"kind": "expense", "key": "E16", "qty": 1.103}, # 합성 줄 — 산근 · 대가는 경비 줄을 안 냄(166-5)
|
||||
]},
|
||||
"B": {"lines": [{"kind": "labor", "key": "L1", "qty": 1.658},
|
||||
{"kind": "labor", "key": "L9", "qty": 1}]},
|
||||
@@ -155,3 +156,26 @@ def test_산근_블록_역전개_엑셀_반올림():
|
||||
machine = s["sum_machine"][0] # 중기시간금액집계표 10 줄 노무비
|
||||
assert (machine["qty"], machine["labor"], machine["sum"]) == (1436.14, 79992998, None)
|
||||
assert s["unlinked"] == 3 # 토공 · 대가 전 구조물 · 수량 빈칸 = 전개 안 함
|
||||
|
||||
|
||||
# ── 166-5 경비 집계표 — 실제 블록 꼴은 경비 자원 0 → 표 위 안내 ──
|
||||
from test_155_b09_tabs import _node # noqa: E402
|
||||
|
||||
EXPENSE_NONE = "경비 갈래 자원 없음 — 중기 · 자재로 셈 · 경비 로직이 들어오면 채워짐"
|
||||
|
||||
|
||||
def _expense_tab(summary):
|
||||
return _node(
|
||||
f"\nconst t = buildSumExpense({{ payload: {{ summary: {json.dumps(summary)} }} }});"
|
||||
"\nconsole.log(JSON.stringify({ n: t.rows.length, hint: t.hint }));",
|
||||
"UI_Tabs_Summary",
|
||||
)
|
||||
|
||||
|
||||
def test_166_5_실자료_경비_0_이면_안내():
|
||||
s = compute_summary(SG_SHEETS, hopyo_lines(SG_SHEETS))
|
||||
assert s["sum_expense"] == [] # 산근 블록 꼴 = 경비 갈래 줄 없음
|
||||
out = _expense_tab(s)
|
||||
assert out["n"] == 0 and out["hint"].startswith(EXPENSE_NONE)
|
||||
filled = _expense_tab(compute_summary(SHEETS, LINES)) # 합성 경비 줄이 있으면 안내 없음
|
||||
assert filled["n"] == 1 and EXPENSE_NONE not in filled["hint"]
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
"""166-6 일위대가목록표 블록 합 — 빈 줄 있는 블록 = 아는 줄 합 + 「빈 줄 n」 · 내역 단가엔 안 넘김.
|
||||
|
||||
견본 = 대가 A(노무 아는 줄 · 자재 단가 없음 줄) · 대가 B(A 를 부름 → 그 줄도 빈 줄) · 대가 C(빈 줄 없음).
|
||||
파이썬 `B09_Estimation_Calc_Labor` ↔ TS 짝 거울 + 목록표 화면 「빈 줄 n」 · 풍선(Node 타입 지움).
|
||||
"""
|
||||
|
||||
import json
|
||||
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_Labor import compute_labor, daega_price # noqa: E402
|
||||
from test_145_2_b09_labor_calc import _same, _ts # noqa: E402
|
||||
from test_155_b09_tabs import _node # noqa: E402
|
||||
|
||||
SHEETS = {
|
||||
"labor": [{"key": "L1", "price": 165545}],
|
||||
"material": [{"key": "M1", "price": None}],
|
||||
"machine": [],
|
||||
"gaps": [],
|
||||
}
|
||||
|
||||
|
||||
def _b(bid, name, lines):
|
||||
return {
|
||||
"id": bid,
|
||||
"kind": "조합",
|
||||
"name": name,
|
||||
"spec": "",
|
||||
"unit": "m",
|
||||
"cite": "",
|
||||
"lines": lines,
|
||||
}
|
||||
|
||||
|
||||
DAEGA = {
|
||||
"blocks": [
|
||||
_b("A", "기슭막이", [
|
||||
{"kind": "labor", "key": "L1", "qty": 0.5, "name": "보통인부"},
|
||||
{"kind": "material", "key": "M1", "qty": 2, "name": "토목용부직포"},
|
||||
]),
|
||||
_b("B", "겹 대가", [
|
||||
{"kind": "labor", "key": "L1", "qty": 0.1, "name": "보통인부"},
|
||||
{"kind": "daega", "key": "A", "qty": 1, "name": "기슭막이"},
|
||||
]),
|
||||
_b("C", "아는 줄만", [{"kind": "labor", "key": "L1", "qty": 1, "name": "보통인부"}]),
|
||||
],
|
||||
"owners": {"pipe@100.0": "A", "pipe@200.0": "C"},
|
||||
} # fmt: skip
|
||||
|
||||
|
||||
def test_아는_줄_합_빈_줄_n():
|
||||
out = compute_labor(DAEGA, SHEETS)
|
||||
rows = {r["key"]: r for r in out["daega"]}
|
||||
# 165,545 × 0.5 = 82,772.5 → 블록 ROUNDDOWN 0 · 자재 줄은 빈 줄
|
||||
assert (rows["A"]["sum"], rows["A"]["labor"], rows["A"]["material"]) == (82772, 82772, 0)
|
||||
assert (rows["A"]["blank"], rows["A"]["blank_names"]) == (1, ["토목용부직포"])
|
||||
# 부른 대가에 빈 줄 → 그 줄도 빈 줄(아는 줄 합을 위로 안 넘김)
|
||||
assert (rows["B"]["sum"], rows["B"]["blank"], rows["B"]["blank_names"]) == (
|
||||
16554,
|
||||
1,
|
||||
["기슭막이"],
|
||||
)
|
||||
assert (rows["C"]["sum"], rows["C"]["blank"]) == (165545, 0)
|
||||
# 목록표 = 블록 합계 그대로(같은 셈 한 벌)
|
||||
for b in out["daega_blocks"]:
|
||||
assert _same(
|
||||
{k: rows[b["key"]][k] for k in ("sum", "blank")}, {"sum": b["sum"], "blank": b["blank"]}
|
||||
)
|
||||
# 내역 단가 = 빈 줄 블록은 빈칸 · 없는 블록은 그대로
|
||||
assert daega_price(out, "pipe@100.0")["sum"] is None
|
||||
assert daega_price(out, "pipe@100.0")["labor"] is None
|
||||
assert daega_price(out, "pipe@200.0")["sum"] == 165545
|
||||
|
||||
|
||||
def test_거울_파이썬_TS():
|
||||
py = json.loads(json.dumps(compute_labor(DAEGA, SHEETS), ensure_ascii=False))
|
||||
ts = _ts(DAEGA, SHEETS, {})
|
||||
assert _same(py, ts["out"])
|
||||
assert _same(daega_price(py, "pipe@100.0"), ts["price"])
|
||||
|
||||
|
||||
def test_목록표_빈_줄_글_풍선():
|
||||
sheets = json.dumps(compute_labor(DAEGA, SHEETS), ensure_ascii=False)
|
||||
out = _node(
|
||||
f"\nconst t = buildDaegaList({{ sheets: {sheets} }});"
|
||||
"\nconsole.log(JSON.stringify({ notes: t.rows.map((r) => r.blank_note),"
|
||||
" sums: t.rows.map((r) => r.sum), cols: t.columns.map((c) => c.key),"
|
||||
" tips: t.rows.map((_, i) => t.tip(i, 'blank_note') ?? null) }));"
|
||||
)
|
||||
assert out["cols"][5:7] == ["sum", "blank_note"] # 합계 바로 옆
|
||||
assert out["notes"] == ["빈 줄 1", "빈 줄 1", ""]
|
||||
assert out["sums"] == [82772, 16554, 165545]
|
||||
assert out["tips"] == ["빈 줄 — 토목용부직포", "빈 줄 — 기슭막이", None]
|
||||
Reference in New Issue
Block a user