- 부모 저장 때 확인 안 된 하위 호표(깊이 끝까지)를 하위 먼저 그 체크대로 함께 만듦(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>
67 lines
3.6 KiB
Python
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("까닭")}
|