코드 - 고정 줄 단가 = 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>
94 lines
5.0 KiB
Python
94 lines
5.0 KiB
Python
"""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)
|
||
}
|