- 새 `M02_Sangeun_Views` — SK 고친 줄(`_Over`) · 같은 입력 · 같은 고름 위에서 `master_text.lines` + `annotate` = `글` · 줄마다 cid · 금액 · 소계 · 계 = SK 줄 · 기준(별도계상 뺌 · 단위 환산 ÷배 · 못 셈 까닭) · `중간` = 시험 계산 중간값 - `calc_doc` — 문서 `줄모드` true = 일위대가 그 줄 셈(`line` · 별도계상 기본) · 몸 `보기` false = 덧칸 안 지음(바탕 원값 셈) - `master_text.lines` · `master_sheet_line.annotate` — `files` 자리에 Master 도 받음(파일 묶음 길 그대로 · M01 `/text` 답 같음) - `lineDoc` — `줄모드: true`(일위대가 줄 모달 89,299.60 = 그 줄 금액) - 시험 `test_717_3` — lineDoc = as_doc 대조에서 `줄모드` 칸 따로 확인(서버 as_doc 은 `line` 인자로 줄 셈 · 문서 칸 없음) - 새 지킴 `test_750_1_sk_views` — 변형 일곱 · 참조 바탕 · 줄 모달 · 보기 false Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
84 lines
4.0 KiB
Python
84 lines
4.0 KiB
Python
"""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 = mf.run(over, key, given).get("중간") or {}
|
||
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}}
|