fix(B09): 내역 구조물 줄 ref = 대가 블록 — 집계표 역전개 · 이동 이음 · 한 바퀴 시험(145-2)
- daega_price / daegaPrice 에 블록 key · split_by_block(파이썬 · TS) = 대가 단가가 있으면 ref {tab: dg, key}
- 한 바퀴 시험 = 설계내역서 → 대가 → 산근(145-1) → 중기 → 집계표(145-5) · 연결 없음 0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QND7Co43B24zK2P937rdxt
This commit is contained in:
@@ -126,6 +126,8 @@ def split_by_block(item: dict[str, Any], price_of: PriceOf) -> list[tuple[dict,
|
||||
"note": " · ".join(t for t in (tag, item.get("note") or "") if t),
|
||||
"owners": {o: item["owners"][o] for o in group["owners"]},
|
||||
}
|
||||
if group["price"] and group["price"].get("key"): # 대가 블록(145-2) — 이동 · 집계표 역전개
|
||||
part["ref"] = {"tab": "dg", "key": group["price"]["key"]}
|
||||
out.append((part, group["price"]))
|
||||
return out
|
||||
|
||||
|
||||
@@ -119,6 +119,8 @@ export function splitByBlock(item: Row, priceOf: PriceOf): Array<[Row, Row | nul
|
||||
note: [tag, item.note || ""].filter((t) => t).join(" · "),
|
||||
owners: Object.fromEntries(group.owners.map((o: string) => [o, item.owners[o]])),
|
||||
};
|
||||
// 대가 블록(145-2) — 이동 · 집계표 역전개
|
||||
if (group.price?.key) part.ref = { tab: "dg", key: group.price.key };
|
||||
out.push([part, group.price]);
|
||||
}
|
||||
return out;
|
||||
|
||||
@@ -193,5 +193,6 @@ def daega_price(sheets: dict[str, Any], owner: str) -> dict[str, Any] | None:
|
||||
return None
|
||||
return {
|
||||
"no": f"대가{row['no']}",
|
||||
"key": bid,
|
||||
**{k: row[k] for k in ("labor", "material", "expense", "sum")},
|
||||
}
|
||||
|
||||
@@ -176,6 +176,7 @@ export function daegaPrice(sheets: Row, owner: string): Row | null {
|
||||
if (!row) return null;
|
||||
return {
|
||||
no: `대가${row.no}`,
|
||||
key: bid,
|
||||
labor: row.labor,
|
||||
material: row.material,
|
||||
expense: row.expense,
|
||||
|
||||
@@ -124,6 +124,7 @@ def test_엑셀_대가_블록_검산():
|
||||
} # fmt: skip
|
||||
assert daega_price(out, "pipe@100.0") == {
|
||||
"no": "대가1",
|
||||
"key": "DG14",
|
||||
"labor": 77755,
|
||||
"material": 9519,
|
||||
"expense": 14248,
|
||||
@@ -362,3 +363,52 @@ def test_집계표_이음_꼴():
|
||||
]
|
||||
assert {"kind": "machine", "key": "X00044", "qty": 0.0416} in lines["DG2"]["lines"]
|
||||
assert all(ln["kind"] != "pct" for ln in lines["DG2"]["lines"]) # % 줄 = 자원 아님
|
||||
|
||||
|
||||
def test_한_바퀴_내역_대가_산근_중기_집계표(tmp_path):
|
||||
"""이음 끝 확인 — 설계내역서 구조물 줄(B08 열 owners) → 대가 블록마다 나눔 → 대가 줄 →
|
||||
산근(145-1 · 승격 줄) → 중기 → 집계표(145-5) 역전개 · 짝 셈 한 벌 = Router.compute_sheets."""
|
||||
from B09_Estimation.B09_Estimation_Calc_Base import rounddown
|
||||
from B09_Estimation.B09_Estimation_Router import compute_sheets
|
||||
from B09_Estimation.B09_Estimation_Summary import compute_summary, hopyo_lines
|
||||
|
||||
root = _project(tmp_path / "loop", [(100, "SS000901"), (400, "SS000902")])
|
||||
_snap(root, "pipe@100.0", "SS000901", LINES, _values(STONE))
|
||||
promoted = [
|
||||
{"로직": "GF000119", "승격": True, "수량": {"손": 1}}, # 노체포설 = 산근 · 중기 줄
|
||||
{"참조": {"층": "system", "주인": None, "키": "SC-T"}, "수량": {"손": 4}},
|
||||
]
|
||||
_snap(root, "pipe@400.0", "SS000902", promoted, _values(STONE), SC)
|
||||
inputs = prices.build_inputs(None, linked_resource_keys(root))
|
||||
inputs["daega"] = daega_inputs(root)
|
||||
inputs["hopyo"] = {}
|
||||
inputs["bill"] = {
|
||||
"items": [
|
||||
{"key": "st:revet", "section": "2.1", "name": "돌기슭막이", "spec": "", "unit": "m",
|
||||
"qty": 10, "ref": {"tab": "dg_list", "key": "revet"}, "note": "",
|
||||
"owners": {"pipe@100.0": 4, "pipe@400.0": 6}},
|
||||
]
|
||||
} # fmt: skip
|
||||
sheets = compute_sheets(root, inputs, {})
|
||||
owners = sheets["daega_owners"]
|
||||
rows = [r for r in sheets["bill"]["rows"] if r.get("kind") == "item"]
|
||||
assert [r["ref"] for r in rows] == [
|
||||
{"tab": "dg", "key": owners["pipe@100.0"]},
|
||||
{"tab": "dg", "key": owners["pipe@400.0"]},
|
||||
]
|
||||
for row in rows:
|
||||
block = _block(sheets, row["ref"]["key"])
|
||||
assert row["price_labor"] == block["labor"] and block["sum"] is not None
|
||||
assert row["labor"] == rounddown(row["qty"] * block["labor"], 0)
|
||||
# 산근 이음 — 대가 줄 키 = 145-1 산근 키 · 단가가 들어옴
|
||||
combo = _block(sheets, owners["pipe@400.0"])
|
||||
sg_line = combo["lines"][0]
|
||||
sg_row = next(r for r in sheets["sg_list"] if r["key"] == sg_line["key"])
|
||||
assert sg_line["kind"] == "sangeun" and sg_line["prices"]["labor"] == sg_row["labor"]
|
||||
# 집계표 역전개 — 대가 · 사전조합 · 품셈 · 산근 끝까지
|
||||
summary = compute_summary(sheets, hopyo_lines(sheets))
|
||||
assert summary["unlinked"] == 0
|
||||
labor = {r["key"]: r["qty"] for r in summary["sum_labor"]}
|
||||
assert labor["LB000033"] == 25.6 # 4 × 2 × 0.32 + 6 × (4 × 3 × 0.32)
|
||||
machine = {r["key"]: r["qty"] for r in summary["sum_machine"]}
|
||||
assert machine.get("EQ000020", 0) > 0.08 # 품셈 4 × 0.5 × 0.0412 + 산근 6 × (중기 시간)
|
||||
|
||||
Reference in New Issue
Block a user