Files
Aislo/B09_Estimation/B09_Estimation_Supply.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

94 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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)
}