- 728-2 단위 환산 뒤 [단가산출 만들기] 500 · 400(100개 ↔ ㎡ · ㎥ ↔ m2 · 본 ↔ M · 개소 ↔ m) 걷음 — 견줌 SK 배 = ratio_of(728 규칙) · 성격 다름 = 환산 계수 = 우리 품 ÷ 엑셀 품(인력 · 장비 둘 이상 같은 비일 때만) · 못 구함 = 고름 대기(까닭 「단위 성격 다름 · 계수 필요」 · 후보[].계수 칸)
- 맞음 블록도 단위 견줌(전엔 셈 없이 기초로 써서 뒤 셈에서 막힘)
- 못옮김 = [{id, 갈래 노임|기계|자재, 이름, 규격, 단위, 수량, 글, 후보}] · 응답 만듦[].못옮김 · 환산
- 몸 바탕[번] = {로직?, 입력값?, 환산?, 잇기?} · 잇기 [{id, 노임|기계|자재: 키} | {id, 뺌}] → SK 더한줄 인력 · 기계 · 재료(엑셀 수량 × 배) · 뺌 = 본뜬 놓음 · 틀린 id · 키 400
- 못옮김 남은 SK 를 쓰는 일위대가 = 남은줄(단산 · SK · 못옮김) · hopyo-build · build-all 409
- 못옮김 남은 블록 = SK(같지 않음)
- 시험 test_729 에 단위 · 잇기 · 409 시험 하나 더함
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
118 lines
5.4 KiB
Python
118 lines
5.4 KiB
Python
"""M02 일위대가 만들기 — 단가산출(SK) 이음 · 남은 줄(PLAN 729-2 · 요구서 내역19 1장 8).
|
|
|
|
`M02_Hopyo_Build.Builder` 가 부름(`b` = 그 만들기) —
|
|
확인 안 한 단가산출 줄 = 그 블록 SK 참조(이 층 · 같은 원본 · 없으면 `M02_Hopyo_Sangeun.Maker` 로 그 블록만
|
|
만듦 · 미리 보기 = 키만 · 맞춤 셈 전 · 고름 대기 · 단위 다름 = 못 이음) ·
|
|
확인한 로직 줄이 차이 SK 의 바탕 = 그 SK 참조(엑셀 차이 보존 · 별칭 짝 = 기초까지만) ·
|
|
남은 줄 = 엑셀 줄 · 갈래 · 까닭 · 후보(단가산출 고름 대기) · 못옮김 남은 SK = 못 이음(`단산` 번 · `못옮김` ·
|
|
잇기 = [단가산출 만들기] `바탕[번].잇기` · 729-4).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from decimal import Decimal
|
|
from typing import Any
|
|
|
|
from M01_MasterData import M01_MasterData_Store as m01
|
|
from M02_MasterTemplete import M02_Hopyo_Finger as finger
|
|
from M02_MasterTemplete import M02_Hopyo_Sangeun as sangeun
|
|
from M02_MasterTemplete import M02_Labor_Doc as labor
|
|
from M02_MasterTemplete import M02_Labor_Ref as refs
|
|
|
|
mm_unit = m01.cm.mf.mp.mm.plain_unit
|
|
LEFT = "안 이은 줄이 남음 — 줄마다 이을 것을 고름"
|
|
WHY = {
|
|
"단가산출": "맞는 기초 없음 — 고름 대기",
|
|
"자재": "자재 후보 여럿 · 없음",
|
|
"별도계상": "자재 후보 여럿 · 없음",
|
|
"노임": "같은 이름 노임 없음",
|
|
"기계": "같은 기계(EQ) 없음 · 여럿",
|
|
"호표": "하위 호표 확인 전 · 단위 다름",
|
|
"%": "밑수가 다른 줄 금액 합 아님",
|
|
}
|
|
|
|
|
|
def _num(value: Decimal) -> int | float:
|
|
value = value.normalize()
|
|
return int(value) if value == value.to_integral_value() else float(value)
|
|
|
|
|
|
def sks(b: Any) -> dict[str, str]:
|
|
"""이 층 그 HP 의 SK `{본뜬 키: SK 키}`(한 번 읽어 둠)."""
|
|
if b._sk is None:
|
|
b._sk = sangeun.made(b.folder, b.key, b.source)
|
|
return b._sk
|
|
|
|
|
|
def sk_doc(b: Any, key: str) -> dict[str, Any]:
|
|
try:
|
|
got = json.loads((b.folder / "sangeun" / f"{key}.json").read_bytes())
|
|
except (OSError, ValueError):
|
|
return {}
|
|
return got if isinstance(got, dict) else {}
|
|
|
|
|
|
def _ref(key: str, line: dict, alias: Any, memo: str, qty: Decimal) -> dict[str, Any]:
|
|
head = {"층": refs.here()[0], "주인": refs.here()[1], "키": key}
|
|
return {"참조": head, "별칭": alias, "메모": memo, "수량": {"손": _num(qty)}}
|
|
|
|
|
|
def sk_line(b: Any, line: dict[str, Any], create: bool) -> tuple[dict | None, dict | None]:
|
|
"""단가산출 줄 → (그 블록 SK 참조 줄, 못 이은 까닭 {까닭, 후보?}) — `create` = 없으면 만듦."""
|
|
ref = line.get("참조") or {}
|
|
if ref.get("종류") != "단산":
|
|
return None, None
|
|
no = int(ref.get("번") or 0)
|
|
key = sks(b).get(sangeun.mark(b.key, no))
|
|
lost = None
|
|
if key is None and create:
|
|
if b._maker is None:
|
|
b._maker = sangeun.Maker(b.src, b.key, b.who)
|
|
if no not in b._maker.first:
|
|
return None, None
|
|
if not b._maker.done:
|
|
return None, {"까닭": "맞춤 셈 전 — 단가산출 못 만듦"}
|
|
plan = b._maker.plan(no)
|
|
if plan["갈래"] == sangeun.skpatch.WAIT:
|
|
return None, {"까닭": plan["까닭"], "후보": plan["후보"]}
|
|
lost = plan["못옮김"]
|
|
key = f"SK-미리{no}" if b.dry else b._maker.write(no, plan, None)
|
|
sks(b)[sangeun.mark(b.key, no)] = key
|
|
if key is None:
|
|
return None, None
|
|
doc = sk_doc(b, key)
|
|
lost = (doc.get("본뜬") or {}).get("못옮김") if lost is None else lost
|
|
if lost: # 연결 안 되면 못 만듦(내역 20-4)
|
|
why = f"단가산출 못옮김 {len(lost)} — [단가산출 만들기]에서 이음"
|
|
return None, {"까닭": why, "단산": no, "SK": key, "못옮김": lost}
|
|
unit = doc.get("단위") or line.get("단위")
|
|
if mm_unit(unit) != mm_unit(line.get("단위")):
|
|
return None, {"까닭": f"단가산출 단위 「{unit}」 다름"}
|
|
qty = Decimal(str(line.get("수량") or 0))
|
|
alias = str(line.get("이름") or "")[: labor.ALIAS_MAX].strip() or None
|
|
return _ref(key, line, alias, f"실무 {qty}{line.get('단위') or ''} · 단산{no}", qty), None
|
|
|
|
|
|
def kept(b: Any, line: dict, one: dict, qty: Decimal, alias: Any, memo: str) -> dict | None:
|
|
"""확인한 로직 줄이 그 블록 차이 SK 의 바탕 = 그 SK 참조 · 아니면 None."""
|
|
ref = line.get("참조") or {}
|
|
if ref.get("종류") != "단산" or one.get("몫") is not None:
|
|
return None
|
|
key = sks(b).get(sangeun.mark(b.key, int(ref.get("번") or 0)))
|
|
doc = sk_doc(b, key) if key else {}
|
|
base = (doc.get("바탕") or {}).get("로직")
|
|
if (doc.get("본뜬") or {}).get("갈래") != sangeun.skpatch.SK or base != one["로직"]:
|
|
return None
|
|
return _ref(key, line, alias, f"{memo} · 차이 SK", qty)
|
|
|
|
|
|
def left(line: dict[str, Any], why: dict | None) -> dict[str, Any]:
|
|
"""남은 줄 한 줄 — 엑셀 줄 · 갈래 · 까닭 · 후보."""
|
|
kind = finger.kind_of(line)
|
|
keep = ("차례", "이름", "규격", "단위", "수량")
|
|
out = {**{k: line.get(k) for k in keep}, "갈래": kind}
|
|
out["까닭"] = (why or {}).get("까닭") or WHY.get(kind, "이을 것 없음")
|
|
more = {k: v for k, v in (why or {}).items() if k not in ("까닭", "후보")}
|
|
return {**out, "후보": (why or {}).get("후보") or [], **more}
|