feat(m02): 사전조합 자재를 사전조합 값 · B08 참조 재료 · B09 겹 대가 · 사본 단가 묶음에 셈 (175-2)

- 사전조합 1 단위 값(Expand._combo) = 안 줄 + 자재 기준단가 × 손 · 빈칸 = 안 셈 · 단가 없음 = 까닭 · 안 줄에 자재 줄
- B08 _ref_mats 가 사전조합 자재(손 × 겹 손)를 품목 코드로 더함 · 사용자 자재는 연료 거름 안 함
- B09 겹 대가 블록에 자재 줄(조합 자재 줄과 한 꼴 _material)
- 사본 단가 묶음: 굳힌 사전조합 자재 · 고름 코드(frozen_materials) · 개인 자재 묶음도
- 화면 하위 행: 안 줄 자재 코드 표시
- 시험: test_175_precombo_mats 네 개 더함

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SE9MxeXTu2uaDZ55BJowAY
This commit is contained in:
2026-10-10 11:49:20 +09:00
co-authored by Claude Opus 5.5
parent 1157af125b
commit bc0160da2d
7 changed files with 152 additions and 14 deletions
+35 -1
View File
@@ -7,7 +7,8 @@
precombo `{층}/precombo/SC-######.json` 사전조합
`{종류:"사전조합", 키, 이름, 단위, 본뜬, 담은로직:[{참조, 수량:{손}, 메모}
| {로직, 입력값, 메모, 수량:{손}, 고름?, 자재표시?}], 자재:[일위대가 자재 꼴]}` —
승격 · 사전조합 · 단가산출 로직(51-11) · 수량은 손(기본 1) · 자재 수량은 손 · 빈칸 = 안 셈(175) ·
승격 · 사전조합 · 단가산출 로직(51-11) · 수량은 손(기본 1) ·
자재 수량은 손 · 빈칸 = 안 셈(175) ·
값 = Σ 안 줄 1 단위 값 × 수량(로직 줄 = 기준 ÷ 배) + Σ 자재 기준단가 × 손
참조 = `{층, 주인, 키}`(마스터 주인 null · 회사 `C` · 개인 `C/U`) — 종류는 키 머리(SP · SC) ·
위 층만 가리킴(개인 → 그 개인 · 그 회사 · 마스터 / 회사 → 그 회사 · 마스터 / 마스터 → 마스터) ·
@@ -460,6 +461,29 @@ class Expand:
why = why or f"「{sub.get('이름')}」 {sub.get('까닭')}"
continue
rows.append({k: v * qty for k, v in sub["기준"].items()})
for mat in doc.get("자재") or []: # 사용자 자재(175-2) = 기준단가 × 손 · 빈칸 = 안 셈
qty = labor._number((mat.get("수량") or {}).get("손"))
if qty is None:
continue
got = labor.material_price(self.whole, mat["코드"], mat.get("단위"))
price = labor._number(got["기준단가"])
zero = dict.fromkeys(labor.COSTS, Decimal(0))
base = None if price is None else {**zero, "재료비": price, "계": price}
name = mat.get("이름") or mat["코드"]
inner.append(
{
"자재": mat["코드"],
"수량": qty,
"이름": name,
"단위": mat.get("단위"),
"기준": base,
"까닭": got["까닭"],
}
)
if base is None:
why = why or f"「{name}」 {got['까닭']}"
continue
rows.append({k: v * qty for k, v in base.items()})
return {
"이름": doc.get("이름"),
"단위": doc.get("단위"),
@@ -512,6 +536,16 @@ def with_pills(doc: dict[str, Any]) -> dict[str, Any]:
return {**doc, "알약": combo_store.combo_pills({"담은로직": lines})["물량"]}
def frozen_materials(copies: dict[str, Any]) -> list[str]:
"""굳힌 사전조합의 자재 · 고른 로직 자재 코드(175-2) — 프로젝트 단가 묶음에 넣음."""
out = []
for doc in copies.values():
out += [str(m.get("코드")) for m in doc.get("자재") or [] if isinstance(m, dict)]
lines = [one for one in doc.get("담은로직") or [] if isinstance(one, dict)]
out += [str(key) for one in lines for key in (one.get("고름") or {}).values()]
return out
def frozen_logics(copies: dict[str, Any]) -> list[str]:
"""굳힌 단가승격 · 사전조합이 담은 로직 키 — 프로젝트 단가 묶음에 넣음."""
return [