Files
Aislo/M02_MasterTemplete/M02_Hopyo_Compare.py
T
eomsangdonandClaude Opus 5.5 eaa8064f1a feat(777-1): 호표가 다른 호표를 부를 때 = 일위대가 둘 — 하위 함께 만들기 · 같은 SC 재사용 · 결과 글 · 납작 길 막음
- 부모 저장 때 확인 안 된 하위 호표(깊이 끝까지)를 하위 먼저 그 체크대로 함께 만듦(409 「먼저 확인」 걷음)
  · 서버 = 체크 제안 몸(M02_Hopyo_Kids.proposal ↔ 화면 bodyFor 짝) · 화면 = 확인 창 캐시 고름(Hopyo_Kids.ts)
  · 하위 실패 = 409 「하위 제N호표 실패 — …」 · 하위 · 하위남은줄 → 결과 표 [고르기]가 그 하위를 엶
  · [모두 고정] 연쇄 실패 까닭 따로 · 미리 보기는 하위 호표 줄을 이음으로 셈
- 같은 엑셀 다시 불러오기 = 같은 이름 · 같은 내용(수량까지) SC 재사용 — 본뜬.또(SK 꼴) · 끝내기는 그 몫만 뺌
- 결과 표 글 「SC-12 · 하위 제4호표 SC-11(사본 담음)」 · 확인 창 호표 줄 글 「하위 일위대가 SC-11 사본」
- [구조물 조합으로] 도 하위 먼저(못 만들면 지금처럼 고정 줄) · 붙여넣기 · B09 통째 = 이미 하위 먼저(안 고침)
- 엑셀 대조(CUTS · _excel_round · excel_given · compare) → 새 M02_Hopyo_Compare.py(Build 608 → 540)
- M02_Labor_Router 병행 흔적 가드 걷음(_later · inspect · 몸 칸 새로)
- STmate [엑셀 보기] 단가산출근거로 감(형식별 블록 시트 이름)
- 낡은 시험 고침: 「제46호표 먼저 확인」 409 · 글 → 하위 함께(777-1 정함) · 718-1 실패 = 남은줄 또는 하위 ·
  화면 시험 StaleError 안내 → unmadeKids · leftAt · 새 지킴 시험 test_777_1_hopyo_kids

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 09:24:48 +09:00

67 lines
3.6 KiB
Python

"""M02 실무 호표 만든 일위대가 ↔ 엑셀 호표 단가 대조(PLAN 705-3 · 723-1 · 742-1 · 777-1 `M02_Hopyo_Build` 에서 떼어 냄).
참고 · 판정 아님 — 우리 = 엑셀 끝수 꼴(EST 비목 합 내림 · STmate 줄 반올림 · 계 = 줄 계 합 내림) 중 엑셀과 같은 쪽 ·
수량 = 엑셀 수량(`본뜬.실무수량` · 하위 사전조합까지 `excel_given`).
"""
from __future__ import annotations
from decimal import ROUND_FLOOR, ROUND_HALF_UP, Decimal
from typing import Any
from M01_MasterData import M01_MasterData_Store as m01
from M02_MasterTemplete import M02_Labor_Doc as labor
from M02_MasterTemplete import M02_Labor_Ref as refs
# 엑셀 끝수 꼴(705-3) — (줄 금액 0.1 · 합 원 자름, 계 = 줄 계 합에서) · EST = 비목 합 내림 ·
# STmate = 줄 반올림 · 계 = 줄 계 합 내림(비목 머리 값과 따로)
CUTS = ((ROUND_FLOOR, False), (ROUND_HALF_UP, True), (ROUND_HALF_UP, False))
def _excel_round(got: dict[str, Any], how: str, by_line: bool) -> Decimal | None:
"""엑셀 끝수(705-3) — 줄 금액 비목마다 0.1(`how`) · 하위 호표 단가 = 원 · 비율 줄 = 기준 × 율 ÷ 100 ·
합 = 비목마다 원(`how`) 더함 · `by_line` = 줄 계 합 원 내림 · 못 셈 줄 있으면 None."""
parts = dict.fromkeys(labor.COSTS, Decimal(0))
for one in got.get("안") or []:
if one.get("기준") is None:
return None
cut = 100 if (one.get("고정") or {}).get("비율") else 1
for k in labor.COSTS:
unit = Decimal(one["기준"][k])
unit = unit.to_integral_value(how) if "참조" in one else unit
parts[k] += (unit * one["수량"] / cut).quantize(Decimal("0.1"), how)
if by_line:
return sum(parts.values()).to_integral_value(ROUND_FLOOR)
return sum(v.to_integral_value(how) for v in parts.values())
def excel_given(ref: dict[str, Any], depth: int = 1) -> dict[str, Any]:
"""`본뜬.실무수량` → 안 줄 알약 값(723-1 · 하위 사전조합까지) — 엑셀 대조 전용."""
doc = refs.read_ref(ref) if depth <= refs.DEPTH else None
if not isinstance(doc, dict):
return {}
rid, hands = refs.ref_id(ref), (doc.get("본뜬") or {}).get("실무수량") or {}
out = {f"{rid}#{i}": v for i, v in (hands.get("줄") or {}).items()}
out |= {f"{rid}#자재|{code}": v for code, v in (hands.get("자재") or {}).items()}
for one in refs.refs_in(doc):
out |= excel_given(one, depth + 1)
return out
def compare(ref: dict[str, Any], hopyo: dict[str, Any]) -> dict[str, Any]:
"""만든 사전조합 1 단위 값 ↔ 엑셀 호표 단가(참고 · 판정 아님) — 우리 = 엑셀 끝수 규칙(내림 ·
반올림 중 엑셀과 같은 쪽 · `_excel_round`) · 수량 = 엑셀 수량(`excel_given` · 723-1)."""
head = {k: ref[k] for k in ("층", "주인", "키")}
got = refs.Expand(m01.loaded()[1], given=excel_given(head))(head)
base = got.get("기준") or {}
excel = (hopyo.get("금액") or {}).get("계")
cuts = [_excel_round(got, *one) for one in CUTS] if base else []
cuts = [c for c in cuts if c is not None]
cut = next(
(c for c in cuts if abs(c - Decimal(str(excel or 0))) < 1), cuts[0] if cuts else None
)
ours = float(cut if cut is not None else base["계"]) if "계" in base else None
gap = round(ours - excel, 1) if ours is not None and excel is not None else None
same = ours is not None and abs(ours - (excel or 0)) < 1 # 705-3 — 엑셀 금액 없음 = 0
return {"엑셀": excel, "우리": ours, "차이": gap, "같음": same, "까닭": got.get("까닭")}