Files
Aislo/M02_MasterTemplete/M02_Sangeun_Views.py
T
eomsangdonandClaude Opus 5.5 f4be6782a5 feat(751-3): M01 · M02 셈 끝수 = 품셈 1-2-2 버림 — 줄 0.1 원 · 비목 소계 1 원 · 계 = 셋 합 · B09 와 같은 값
- 끝수 한 곳 `master_cut.py`(B09 `rounddown` 재사용) — 엔진 답에 입힘: 줄 비목마다 0.1 원 버림 · 하위 로직 줄 = 하위 끝수 계 × 수량 · 덧줄 = 버린 줄 합으로 다시 셈 · 비목 합 1 원 버림 · 중간 칸도 버린 값
- 쓰는 곳: M01 시험 계산(`check_master.calc`) · 읽는 식(`master_text.lines`) · 옛 조합 미리보기(`master_combo`) · M02 `run_line`(단가산출 · 일위대가 · 펼침) · 별도계상 뺀 기준 · 켜쌓기율 곱 뒤 · 일위대가 반영 · 반영합 · 비율 줄 · 사전조합 안 줄
- 일위대가 반영 TS 짝(`Labor_Calc.ts`) 같은 끝수 · 거울 헬퍼가 상대 경로 .ts 가져옴
- B09 = `run_line(raw=True)` 엔진 날 값(제 단가로 다시 버림 · % 덧줄 율 비 그대로) — 검증_sub3 B09 247 칸 전후 같음
- `master_text` 꼴 셋 = `common_util_money` 로 갈음(줄 금액 `fmt_line_money` · 식 안 금액 = 버린 0.1 원)
- 화면: 상세 줄 금액 · 시험 계산 줄 · 중간 돈 = `formatLineMoney` · 일위대가 반영 칸 0.1 원 · 상세 바닥 · 박스 · 인력재료경비 비목 소계 = 줄 합 1 원 버림
- 테스트1 네 보기 · 서고 목록 = 124,419(옛 124,420 / 124,419.85) · 재료 줄 11,694.6 + 23,425.6 + 1,404.8 = 소계 36,525
- 새 지킴 시험 test_751_3_money_cut
- 옛 날 금액(끝수 없음)을 대조하던 시험 24 파일 고침 — 까닭 = 금액 규칙이 줄 0.1 원 · 소계 1 원 버림으로 바뀜(고정 값 → 새 값 · 줄 합 = 계 → 줄 합 아래 비목마다 1 원 안 · 곱 비 = 끝수 폭 안) · 실무 xlsx 영월 엑셀 같음 22 → 23 · 이어 붙이는 TS 시험(704_3 · 717_2b)에 `rounddown` 같은 식

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 06:16:01 +09:00

84 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""M02 단가산출(SK) 보기 넷 = 셈 답 하나(PLAN 750-1 · 요구 588-1) — 화면 셈 길 답 덧칸.
- `글` = 읽는 식(M01 `/text` 와 같은 꼴 · `master_text.lines` + `master_sheet_line.annotate`) ·
SK 고친 줄(`_Over`) · 같은 입력(자동값 + 입력값) · 같은 고름(`choosing`) 위에서 지음.
줄마다 `cid` = SK 줄 cid(`annotate` 와 같은 차례 — 호표 줄 × `_shares` 비목 · 뒤 덧줄).
금액 · 소계 · 계 = SK `줄` · `기준` 그대로(`finish` — 별도계상 뺌 · 켜쌓기율 · 단위 환산 ÷배 ·
못 셈 줄 까닭) · 식 글(`글` · `이름글`)은 바탕 단위 셈 그대로 + 머리 `나눔`(배 ≠ 1).
- `중간` = 시험 계산 중간값(수 · 글만) — 시험 계산 = {lines: `줄`, sums: `기준`, middle: `중간`}.
계산 자리 = 서버 단독(CLAUDE.md 5장 ③) · 화면은 그리기만.
"""
from __future__ import annotations
from decimal import Decimal
from typing import Any
from M02_MasterTemplete import M02_Labor_Doc as labor
mf = labor.m01.cm.mf
import master_sheet_line as msl # noqa: E402 — scripts 길은 `m01` 이 둠
import master_text as mtx # noqa: E402
_ERRORS = (mf.FormulaError, ArithmeticError, KeyError, TypeError, ValueError)
def text_of(over: Any, key: str, values: dict, picks: Any, ids: list, eng: list) -> dict:
"""`{글, 중간}` — `eng` = `run_line` 줄(별도계상 빼기 전 · 차례 맞춤용) · 못 지음 = 까닭."""
row = over.logic(key)
auto = {k: v for k, v in labor.m01.mau.values(over, row).items() if v is not None}
given = {**auto, **labor.m01._dec(values or {})}
try:
with mf.mp.choosing(picks or None):
text = msl.annotate(over, key, given, mtx.lines(over, key, given))
mid = labor.mcut.engine(over, key, mf.run(over, key, given)).get("중간") or {} # 751-3
except _ERRORS as e:
return {"글": {"ok": False, "reason": str(e) or type(e).__name__}, "중간": {}}
if text.get("ok") and "groups" in text and "결과" not in row:
_tag(row, ids, eng, text)
keep = (Decimal, int, float, str, bool)
return {"글": text, "중간": {k: v for k, v in mid.items() if isinstance(v, keep)}}
def _tag(row: dict, ids: list, eng: list, text: dict) -> None:
"""글 줄마다 `cid` — `annotate` 와 같은 차례(호표 줄 × 몫 비목 → 덧줄)."""
slots = {g["비목"]: iter(g["줄"]) for g in text["groups"]}
items, adds = row.get("호표") or [], row.get("덧줄") or []
for n, line in enumerate(eng):
if n < len(items):
parts = [p for p, _ in mtx._shares(line)] if line.get("비목") else []
else:
parts = [adds[n - len(items)]["비목"]] if n - len(items) < len(adds) else []
for part in parts:
one = next(slots.get(part, iter(())), None)
if one is not None and n < len(ids):
one["cid"] = ids[n]
def finish(ans: dict) -> dict:
"""화면 답(`per_unit` 뒤) — 글 금액 · 소계 · 계 = SK 줄 · 기준 · SK 에 없는 줄(별도계상) 뺌."""
text = ans.get("글") or {}
base = ans.get("기준")
if not text.get("ok") or "groups" not in text or not base:
return ans
sk = {x["cid"]: x for x in ans.get("줄") or [] if x.get("cid")}
groups = []
for g in text["groups"]:
kept = []
for one in g["줄"]:
line = sk.get(one.get("cid"))
if line is None and one.get("cid"):
continue # SK 에서 빠진 줄(별도계상)
if line is not None:
parts = line.get("비목") or {}
money = parts.get(g["비목"]) if len(parts) > 1 else line.get("금액")
one = {**one, "금액": money}
if line.get("까닭"):
one["까닭"] = line["까닭"]
kept.append(one)
if kept:
groups.append({**g, "줄": kept, "소계": base.get(g["비목"])})
times = ans.get("화면배")
head = {"나눔": times} if times not in (None, 1) else {}
return {**ans, "글": {**text, "groups": groups, "계": base.get("계"), **head}}