"""B09 자재 관급 · 별도 표시 · 사본 단가 목록(PLAN 841-1) — 서버 단독 · 순수 함수. 자재 표시 = M02 자재표시를 대비표 기본 표시로 · 노무비 · 중기목록 = 엔진 단가 나열(`price_lists`). M02 일위대가 · 단가산출 셈은 재료 줄을 자재표시(자재구분 관급 · 별도계상 — 빈 칸 = 별도계상)로 합에서 뺌(`M02_Labor_Doc.apart`) → B09 도 같은 표시로 대가 · 산근 안 0 원 · 4 자재대 · 관급자재대로 (`B09_Estimation_Calc_Labor._apart` · `Sangeun.Solver._aside` · `Calc_Bill` 자재대 수량 = `aside_qty`). 대비표 표시 = 사용자 › 이 기본 · 사용자 「사급」 = 기본을 끔. """ from __future__ import annotations from typing import Any from M02_MasterTemplete import M02_Labor_Doc as labor_doc PARTS = ("labor", "material", "expense") def supply_mark(one: Any) -> str | None: """M02 자재표시(841-1) → 대비표 기본 표시 — 관급 · 별도(별도계상 · M02 기본) · None(직접계산).""" if labor_doc.mark_of(one, "자재구분") == "관급": return "관급" return "별도" if labor_doc.apart(one) else None def material_marks(blocks: list[dict[str, Any]]) -> dict[str, str | None]: """대가 블록 재료 줄 M02 표시를 자재 키마다 하나로(841-1) — 관급 하나라도 = 관급 · 별도 하나라도 = 별도 · 모두 직접계산 = None. ponytail: 키 하나 = 표시 하나(줄마다 다르면 별도 쪽 · 자재대에 한 번).""" out: dict[str, str | None] = {} for block in blocks: for line in block.get("lines") or []: if line.get("kind") != "material" or not line.get("key") or "mark" not in line: continue key, was = str(line["key"]), out.get(str(line["key"])) out[key] = "관급" if "관급" in (was, line["mark"]) else was or line["mark"] return out def supply_defaults(inputs: dict[str, Any], user: dict[str, Any]) -> Any: """841-1 대비표 기본 표시 = M02 자재표시(대가 재료 줄 · 없으면 M02 기본 별도계상) — 로직 자재 (B08 줄 밖 · 유가 밖) 입력 줄에 `supply` 를 얹음 → 자재 키 → 관급 · 별도(사용자 표시 › 기본).""" marks = material_marks((inputs.get("daega") or {}).get("blocks") or []) for row in inputs.get("materials") or []: if row.get("origin") == "M01" and "supply" not in row and marks.get(row["key"], "별도"): row["supply"] = marks.get(row["key"], "별도") mine = user.get("materials") or {} default = {row["key"]: row.get("supply") for row in inputs.get("materials") or []} def supply(key: Any) -> str | None: got = (mine.get(key) or {}).get("supply") return None if got == "사급" else got or default.get(key, marks.get(key, "별도")) return supply def price_lists(blocks: list[dict[str, Any]], sg_blocks: list[dict[str, Any]]) -> tuple[list, list]: """노무비목록표 · 중기목록표 입력(841-1) — 대가 입력 줄 `own` · 산근 줄 `price` = M02 엔진 단가 (사본 값) 나열 · 다시 안 셈 · 수량 있는 줄만. ponytail: 키 하나 = 처음 본 단가(사본마다 시점이 달라도).""" labor: dict[str, dict] = {} machine: dict[str, dict] = {} for block in [*blocks, *sg_blocks]: for ln in block.get("lines") or []: kind = ln.get("kind") key = ln.get("key") or (ln.get("ref") or {}).get("key") if kind not in ("labor", "machine") or not key or not ln.get("qty"): continue price = ln.get("own") or ln.get("price") or {} name, spec = str(ln.get("name") or ""), str(ln.get("spec") or "") name = name.removesuffix(spec).strip() if spec else name # 「굴착기 0.7㎥」 + 규격 겹침 head = {"key": key, "name": name, "spec": spec} if kind == "labor" and price.get("labor") is not None: labor.setdefault(key, {**head, "unit": "인", "price": price["labor"]}) elif kind == "machine" and None not in [price.get(p) for p in PARTS]: machine.setdefault(key, {**head, **{p: price[p] for p in PARTS}}) return list(labor.values()), list(machine.values()) def sk_money(doc: dict, whole: Any, expand: Any, rid: str) -> dict[str, float] | None: """단가산출 블록 합(841-1) = M02 가 일위대가 안 SK 를 셀 때 쓰는 1 단위 셈(`M02_Sangeun_Calc.unit` · 수식 문서 · 기계 덮음 · 별도계상까지) × 배(블록 = 바탕 기준단위) — 못 셈 = None(줄 합 그대로).""" from M02_MasterTemplete import M02_Sangeun_Calc as calc try: got = calc.unit(doc, whole, expand, (rid,)).get("기준") per = float(calc.ratio_of(doc, whole.logic(doc["바탕"]["로직"]), whole)) except Exception: # noqa: BLE001 — M02 셈이 못 돌면 줄 합(옛 길) 그대로 return None if not got: return None return { p: float(got[k]) * per for p, k in zip(PARTS, ("노무비", "재료비", "경비"), strict=True) }