- [수정] 모달 = Labor_Table(읽기 · 덧칸 표지 · 엑셀 금액) · 줄 = 로직(단가산출 · 일위대가) / 요소(연결됨 · 후보 · 못 이음) · 단가산출 줄 = 가져온 식 SK 수식 탭 모달(Labor_SkEdit) · 서버 hopyo-view(M02_Hopyo_View) - 엑셀 보기 목록 · 칠 = 줄 표지(View.listing) · 단가산출 탭 = 블록 목록 + [가져온 식으로 열기] · [내 단가산출로] - 걷음(요구 703): 판정 체계 785(Judge · Solve · Bind · San_Basis 다섯 · Make.Move · Row 1차 판정 · 화면 Check · CheckRows · Rows · Block · JudgeApi · Picks · Judge.css) · [우리 기초로 바꾸기](to-base) · 근거 기초 제안 · Clause 기초 판정 - 시험 지움: 642_2(Bind · Solve) · 642_3(Row 1차 판정) · 642_5(옮기기 Move) · 642_6(판정 화면) · 786_2(옛 [수정] 모달) · 793_3a(근거 → 기초 제안) — 모두 걷은 기초 판정 길 몫 - 시험 고침: 642_1 · 794_2a2 · 794_2b(근거 제안 부분만 뺌) · 793_2 · 793_3b(기초 바꾸기 기대 → 없음) · 627 · 779_2 · 785_4 · 807_1 · m02_hopyo_excel · grid · stmate(judge 길 → view 길) - 새 시험 test_809_1_import_labor(기초 길 0 · 표지 1,350 줄 · 가져온 식 SK · 모달 = Labor_Table · 금액 = 엑셀) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
123 lines
6.2 KiB
Python
123 lines
6.2 KiB
Python
"""M02 일위대가 실무자료 → 우리 SC 줄 몸(PLAN 785-5 · 809-1) — `M02_Hopyo_Build.Builder` 가 줄 차례대로 부름.
|
||
|
||
`Lines.put` = 대상 하나(`{로직|자재|호표|전국|이음|참조, 입력값, 배, 몫}` · 붙여넣기 · 구조물 조합으로 길) →
|
||
우리 줄 · 자재(같은 로직 둘째 = 한 줄 SC 사본 · 재료 = 자재 목록 · 이음 = 고정 줄).
|
||
확인 안 한 줄 = Builder 가 고정 길(`Fixed.line_of`)로. 옛 판정 고른 것 · [옮기기](785-5 `Move`)는 809-1 에서 지움 —
|
||
불러오기 옮기기 = [내 일위대가로](`Build.build_all only` · 경쟁사 로직 인정 · 요구 703).
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from decimal import Decimal
|
||
from typing import Any
|
||
|
||
from M02_MasterTemplete import M02_Hopyo_Build as hbuild
|
||
from M02_MasterTemplete import M02_Hopyo_Fixed as hfix
|
||
from M02_MasterTemplete import M02_Hopyo_Kids as hkids
|
||
from M02_MasterTemplete import M02_Hopyo_Material as hmat
|
||
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
|
||
|
||
|
||
def _num(value: Decimal) -> int | float:
|
||
return hbuild._num(value)
|
||
|
||
|
||
# ── 확인한 줄 몸(SC) ─────────────────────────────────────────────────────
|
||
class Lines:
|
||
"""한 호표 줄 모음 — `Builder.build` 가 줄 차례대로 부름 · 확인 안 한 줄은 Builder 가 고정 길로."""
|
||
|
||
def __init__(self, b: Any, rows: list[dict], where: dict, stamp: str, linker: Any) -> None:
|
||
self.b, self.rows, self.where, self.stamp, self.linker = b, rows, where, stamp, linker
|
||
self.lines: list[dict] = []
|
||
self.mats: dict[str, dict] = {}
|
||
self.missing: list[dict] = []
|
||
self.used: set[str] = set()
|
||
self.mat_lines: dict[str, dict] = {}
|
||
self.nation: dict[tuple, dict] = {}
|
||
self.taken: set[str] = set()
|
||
self.kids: set[int] = set()
|
||
self.left: list[dict] = []
|
||
|
||
def put(self, line: dict, one: dict, alias: str | None, qty: Decimal | None = None,
|
||
mark: dict | None = None) -> None: # fmt: skip
|
||
"""대상 하나 → 줄 · 자재 — 옛 꼴 `{로직|자재|호표|전국|이음, 입력값, 배, 몫}` · `qty` = 새 길 수량
|
||
(엑셀 × 몫 × 배) · `mark` = 새 길 줄 `본뜬`."""
|
||
keep = len(self.lines)
|
||
if "이음" in one:
|
||
others = [x for x in self.rows if x is not line]
|
||
fx = hfix.line_of(line, others, self.where, self.taken, self.linker, one["이음"])
|
||
self.lines.append(fx)
|
||
else:
|
||
qty = (
|
||
qty
|
||
if qty is not None
|
||
else Decimal(str(line.get("수량") or 0)) * Decimal(str(one["배"]))
|
||
)
|
||
self._put(line, one, alias, qty, mark is not None)
|
||
for row in self.lines[keep:]:
|
||
row.update({"본뜬": mark} if mark else {})
|
||
|
||
def _put(self, line: dict, one: dict, alias: str | None, qty: Decimal, new: bool) -> None:
|
||
b = self.b
|
||
memo = hbuild._memo(line, one)
|
||
if "전국" in one:
|
||
at = (one["이름"], one["규격"], one["단위"])
|
||
have = self.nation.get(at)
|
||
hand = qty + Decimal(str(have["수량"]["손"])) if have else qty
|
||
head = {"이름": at[0], "규격": at[1], "단위": at[2], "수량": {"손": _num(hand)}}
|
||
self.nation[at] = {**head, **(hmat.marks(line, at[0]) if not have else {
|
||
k: have[k] for k in labor.MARKS if k in have
|
||
})} # fmt: skip
|
||
self.missing.append(hbuild._missing(line, hbuild.NATIONAL))
|
||
return
|
||
if "자재" in one:
|
||
code = one["자재"]
|
||
have = self.mats.get(code)
|
||
hand = qty + Decimal(str(have["수량"]["손"])) if have else qty
|
||
name = b.mat_names.get(code, "")
|
||
marks = (
|
||
have and {k: have[k] for k in labor.MARKS if k in have} or hmat.marks(line, name)
|
||
)
|
||
if one.get("별도계상") is not None: # 세 칸 값(빈 칸 = 기본 「별도계상」)
|
||
marks = {**marks, "별도계상": "별도계상" if one["별도계상"] else "직접계산"}
|
||
self.mats[code] = {"코드": code, "수량": {"손": _num(hand)}, **marks}
|
||
if not have:
|
||
self.mat_lines[code] = line
|
||
return
|
||
if "호표" in one or "참조" in one:
|
||
if "호표" in one:
|
||
self.kids.add(one["호표"])
|
||
key = b.done.get(hbuild.mark(b.key, one["호표"]), "SC-미리")
|
||
ref = {"층": refs.here()[0], "주인": refs.here()[1], "키": key}
|
||
else:
|
||
ref = one["참조"]
|
||
self.lines.append({"참조": ref, "별칭": alias, "메모": memo, "수량": {"손": _num(qty)}})
|
||
return
|
||
row = {"로직": one["로직"], "입력값": one["입력값"], "메모": memo}
|
||
if not new:
|
||
kept, why = sangeun.kept(b, line, one, qty, alias, memo)
|
||
if why:
|
||
self.left.append(sangeun.left(line, why))
|
||
if kept is not None:
|
||
self.lines.append(kept)
|
||
return
|
||
if one["로직"] not in self.used:
|
||
self.used.add(one["로직"])
|
||
self.lines.append({**row, "별칭": alias, "수량": {"손": _num(qty)}})
|
||
return
|
||
at = int(line.get("차례", 0))
|
||
hopyo, file = b.hopyo, b.doc.get("파일") or ""
|
||
wrap = { # 같은 로직 둘째 — 한 줄 사전조합으로 감쌈
|
||
"이름": f"{hopyo['이름']} — {line.get('이름')}",
|
||
"단위": line.get("단위") or None,
|
||
"구분": hbuild.ORIGIN,
|
||
"상세구분": file,
|
||
"담은로직": [{**row, "별칭": alias, "수량": {"손": 1}}],
|
||
"자재": [],
|
||
"본뜬": b._origin(f"{hbuild.mark(b.key, b.no, at)} {one['로직']}", self.stamp),
|
||
}
|
||
ref = {"키": "SC-미리"} if b.dry else hkids.save(wrap, b.same)[0] # 미리 보기 = 쓰기 없음
|
||
self.lines.append({"참조": ref, "별칭": alias, "메모": memo, "수량": {"손": _num(qty)}})
|